-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #54 from Jigsaw-Code/outline-connectivity-app
connectivity test app (without android)
- Loading branch information
Showing
72 changed files
with
8,127 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
output | ||
|
||
# vscode | ||
.vscode | ||
|
||
# node | ||
node_modules | ||
|
||
# yarn | ||
.yarn/cache | ||
.yarn/sdks | ||
.yarn/unplugged | ||
.yarn/install-state.gz | ||
.pnp.* | ||
|
||
# apple | ||
.DS_Store |
9 changes: 9 additions & 0 deletions
9
x/examples/outline-connectivity-app/.yarn/plugins/@yarnpkg/plugin-typescript.cjs
Large diffs are not rendered by default.
Oops, something went wrong.
28 changes: 28 additions & 0 deletions
28
x/examples/outline-connectivity-app/.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
Large diffs are not rendered by default.
Oops, something went wrong.
874 changes: 874 additions & 0 deletions
874
x/examples/outline-connectivity-app/.yarn/releases/yarn-3.6.1.cjs
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
# 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. The following diagram illustrates how the shared code is built and used across platforms: | ||
|
||
```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.Request()"] | ||
end | ||
subgraph app_mobile | ||
subgraph ios | ||
I["MobileBackendPlugin.swift"] | ||
end | ||
subgraph android | ||
J["MobileBackendPlugin.kt"] | ||
end | ||
K["index.html"] | ||
L["MobileBackend.Request()"] | ||
end | ||
A -.-> |gomobile| C | ||
A -.-> |gomobile| D | ||
A --> G | ||
B --> H | ||
B --> K | ||
C --> I | ||
D --> J | ||
I --> L | ||
J --> L | ||
L --> K | ||
G --> H | ||
style K fill:blue; | ||
style K color:white; | ||
style H fill:blue; | ||
style H color:white; | ||
``` | ||
|
||
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 that enables the frontend to make requests to the backend via the given platform. | ||
|
||
```ts | ||
interface Backend { | ||
Request<T, K>(resourceName: string, parameters: T): Promise<K> | ||
} | ||
``` | ||
|
||
In a `Request` call, the frontend passes a `resourceName` and `parameters` to the backend, and the backend returns a promise either containing the result or which throws an error. The `resource` is the name of a function in the `shared_backend` package, and the `parameters` are are passed to that function. | ||
|
||
With this middleware implemented, we can now use the shared code in the frontend. For example, in the mobile app, we can use the shared code like so: | ||
|
||
```ts | ||
@customElement("app-main") | ||
export class AppMain extends LitElement { | ||
render() { | ||
return html`<connectivity-test-page | ||
.onSubmit=${ | ||
(parameters: SharedFrontend.ConnectivityTestRequest) => | ||
MobileBackend.Request<SharedFrontend.ConnectivityTestRequest, SharedFrontend.ConnectivityTestResponse>("ConnectivityTest", parameters) | ||
} />`; | ||
} | ||
} | ||
``` | ||
|
||
## 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. `yarn` | ||
|
||
If at any point you run into issues during development, try `yarn reset`. | ||
|
||
### Development Server | ||
|
||
`yarn watch` | ||
|
||
### Build | ||
|
||
> TODO: how to generate credentials | ||
`yarn build` | ||
|
||
### Needed Improvements | ||
|
||
1. **\[P1\]** android (in progress) | ||
1. **\[P1\]** read browser language on load, centralize language list, and only localize once | ||
1. **\[P1\]** documentation on how to generate mobile app build credentials | ||
1. **\[P1\]** add individual test result errors to the test result output UI | ||
1. **\[P2\]** use x/config to parse the access key and showcase the different transports (see: https://github.com/Jigsaw-Code/outline-sdk/blob/main/x/examples/outline-connectivity/main.go) | ||
1. **\[P2\]** generalize request handler via generics/reflection | ||
1. **\[P2\]** Create a logo for the app | ||
1. **\[P2\]** Make backend request calls non-blocking | ||
1. **\[P2\]** Introducing some kind of tracing into the test | ||
|
||
### 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. <span style="color:gray">**\[P3\]** spurious lit localize TS error</span> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
// 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 | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"errors" | ||
|
||
"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) Request(resourceName string, parameters string) (shared_backend.Response, error) { | ||
var response shared_backend.Response | ||
|
||
request := shared_backend.Request{ResourceName: resourceName, Parameters: parameters} | ||
|
||
rawRequest, requestSerializeError := json.Marshal(request) | ||
|
||
if requestSerializeError != nil { | ||
return response, errors.New("DesktopBackend.Request: failed to serialize request") | ||
} | ||
|
||
// TODO: make this non-blocking with goroutines/channels | ||
responseParseError := json.Unmarshal(shared_backend.HandleRequest(rawRequest), &response) | ||
|
||
if responseParseError != nil { | ||
return response, errors.New("DesktopBackend.Request: failed to parse response") | ||
} | ||
|
||
return response, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// 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 DesktopBackend from "./generated/wailsjs/go/main/App"; | ||
|
||
async function requestBackend<T, K>(resourceName: string, parameters: T): Promise<K> { | ||
const response = await DesktopBackend.Request(resourceName, JSON.stringify(parameters)); | ||
|
||
if (response.error) { | ||
throw new Error(response.error); | ||
} | ||
|
||
return JSON.parse(response.body); | ||
} | ||
|
||
// frontend | ||
import * as SharedFrontend from "shared_frontend"; | ||
import type { ConnectivityTestRequest, ConnectivityTestResponse } 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 { | ||
render() { | ||
return html`<connectivity-test-page .onSubmit=${ | ||
(parameters: ConnectivityTestRequest) => | ||
requestBackend<ConnectivityTestRequest, ConnectivityTestResponse>( | ||
"ConnectivityTest", parameters | ||
) | ||
} />`; | ||
} | ||
} |
5 changes: 5 additions & 0 deletions
5
x/examples/outline-connectivity-app/app_desktop/generated/wailsjs/go/main/App.d.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
import {shared_backend} from '../models'; | ||
|
||
export function Request(arg1:string,arg2:string):Promise<shared_backend.Response>; |
7 changes: 7 additions & 0 deletions
7
x/examples/outline-connectivity-app/app_desktop/generated/wailsjs/go/main/App.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
|
||
export function Request(arg1, arg2) { | ||
return window['go']['main']['App']['Request'](arg1, arg2); | ||
} |
19 changes: 19 additions & 0 deletions
19
x/examples/outline-connectivity-app/app_desktop/generated/wailsjs/go/models.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
export namespace shared_backend { | ||
|
||
export class Response { | ||
body: string; | ||
error: string; | ||
|
||
static createFrom(source: any = {}) { | ||
return new Response(source); | ||
} | ||
|
||
constructor(source: any = {}) { | ||
if ('string' === typeof source) source = JSON.parse(source); | ||
this.body = source["body"]; | ||
this.error = source["error"]; | ||
} | ||
} | ||
|
||
} | ||
|
24 changes: 24 additions & 0 deletions
24
x/examples/outline-connectivity-app/app_desktop/generated/wailsjs/runtime/package.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 <[email protected]>", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/wailsapp/wails/issues" | ||
}, | ||
"homepage": "https://github.com/wailsapp/wails#readme" | ||
} |
Oops, something went wrong.