| .vscode | ||
| src | ||
| src-tauri | ||
| .gitignore | ||
| COPYING | ||
| deno.lock | ||
| FUNDING.yml | ||
| index.html | ||
| Makefile | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
| vite.config.ts | ||
Next step
Use Fort Porwarding for something real. Maybe SSH between Amber and the media PC.
How to
How to use the Makefile shortcuts
make apk- Build an APK for aarch64 Android targetsmake desktop- Build a desktop release binary for the current platform
How to build
How to install build pre-requisites
sudo apt-get update
sudo apt-get install libwebkit2gtk-4.1-dev \
build-essential \
curl \
wget \
file \
libxdo-dev \
libssl-dev \
libayatana-appindicator3-dev \
librsvg2-dev
# Install deno
curl -fsSL https://deno.land/install.sh | sh
# Install deps (equiv to npm install or pnpm install)
deno install
# Set this env var to keep Deno from phoning home when it doesn't need to
export DENO_NO_UPDATE_CHECK=1
How to build for Android
Download the Android Studio Meerkat Feature Drop (brought to you by Brawndo, the Thirst Mutilator, featuring Dante from Devil May Cry, and Knuckles) https://developer.android.com/studio
Unpack and run bin/studio
export ANDROID_HOME=/home/user/Android/Sdk
export NDK_HOME=/home/user/Android/Sdk/ndk/29.0.13599879
# Sometimes Cargo will do this for you but sometimes it won't lol
rustup target add aarch64-linux-android armv7-linux-androideabi
sudo apt-get install openjdk-17-jre
# Set up signing per https://v2.tauri.app/distribute/sign/android/
# Now petition the demiurge, make a save point, and mash BUILD
# Takes about 2.5 minutes
make apk
How to run
How to run for desktop
nice deno task tauri dev -- -- --secret-key-path private/iroh-secret-key.bin
How to test Fort Porwarding
You'll need to run the server and client once each to let them save their secret keys to disk, and to figure out their public keys.
Put the secret keys under private/, since it's ignored by Git. Secrets don't
go in Git!
# In Terminal 1, start the server with a well-known key, pointed at example.com's plaintext HTTP, allowing our client to connect
cargo run -p fort_porwarding -- server \
--secret-key-path private/key-server.bin \
--upstream-addr '[2600:1408:ec00:36::1736:7f31]:80' \
--allowed-client-id "$CLIENT_ID"
# In Terminal 2, start the client, which will try to connect to either of my well-known server IDs
cargo run -p fort_porwarding -- client \
--secret-key-path private/key-client.bin \
--server-id "$SERVER_ID"
# In Terminal 3, GET example.com (with SNI), forwarded over Fort Porwarding
curl -v -H Host:example.com http://127.0.0.1:58008/
Absolutely every idea
- Networked music player
- Chat
- Journal
- Mood tracker
- SSH / VNC
- File sharing (e.g. movies from computer, camera roll from phone)
- Tunneling
Random notes
"App not installed as package appears to be invalid"
I fixed this on Android but after renaming the project and blowing up gen/android it broke again
I had to add the signingConfigs section to gen/android/app/build.gradle.kts.
But after I do that, it can't find key.properties for some reason... was that in Git?
10 MB to 29 MB
It's actually due to Iroh, not due to the UnifiedPush plugin.
QUIC is just fucking huge.
Event storming
- UnifiedPush message
- Service lifecycle (onStart, onDestroy)
- UI events (User sends message)
- Inbound network data (incoming peer connection, incoming peer data)
- Activity lifecycle (onStart, onStop)
- Network state change (gained network)
1 - UnifiedPush messages come directly to the Kotlin service. We ensure the Rust main task is running, do some minimal decoding if needed, then do a try_send() into a 1-slot mpsc channel on the Rust side. Rust eventually wakes up, pulls the data from that channel, and processes the UP message.
2 - Service lifecycle messages come to the Service. onStart() triggers us to ensure the Rust main task is running. onDestroy() is forwarded to the Rust main task and it might be synchronous, it might call block_on() internally waiting on the Rust main task to stop.
3 - UI events come to the JS in the Tauri Activity. From there we can call into the Tauri Rust code in the Activity, and that can hop to the Rust main task, since everything is mostly in one process. This keeps us out of Kotlin as much as possible, so the code is reusable for desktop.
4 - Inbound network data comes to Iroh in the Rust main task. No problem there since we aren't thinking about outbound events yet.
5 - Activity lifecycle events probably create corresponding events in Tauri? We can forward those the same way as we forward UI events, since they're received in Rust code in the Activity.
6 - Network state change will come through Kotlin. If it's in the same process, we can treat it like UnifiedPush, we'll ensure the Rust library is loaded, ensure the main task is running, then do a notify() type call.
Issues:
- (Yes, for now anyway) Does
block_on()foronDestroy()make sense? - (LazyLock) How can I set up a per-process singleton so that I can always get a handle on the Rust main task from the Kotlin Service, from the Rust code in the Tauri Activity, etc? I'm willing to use a global just this once, but I'll keep that as a wrapper so that for testing and desktop I can still have multiple instances.
How about outbound events?
- Main task to UI - Works
- Main task to Kotlin - Works