Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

connectivity test app (without android) #54

Merged
merged 23 commits into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
f710178
add initial test app
daniellacosse Aug 23, 2023
a8dcdc4
Merge branch 'main' into outline-connectivity-app
daniellacosse Aug 30, 2023
83f9359
Update x/outline-connectivity-app/go.mod
daniellacosse Aug 30, 2023
55285bf
move folder, run go mod tidy
daniellacosse Aug 30, 2023
5886b41
Update x/examples/outline-connectivity-app/shared_frontend/index.ts
daniellacosse Aug 31, 2023
7872ea7
Update x/examples/outline-connectivity-app/package.json
daniellacosse Aug 31, 2023
fe0c58b
adds licenses and updates go.mod path
daniellacosse Sep 6, 2023
42b861e
address all feedback but the refactoring ones
daniellacosse Sep 6, 2023
be74d8c
remove pnp files
daniellacosse Sep 6, 2023
f1f4630
revert generated/wailsjs - wails generate module dosen't workj
daniellacosse Sep 6, 2023
d72e369
Update x/examples/outline-connectivity-app/shared_frontend/pages/conn…
daniellacosse Sep 7, 2023
c896bf1
wip
daniellacosse Sep 7, 2023
27f5f9b
renaming to request
daniellacosse Sep 11, 2023
ff679bd
Merge branch 'outline-connectivity-app' of https://github.com/Jigsaw-…
daniellacosse Sep 11, 2023
198433f
fix types and update docs
daniellacosse Sep 11, 2023
c1227bf
add todo
daniellacosse Sep 11, 2023
6984d5e
move ConnectivityTest check inside if statement
daniellacosse Sep 12, 2023
cd51fbb
update todos in README
daniellacosse Sep 12, 2023
7de8aec
fix diagram and add TODO for generic parser
daniellacosse Sep 13, 2023
4d43597
okay THAT should work
daniellacosse Sep 13, 2023
630c1b3
fix ipv6 resolver, and language switcher
daniellacosse Sep 13, 2023
cccf239
fix translation switcher
daniellacosse Sep 13, 2023
6623399
add TODO for test result output
daniellacosse Sep 13, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions x/examples/outline-connectivity-app/.gitignore
daniellacosse marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
output
node_modules
.yarn/cache
.yarn/sdks
.yarn/unplugged
.yarn/install-state.gz
.pnp.*
.DS_Store
.vscode/settings.json
5 changes: 5 additions & 0 deletions x/examples/outline-connectivity-app/.vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"recommendations": [
"arcanis.vscode-zipfs"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"typescript.tsdk": "x/examples/outline-connectivity-app/.yarn/sdks/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true,
"search.exclude": {
"**/.yarn": true,
"**/.pnp.*": true
}
}
daniellacosse marked this conversation as resolved.
Show resolved Hide resolved

Large diffs are not rendered by default.

Large diffs are not rendered by default.

874 changes: 874 additions & 0 deletions x/examples/outline-connectivity-app/.yarn/releases/yarn-3.6.1.cjs

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions x/examples/outline-connectivity-app/.yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
plugins:
- path: .yarn/plugins/@yarnpkg/plugin-typescript.cjs
spec: "@yarnpkg/plugin-typescript"
- path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
spec: "@yarnpkg/plugin-workspace-tools"

yarnPath: .yarn/releases/yarn-3.6.1.cjs
128 changes: 128 additions & 0 deletions x/examples/outline-connectivity-app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# Outline Connectivity App

## Overview

This is a simple cross-platform app to test connectivity to Outline servers, using the Outline SDK. It is built with [Wails](https://wails.app/) and [Capacitor](https://capacitorjs.com/).

### Architecture

The overarching goal of this application is to demonstrate how the Outline SDK enables you to write each line of business logic only once across all platforms.

We achieve this by first writing a [`shared_backend`](./shared_backend) package in Go - which contains the UDP/TCP connectivity test implemented with the Outline SDK - and a [`shared_frontend`](./shared_frontend/) GUI built with TypeScript and Lit which contains an HTML form for entering the required connectivity test parameters.

Each platform used - [Wails](https://wails.app/) for desktop and [Capacitor](https://capacitorjs.com/) for mobile - then has a thin wrapper around the shared code that handles the platform-specific details.

```mermaid
graph LR
subgraph Shared
A["shared_backend"]
B["shared_frontend"]
end
subgraph Build
C["SharedBackend.xcframework"]
D["SharedBackend.aar"]
end
subgraph app_desktop
H["index.html"]
G["DesktopBackend.Invoke()"]
end
subgraph app_mobile
subgraph ios
I["MobileBackendPlugin.swift"]
end
subgraph android
J["MobileBackendPlugin.kt"]
end
K["index.html"]
L["MobileBackend.Invoke()"]
end

A -.-> |gomobile| C
A -.-> |gomobile| D
A --> G
B --> H
B --> K
C --> I
D --> J
I --> L
J --> L
L --> K
daniellacosse marked this conversation as resolved.
Show resolved Hide resolved
G --> H
daniellacosse marked this conversation as resolved.
Show resolved Hide resolved

style K fill:blue;
daniellacosse marked this conversation as resolved.
Show resolved Hide resolved
style H fill:blue;
```

For Mobile, we use `gomobile` to build the `shared_backend` package into a `xcframework` for iOS and an `aar` for Android. You can see this for yourself by running `yarn shared_backend build`. For Desktop, Wails simply refers to the `shared_backend` package directly.

Then we implement a small piece of middleware called `Invokable` that enables the frontend to speak to the backend via the given platform.

```ts
interface Invokable {
Invoke(parameters: { method: string; input: string; }): Promise<{ result: string; errors: string[] }>
}
```

In an `Invoke` call, the frontend passes a `method` and `input` to the backend, and the backend returns a `result` and `errors`. The `method` is the name of a function in the `shared_backend` package, and the `input` is a JSON string that is passed to that function. The `result` is a JSON string returned by the function, and the `errors` are any errors that occurred during the function call.

With this simple Invokable binding to whatever native backend the frontend is running on, we can then build the frontend convenience bindings with typing and examples, like so:

```ts
@customElement("app-main")
export class AppMain extends LitElement {
backend = SharedBackend.from(MobileBackend)

render() {
// this.backend.connectivityTest's input is a ConnectivityTestParameters interface, output is a ConnectivityTestResult[]
return html`<connectivity-test-page .onSubmit=${this.backend.connectivityTest} />`;
}
}
```


## Development

### Prerequisites

- [Node.js](https://nodejs.org/)
- [Yarn](https://yarnpkg.com/)
- [Go](https://golang.org/)
- [Wails](https://wails.app/)
- [Capacitor](https://capacitorjs.com/)
- [CocoaPods](https://cocoapods.org/)
- [Xcode](https://developer.apple.com/xcode/)
- [Android SDK](https://developer.android.com/studio)
- [Android NDK](https://developer.android.com/ndk)

### Setup

1. Clone this repo
1. `cd` into the repo
1. if using xcode, copy the `settings.example.json` to `settings.json` if it looks good to you
1. `yarn`

If at any point you run into issues during development, try `yarn reset`.

### Development Server

`yarn watch`

### Build

> NOTE: You will need credentials to build for iOS and Android. Talk to @jigsaw.
daniellacosse marked this conversation as resolved.
Show resolved Hide resolved

`yarn build`

### Needed Improvements

1. **\[P1\]** android (in progress)
1. **\[P1\]** read browser language on load (and only localize once)

### Current Issues

1. <span style="color:red">**\[P0\]** add server url to an ENV var somehow... pretty dumb capacitor...</span>
1. **\[P1\]** Results dialog isn't rendering as intended (likely because of the `{ all: initial }`)
1. **\[P2\]** `cap ___ run` breaks (have workaround and [issue filed](https://github.com/ionic-team/capacitor/issues/6791))
1. **\[P2\]** Create a logo for the app
1. **\[P2\]** Introducing some kind of tracing into the test
1. <span style="color:gray">**\[P3\]** spurious lit localize TS error</span>
55 changes: 55 additions & 0 deletions x/examples/outline-connectivity-app/app_desktop/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright 2023 Jigsaw Operations LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main
daniellacosse marked this conversation as resolved.
Show resolved Hide resolved

import (
"context"
"encoding/json"
"github.com/Jigsaw-Code/outline-sdk/x/examples/outline-connectivity-app/shared_backend"
)

// App struct
type App struct {
ctx context.Context
}

// NewApp creates a new App application struct
func NewApp() *App {
return &App{}
}

// startup is called when the app starts. The context is saved
// so we can call the runtime methods
func (a *App) startup(ctx context.Context) {
a.ctx = ctx
}

func (a *App) Invoke(input shared_backend.CallInputMessage) shared_backend.CallOutputMessage {
rawInputMessage, marshallingError := json.Marshal(input)

if marshallingError != nil {
return shared_backend.CallOutputMessage{Result: "", Errors: []string{"Invoke: failed to serialize raw invocation input"}}
}

var outputMessage shared_backend.CallOutputMessage

unmarshallingError := json.Unmarshal(shared_backend.SendRawCall(rawInputMessage), &outputMessage)

if unmarshallingError != nil {
return shared_backend.CallOutputMessage{Result: "", Errors: []string{"Invoke: failed to parse invocation result"}}
}

return outputMessage
}
34 changes: 34 additions & 0 deletions x/examples/outline-connectivity-app/app_desktop/app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2023 Jigsaw Operations LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// backend
import * as SharedBackend from "shared_backend";
import * as DesktopBackend from "./generated/wailsjs/go/main/App";

// frontend
import * as SharedFrontend from "shared_frontend";
import { LitElement, html } from "lit";
import { customElement } from "lit/decorators.js";

SharedFrontend.registerAllElements();

// main
@customElement("app-main")
export class AppMain extends LitElement {
backend = SharedBackend.from(DesktopBackend);

render() {
return html`<connectivity-test-page .onSubmit=${this.backend.connectivityTest} />`;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
daniellacosse marked this conversation as resolved.
Show resolved Hide resolved
import {shared_backend} from '../models';

export function Invoke(arg1:shared_backend.CallInputMessage):Promise<shared_backend.CallOutputMessage>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// @ts-check
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
daniellacosse marked this conversation as resolved.
Show resolved Hide resolved

export function Invoke(arg1) {
return window['go']['main']['App']['Invoke'](arg1);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
export namespace shared_backend {

export class CallInputMessage {
method: string;
input: string;

static createFrom(source: any = {}) {
return new CallInputMessage(source);
}

constructor(source: any = {}) {
if ('string' === typeof source) source = JSON.parse(source);
this.method = source["method"];
this.input = source["input"];
}
}
export class CallOutputMessage {
result: string;
errors: string[];

static createFrom(source: any = {}) {
return new CallOutputMessage(source);
}

constructor(source: any = {}) {
if ('string' === typeof source) source = JSON.parse(source);
this.result = source["result"];
this.errors = source["errors"];
}
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "@wailsapp/runtime",
"version": "2.0.0",
"description": "Wails Javascript runtime library",
"main": "runtime.js",
"types": "runtime.d.ts",
"scripts": {
},
"repository": {
"type": "git",
"url": "git+https://github.com/wailsapp/wails.git"
},
"keywords": [
"Wails",
"Javascript",
"Go"
],
"author": "Lea Anthony <lea.anthony@gmail.com>",
"license": "MIT",
"bugs": {
"url": "https://github.com/wailsapp/wails/issues"
},
"homepage": "https://github.com/wailsapp/wails#readme"
}
Loading