Compare commits
9 commits
coderedart
...
master
Author | SHA1 | Date | |
---|---|---|---|
gallant | 8483d6ee01 | ||
gallant | 5f7e3081e0 | ||
gallant | 7da5e13b91 | ||
692d9865cd | |||
3fb74d7d2b | |||
f50f3e60b2 | |||
88e0b19c50 | |||
08b025b4e4 | |||
d12c19da37 |
45
.github/workflows/pages.yml
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
name: Github Pages
|
||||
|
||||
# By default, runs if you push to master. keeps your deployed app in sync with master branch.
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
# to only run when you do a new github release, comment out above part and uncomment the below trigger.
|
||||
# on:
|
||||
# release:
|
||||
# types:
|
||||
# - published
|
||||
|
||||
permissions:
|
||||
contents: write # for committing to gh-pages branch.
|
||||
|
||||
jobs:
|
||||
build-github-pages:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2 # repo checkout
|
||||
- uses: actions-rs/toolchain@v1 # get rust toolchain for wasm
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: stable
|
||||
target: wasm32-unknown-unknown
|
||||
override: true
|
||||
- name: Rust Cache # cache the rust build artefacts
|
||||
uses: Swatinem/rust-cache@v1
|
||||
- name: Download and install Trunk binary
|
||||
run: wget -qO- https://github.com/thedodd/trunk/releases/latest/download/trunk-x86_64-unknown-linux-gnu.tar.gz | tar -xzf-
|
||||
- name: Build # build
|
||||
# "${GITHUB_REPOSITORY#*/}" evaluates into the name of the repository
|
||||
# using --public-url something will allow trunk to modify all the href paths like from favicon.ico to repo_name/favicon.ico .
|
||||
# this is necessary for github pages where the site is deployed to username.github.io/repo_name and all files must be requested
|
||||
# relatively as eframe_template/favicon.ico. if we skip public-url option, the href paths will instead request username.github.io/favicon.ico which
|
||||
# will obviously return error 404 not found.
|
||||
run: ./trunk build --release --public-url "${GITHUB_REPOSITORY#*/}"
|
||||
- name: Deploy
|
||||
uses: JamesIves/github-pages-deploy-action@v4
|
||||
with:
|
||||
folder: dist
|
||||
# this option will not maintain any history of your previous pages deployment
|
||||
# set to false if you want all page build to be committed to your gh-pages branch history
|
||||
single-commit: true
|
18
.github/workflows/rust.yml
vendored
|
@ -33,8 +33,8 @@ jobs:
|
|||
with:
|
||||
profile: minimal
|
||||
toolchain: stable
|
||||
target: wasm32-unknown-unknown
|
||||
override: true
|
||||
- run: rustup target add wasm32-unknown-unknown
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: check
|
||||
|
@ -66,7 +66,7 @@ jobs:
|
|||
profile: minimal
|
||||
toolchain: stable
|
||||
override: true
|
||||
- run: rustup component add rustfmt
|
||||
components: rustfmt
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
|
@ -82,14 +82,14 @@ jobs:
|
|||
profile: minimal
|
||||
toolchain: stable
|
||||
override: true
|
||||
- run: rustup component add clippy
|
||||
components: clippy
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: clippy
|
||||
args: -- -D warnings
|
||||
|
||||
wasm_bindgen:
|
||||
name: wasm-bindgen
|
||||
trunk:
|
||||
name: trunk
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
@ -97,7 +97,9 @@ jobs:
|
|||
with:
|
||||
profile: minimal
|
||||
toolchain: 1.61.0
|
||||
target: wasm32-unknown-unknown
|
||||
override: true
|
||||
- run: rustup target add wasm32-unknown-unknown
|
||||
- run: ./setup_web.sh
|
||||
- run: ./wasm_bindgen_check.sh
|
||||
- name: Download and install Trunk binary
|
||||
run: wget -qO- https://github.com/thedodd/trunk/releases/latest/download/trunk-x86_64-unknown-linux-gnu.tar.gz | tar -xzf-
|
||||
- name: Build
|
||||
run: ./trunk build
|
||||
|
|
1
.gitignore
vendored
|
@ -1 +1,2 @@
|
|||
/target
|
||||
/dist
|
||||
|
|
690
Cargo.lock
generated
20
Cargo.toml
|
@ -1,24 +1,16 @@
|
|||
[package]
|
||||
name = "eframe_template"
|
||||
default-run = "eframe_template_bin"
|
||||
name = "sshuttle_gui"
|
||||
version = "0.1.0"
|
||||
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
|
||||
authors = ["Gallant"]
|
||||
edition = "2021"
|
||||
rust-version = "1.60"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[[bin]]
|
||||
name = "eframe_template_bin"
|
||||
path = "src/main.rs"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
|
||||
[dependencies]
|
||||
egui = "0.18.0"
|
||||
eframe = { version = "0.18.0", features = ["persistence"] }
|
||||
egui = "0.19.0"
|
||||
eframe = { version = "0.19.0", features = ["persistence"] }
|
||||
serde = { version = "1", features = ["derive"] } # You only need this if you want app persistence
|
||||
|
||||
# native:
|
||||
|
@ -42,5 +34,5 @@ opt-level = 2 # fast and small wasm
|
|||
# eframe = { git = "https://github.com/emilk/egui", branch = "master" }
|
||||
|
||||
# If you fork https://github.com/emilk/egui you can test with:
|
||||
# egui = { path = "../egui/egui" }
|
||||
# eframe = { path = "../egui/eframe" }
|
||||
# egui = { path = "../egui/crates/egui" }
|
||||
# eframe = { path = "../egui/crates/eframe" }
|
||||
|
|
64
README.md
|
@ -3,7 +3,7 @@
|
|||
[![dependency status](https://deps.rs/repo/github/emilk/eframe_template/status.svg)](https://deps.rs/repo/github/emilk/eframe_template)
|
||||
[![Build Status](https://github.com/emilk/eframe_template/workflows/CI/badge.svg)](https://github.com/emilk/eframe_template/actions?workflow=CI)
|
||||
|
||||
This is a template repo for [eframe](https://github.com/emilk/egui/tree/master/eframe), a framework for writing apps using [egui](https://github.com/emilk/egui/).
|
||||
This is a template repo for [eframe](https://github.com/emilk/egui/tree/master/crates/eframe), a framework for writing apps using [egui](https://github.com/emilk/egui/).
|
||||
|
||||
The goal is for this to be the simplest way to get started writing a GUI app in Rust.
|
||||
|
||||
|
@ -15,20 +15,15 @@ Start by clicking "Use this template" at https://github.com/emilk/eframe_templat
|
|||
|
||||
Change the name of the crate: Chose a good name for your project, and change the name to it in:
|
||||
* `Cargo.toml`
|
||||
* Change the `package.name` from `eframe_template` to `your_crate`
|
||||
* Change the `package.name` from `eframe_template` to `your_crate`.
|
||||
* Change the `package.authors`
|
||||
* Change the `package.default-run` from `eframe_template_bin` to `your_crate_bin` (note the `_bin`!)
|
||||
* Change the `bin.name` from `eframe_template_bin` to `your_crate_bin` (note the `_bin`!)
|
||||
* `main.rs`
|
||||
* Change `eframe_template::TemplateApp` to `your_crate::TemplateApp`
|
||||
* `docs/index.html`
|
||||
* Change the `<title>`
|
||||
* Change the `<script src=…` line from `eframe_template.js` to `your_crate.js`
|
||||
* Change the `wasm_bindgen(…` line from `eframe_template_bg.wasm` to `your_crate_bg.wasm` (note the `_bg`!)
|
||||
* `docs/sw.js`
|
||||
* Change the `'./eframe_template.js'` to `./your_crate.js` (in `filesToCache` array)
|
||||
* Change the `'./eframe_template_bg.wasm'` to `./your_crate_bg.wasm` (in `filesToCache` array)
|
||||
* Remove the web build of the old name: `rm docs/eframe_template*`
|
||||
* `index.html`
|
||||
* Chage the `<title>eframe template</title>` to `<title>your_crate</title>`. optional.
|
||||
* `assets/sw.js`
|
||||
* Change the `'./eframe_template.js'` to `./your_crate.js` (in `filesToCache` array)
|
||||
* Change the `'./eframe_template_bg.wasm'` to `./your_crate_bg.wasm` (in `filesToCache` array)
|
||||
|
||||
### Learning about egui
|
||||
|
||||
|
@ -48,42 +43,33 @@ On Linux you need to first run:
|
|||
|
||||
On Fedora Rawhide you need to run:
|
||||
|
||||
`dnf install clang clang-devel clang-tools-extra speech-dispatcher-devel libxkbcommon-devel pkg-config openssl-devel libxcb-devel`
|
||||
`dnf install clang clang-devel clang-tools-extra speech-dispatcher-devel libxkbcommon-devel pkg-config openssl-devel libxcb-devel fontconfig-devel`
|
||||
|
||||
For running the `build_web.sh` script you also need to install `jq` and `binaryen` with your packet manager of choice.
|
||||
### Web Locally
|
||||
|
||||
### Compiling for the web
|
||||
You can compile your app to [WASM](https://en.wikipedia.org/wiki/WebAssembly) and publish it as a web page.
|
||||
|
||||
Install [jq](https://stedolan.github.io/jq/download/).
|
||||
We use [Trunk](https://trunkrs.dev/) to build for web target.
|
||||
1. Install Trunk with `cargo install --locked trunk`.
|
||||
2. Run `trunk serve` to build and serve on `http://127.0.0.1:8080`. Trunk will rebuild automatically if you edit the project.
|
||||
3. Open `http://127.0.0.1:8080/index.html#dev` in a browser. See the warning below.
|
||||
|
||||
Make sure you are using the latest version of stable rust by running `rustup update`.
|
||||
> `assets/sw.js` script will try to cache our app, and loads the cached version when it cannot connect to server allowing your app to work offline (like PWA).
|
||||
> appending `#dev` to `index.html` will skip this caching, allowing us to load the latest builds during development.
|
||||
|
||||
You can compile your app to [WASM](https://en.wikipedia.org/wiki/WebAssembly) and publish it as a web page. For this you need to set up some tools. There are a few simple scripts that help you with this:
|
||||
|
||||
```sh
|
||||
./setup_web.sh
|
||||
./start_server.sh
|
||||
./build_web.sh --optimize --open
|
||||
```
|
||||
|
||||
* `setup_web.sh` installs the tools required to build for web
|
||||
* `start_server.sh` starts a local HTTP server so you can test before you publish
|
||||
* `build_web.sh` compiles your code to WASM and puts it in the `docs/` folder (see below) and `--open` opens the result in your default browser.
|
||||
|
||||
The finished web app is found in the `docs/` folder (this is so that you can easily share it with [GitHub Pages](https://docs.github.com/en/free-pro-team@latest/github/working-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site)). It consists of three files:
|
||||
|
||||
* `index.html`: A few lines of HTML, CSS and JS that loads your app. **You need to edit this** (once) to replace `eframe_template` with the name of your crate!
|
||||
* `your_crate_bg.wasm`: What the Rust code compiles to.
|
||||
* `your_crate.js`: Auto-generated binding between Rust and JS.
|
||||
### Web Deploy
|
||||
1. Just run `trunk build --release`.
|
||||
2. It will generate a `dist` directory as a "static html" website
|
||||
3. Upload the `dist` directory to any of the numerous free hosting websites including [GitHub Pages](https://docs.github.com/en/free-pro-team@latest/github/working-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site).
|
||||
4. we already provide a workflow that auto-deploys our app to GitHub pages if you enable it.
|
||||
> To enable Github Pages, you need to go to Repository -> Settings -> Pages -> Source -> set to `gh-pages` branch and `/` (root).
|
||||
>
|
||||
> If `gh-pages` is not available in `Source`, just create and push a branch called `gh-pages` and it should be available.
|
||||
|
||||
You can test the template app at <https://emilk.github.io/eframe_template/>.
|
||||
|
||||
### Web testing/development
|
||||
|
||||
Open `index.html#dev` to disable caching, which makes development easier.
|
||||
|
||||
## Updating egui
|
||||
|
||||
As of 2022, egui is in active development with frequent releases with breaking changes. [eframe_template](https://github.com/emilk/eframe_template/) will be updated in lock-step to always use the latest version of egui.
|
||||
|
||||
When updating `egui` and `eframe` it is recommended you do so one version at the time, and read about the changes in [the egui changelog](https://github.com/emilk/egui/blob/master/CHANGELOG.md) and [eframe changelog](https://github.com/emilk/egui/blob/master/eframe/CHANGELOG.md).
|
||||
When updating `egui` and `eframe` it is recommended you do so one version at the time, and read about the changes in [the egui changelog](https://github.com/emilk/egui/blob/master/CHANGELOG.md) and [eframe changelog](https://github.com/emilk/egui/blob/master/crates/eframe/CHANGELOG.md).
|
||||
|
|
2
Trunk.toml
Normal file
|
@ -0,0 +1,2 @@
|
|||
[build]
|
||||
filehash = false
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 314 KiB After Width: | Height: | Size: 314 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
28
assets/manifest.json
Normal file
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "egui Template PWA",
|
||||
"short_name": "egui-template-pwa",
|
||||
"icons": [
|
||||
{
|
||||
"src": "./icon-256.png",
|
||||
"sizes": "256x256",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "./maskable_icon_x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "any maskable"
|
||||
},
|
||||
{
|
||||
"src": "./icon-1024.png",
|
||||
"sizes": "1024x1024",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"lang": "en-US",
|
||||
"id": "/index.html",
|
||||
"start_url": "./index.html",
|
||||
"display": "standalone",
|
||||
"background_color": "white",
|
||||
"theme_color": "white"
|
||||
}
|
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 128 KiB |
|
@ -2,8 +2,8 @@ var cacheName = 'egui-template-pwa';
|
|||
var filesToCache = [
|
||||
'./',
|
||||
'./index.html',
|
||||
'./eframe_template.js',
|
||||
'./eframe_template_bg.wasm',
|
||||
'./sshuttle_gui.js',
|
||||
'./sshuttle_gui_bg.wasm',
|
||||
];
|
||||
|
||||
/* Start the service worker and cache all of the app's content */
|
|
@ -1,78 +0,0 @@
|
|||
@echo off
|
||||
|
||||
SET script_path=%~dp0
|
||||
cd %script_path%
|
||||
|
||||
SET OPEN=0
|
||||
SET OPTIMIZE=0
|
||||
|
||||
:do_while
|
||||
IF (%1) == () GOTO end_while
|
||||
|
||||
IF %1 == -h GOTO print_help
|
||||
IF %1 == --help GOTO print_help
|
||||
|
||||
IF %1 == --optimize (
|
||||
SET OPTIMIZE=1
|
||||
SHIFT
|
||||
GOTO do_while
|
||||
)
|
||||
|
||||
IF %1 == --open (
|
||||
SET OPEN=1
|
||||
SHIFT
|
||||
GOTO do_while
|
||||
)
|
||||
|
||||
echo Unknown command "%1"
|
||||
:end_while
|
||||
|
||||
@REM call this first : `./setup_web.bat`
|
||||
|
||||
for %%I in (.) do SET FOLDER_NAME=%%~nxI
|
||||
|
||||
@REM assume crate name is the same as the folder name
|
||||
SET CRATE_NAME=%FOLDER_NAME%
|
||||
|
||||
@REM for those who name crates with-kebab-case
|
||||
SET CRATE_NAME_SNAKE_CASE=%FOLDER_NAME:-=_%
|
||||
|
||||
@REM This is required to enable the web_sys clipboard API which egui_web uses
|
||||
@REM https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.Clipboard.html
|
||||
@REM https://rustwasm.github.io/docs/wasm-bindgen/web-sys/unstable-apis.html
|
||||
SET RUSTFLAGS=--cfg=web_sys_unstable_apis
|
||||
|
||||
@REM Clear output from old stuff:
|
||||
DEL /F docs\%CRATE_NAME_SNAKE_CASE%_bg.wasm
|
||||
|
||||
echo Building rust...
|
||||
SET BUILD=release
|
||||
cargo build -p %CRATE_NAME% --release --lib --target wasm32-unknown-unknown
|
||||
|
||||
@REM Get the output directory (in the workspace it is in another location)
|
||||
FOR /F "delims=" %%i IN ('cargo metadata --format-version=1 ^| jq --raw-output .target_directory') DO SET TARGET=%%i
|
||||
|
||||
echo Generating JS bindings for wasm...
|
||||
SET TARGET_NAME=%CRATE_NAME_SNAKE_CASE%.wasm
|
||||
wasm-bindgen "%TARGET%\wasm32-unknown-unknown\%BUILD%\%TARGET_NAME%" --out-dir "docs" --no-modules --no-typescript
|
||||
|
||||
IF %OPTIMIZE% == 1 (
|
||||
echo Optimizing wasm...
|
||||
@REM to get wasm-opt: apt/brew/dnf install binaryen
|
||||
@REM add -g to get debug symbols :
|
||||
wasm-opt "docs\%CRATE_NAME%_bg.wasm" -O2 --fast-math -o "docs\%CRATE_NAME%_bg.wasm"
|
||||
)
|
||||
|
||||
echo Finished: docs/%CRATE_NAME_SNAKE_CASE%.wasm"
|
||||
|
||||
IF %OPEN% == 1 start http://localhost:8080/index.html
|
||||
|
||||
GOTO end_program
|
||||
|
||||
:print_help
|
||||
echo build_web.sh [--optimize] [--open]
|
||||
echo --optimize: optimize the generated WASM for performance
|
||||
echo --open: open the result in a browser
|
||||
GOTO end_program
|
||||
|
||||
:end_program
|
77
build_web.sh
|
@ -1,77 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
|
||||
CRATE_NAME=${PWD##*/} # assume crate name is the same as the folder name
|
||||
|
||||
script_path=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P )
|
||||
cd "$script_path"
|
||||
|
||||
OPEN=false
|
||||
OPTIMIZE=false
|
||||
|
||||
while test $# -gt 0; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
echo "build_web.sh [--optimize] [--open]"
|
||||
echo " --optimize: enable optimization step"
|
||||
echo " --open: open the result in a browser"
|
||||
exit 0
|
||||
;;
|
||||
-O|--optimize)
|
||||
shift
|
||||
OPTIMIZE=true
|
||||
;;
|
||||
--open)
|
||||
shift
|
||||
OPEN=true
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
./setup_web.sh
|
||||
|
||||
CRATE_NAME_SNAKE_CASE="${CRATE_NAME//-/_}" # for those who name crates with-kebab-case
|
||||
|
||||
# This is required to enable the web_sys clipboard API which egui_web uses
|
||||
# https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.Clipboard.html
|
||||
# https://rustwasm.github.io/docs/wasm-bindgen/web-sys/unstable-apis.html
|
||||
export RUSTFLAGS=--cfg=web_sys_unstable_apis
|
||||
|
||||
# Clear output from old stuff:
|
||||
rm -f "docs/${CRATE_NAME_SNAKE_CASE}_bg.wasm"
|
||||
|
||||
echo "Building rust…"
|
||||
BUILD=release
|
||||
cargo build -p "${CRATE_NAME}" --release --lib --target wasm32-unknown-unknown
|
||||
|
||||
# Get the output directory (in the workspace it is in another location)
|
||||
TARGET=$(cargo metadata --format-version=1 | jq --raw-output .target_directory)
|
||||
|
||||
echo "Generating JS bindings for wasm…"
|
||||
TARGET_NAME="${CRATE_NAME_SNAKE_CASE}.wasm"
|
||||
WASM_PATH="${TARGET}/wasm32-unknown-unknown/${BUILD}/${TARGET_NAME}"
|
||||
wasm-bindgen "${WASM_PATH}" --out-dir docs --no-modules --no-typescript
|
||||
|
||||
if [[ "${OPTIMIZE}" == true ]]; then
|
||||
echo "Optimizing wasm…"
|
||||
# to get wasm-opt: apt/brew/dnf install binaryen
|
||||
wasm-opt "docs/${CRATE_NAME}_bg.wasm" -O2 --fast-math -o "docs/${CRATE_NAME}_bg.wasm" # add -g to get debug symbols
|
||||
fi
|
||||
|
||||
echo "Finished: docs/${CRATE_NAME_SNAKE_CASE}.wasm"
|
||||
|
||||
if [[ "${OPEN}" == true ]]; then
|
||||
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||||
# Linux, ex: Fedora
|
||||
xdg-open http://localhost:8080/index.html#dev
|
||||
elif [[ "$OSTYPE" == "msys" ]]; then
|
||||
# Windows
|
||||
start http://localhost:8080/index.html#dev
|
||||
else
|
||||
# Darwin/MacOS, or something else
|
||||
open http://localhost:8080/index.html#dev
|
||||
fi
|
||||
fi
|
1
check.sh
|
@ -8,3 +8,4 @@ cargo fmt --all -- --check
|
|||
cargo clippy --workspace --all-targets --all-features -- -D warnings -W clippy::all
|
||||
cargo test --workspace --all-targets --all-features
|
||||
cargo test --workspace --doc
|
||||
trunk build
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
This folder contains the files required for the web app.
|
||||
|
||||
The reason the folder is called "docs" is because that is the name that GitHub requires in order to host a web page from the `master` branch of a repository. You can test the `eframe_template` at <https://emilk.github.io/eframe_template/>.
|
|
@ -1,27 +0,0 @@
|
|||
{
|
||||
"name": "Egui Template PWA",
|
||||
"short_name": "egui-template-pwa",
|
||||
"icons": [{
|
||||
"src": "./icon-256.png",
|
||||
"sizes": "256x256",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "./maskable_icon_x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "any maskable"
|
||||
},
|
||||
{
|
||||
"src": "./icon-1024.png",
|
||||
"sizes": "1024x1024",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"lang": "en-US",
|
||||
"id": "/index.html",
|
||||
"start_url": "./index.html",
|
||||
"display": "standalone",
|
||||
"background_color": "white",
|
||||
"theme_color": "white"
|
||||
}
|
|
@ -6,11 +6,29 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
|
||||
<head>
|
||||
<title>eframe template</title>
|
||||
<!-- change this to your project name -->
|
||||
<title>sshuttle_gui</title>
|
||||
|
||||
<!-- config for our rust wasm binary. go to https://trunkrs.dev/assets/#rust for more customization -->
|
||||
<link data-trunk rel="rust" data-wasm-opt="2" />
|
||||
<!-- this is the base url relative to which other urls will be constructed. trunk will insert this from the public-url option -->
|
||||
<base data-trunk-public-url />
|
||||
|
||||
<link data-trunk rel="icon" href="assets/favicon.ico">
|
||||
|
||||
|
||||
<link data-trunk rel="copy-file" href="assets/sw.js" />
|
||||
<link data-trunk rel="copy-file" href="assets/manifest.json" />
|
||||
<link data-trunk rel="copy-file" href="assets/icon-1024.png" />
|
||||
<link data-trunk rel="copy-file" href="assets/icon-256.png" />
|
||||
<link data-trunk rel="copy-file" href="assets/icon_ios_touch_192.png" />
|
||||
<link data-trunk rel="copy-file" href="assets/maskable_icon_x512.png" />
|
||||
|
||||
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<link rel="apple-touch-icon" href="icon_ios_touch_192.png">
|
||||
<meta name="theme-color" media="(prefers-color-scheme: light)" content="white">
|
||||
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#404040">
|
||||
<link rel="apple-touch-icon" href="icon_ios_touch_192.png">
|
||||
|
||||
<style>
|
||||
html {
|
||||
|
@ -38,6 +56,8 @@
|
|||
overflow: hidden;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Position canvas in center-top: */
|
||||
|
@ -94,78 +114,24 @@
|
|||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- The WASM code will resize the canvas dynamically -->
|
||||
<!-- the id is hardcoded in main.rs . so, make sure both match. -->
|
||||
<canvas id="the_canvas_id"></canvas>
|
||||
<div class="centered" id="center_text">
|
||||
<p style="font-size:16px">
|
||||
Loading…
|
||||
</p>
|
||||
<div class="lds-dual-ring"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// The `--no-modules`-generated JS from `wasm-bindgen` attempts to use
|
||||
// `WebAssembly.instantiateStreaming` to instantiate the wasm module,
|
||||
// but this doesn't work with `file://` urls. This example is frequently
|
||||
// viewed by simply opening `index.html` in a browser (with a `file://`
|
||||
// url), so it would fail if we were to call this function!
|
||||
//
|
||||
// Work around this for now by deleting the function to ensure that the
|
||||
// `no_modules.js` script doesn't have access to it. You won't need this
|
||||
// hack when deploying over HTTP.
|
||||
delete WebAssembly.instantiateStreaming;
|
||||
</script>
|
||||
|
||||
<!-- this is the JS generated by the `wasm-bindgen` CLI tool -->
|
||||
<script src="eframe_template.js"></script>
|
||||
|
||||
<script>
|
||||
// We'll defer our execution until the wasm is ready to go.
|
||||
// Here we tell bindgen the path to the wasm file so it can start
|
||||
// initialization and return to us a promise when it's done.
|
||||
console.debug("loading wasm…");
|
||||
wasm_bindgen("./eframe_template_bg.wasm")
|
||||
.then(on_wasm_loaded)
|
||||
.catch(on_wasm_error);
|
||||
|
||||
function on_wasm_loaded() {
|
||||
console.debug("wasm loaded. starting app…");
|
||||
|
||||
// This call installs a bunch of callbacks and then returns:
|
||||
wasm_bindgen.start("the_canvas_id");
|
||||
|
||||
console.debug("app started.");
|
||||
document.getElementById("center_text").remove();
|
||||
}
|
||||
|
||||
function on_wasm_error(error) {
|
||||
console.error("Failed to start: " + error);
|
||||
document.getElementById("center_text").innerHTML = `
|
||||
<p>
|
||||
An error occurred during loading:
|
||||
</p>
|
||||
<p style="font-family:Courier New">
|
||||
${error}
|
||||
</p>
|
||||
<p style="font-size:14px">
|
||||
Make sure you use a modern browser with WebGL and WASM enabled.
|
||||
</p>`;
|
||||
}
|
||||
</script>
|
||||
|
||||
<!--Register Service Worker-->
|
||||
<!--Register Service Worker. this will cache the wasm / js scripts for offline use (for PWA functionality). -->
|
||||
<!-- Force refresh (Ctrl + F5) to load the latest files instead of cached files -->
|
||||
<script>
|
||||
// We disable caching during development so that we always view the latest version.
|
||||
if ('serviceWorker' in navigator && window.location.hash !== "#dev") {
|
||||
window.addEventListener('load', function() {
|
||||
window.addEventListener('load', function () {
|
||||
navigator.serviceWorker.register('sw.js');
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
@REM Pre-requisites:
|
||||
rustup target add wasm32-unknown-unknown
|
||||
cargo install wasm-bindgen-cli
|
||||
cargo update -p wasm-bindgen
|
||||
|
||||
@REM For local tests with `./start_server`:
|
||||
cargo install basic-http-server
|
|
@ -1,9 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
|
||||
# Pre-requisites:
|
||||
rustup target add wasm32-unknown-unknown
|
||||
cargo install wasm-bindgen-cli --version 0.2.82
|
||||
|
||||
# For local tests with `./start_server`:
|
||||
cargo install basic-http-server
|
139
src/app.rs
|
@ -1,19 +1,82 @@
|
|||
use egui::Window;
|
||||
use crate::connect_ssh;
|
||||
|
||||
|
||||
/// We derive Deserialize/Serialize so we can persist app state on shutdown.
|
||||
#[derive(serde::Deserialize, serde::Serialize)]
|
||||
#[serde(default)] // if we add new fields, give them default values when deserializing old state
|
||||
pub struct TemplateApp {
|
||||
// Example stuff:
|
||||
label: String,
|
||||
|
||||
deets: SshDeets,
|
||||
// this how you opt-out of serialization of a member
|
||||
#[serde(skip)]
|
||||
value: f32,
|
||||
}
|
||||
#[derive(serde::Deserialize, serde::Serialize, Clone)]
|
||||
#[serde(default)]
|
||||
pub struct SshDeets {
|
||||
pub dns: bool,
|
||||
pub user: String,
|
||||
pub ip: String,
|
||||
pub port: String,
|
||||
pub mask: String,
|
||||
}
|
||||
|
||||
impl Default for SshDeets {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
dns: true,
|
||||
user: "No".to_owned(),
|
||||
ip: "127.0.0.1".to_owned(),
|
||||
port: "8080".to_owned(),
|
||||
mask: "".to_owned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SshDeets {
|
||||
pub fn new(self,
|
||||
yeah: bool,
|
||||
username: &str,
|
||||
ip_addy: &str,
|
||||
port_num: &str,
|
||||
masking: String) -> Self
|
||||
{
|
||||
Self {
|
||||
dns: yeah,
|
||||
user: String::from(username),
|
||||
ip: String::from(ip_addy),
|
||||
port: String::from(port_num),
|
||||
mask: masking,
|
||||
}
|
||||
|
||||
}
|
||||
pub fn concat(&self, connect: bool) -> Vec<String> {
|
||||
let mut final_thing: Vec<String> = vec![];
|
||||
if connect == false{
|
||||
if self.dns == true {
|
||||
final_thing.push(String::from("--dns"));
|
||||
final_thing.push(String::from("-Nr"));
|
||||
final_thing.push(format!("{}:{}", self.user, self.ip));
|
||||
final_thing.push(String::from("-x"));
|
||||
final_thing.push(self.mask.clone());
|
||||
return final_thing;
|
||||
}
|
||||
else {
|
||||
return vec![];
|
||||
}
|
||||
}else {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TemplateApp {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
// Example stuff:
|
||||
deets: SshDeets::default(),
|
||||
label: "Hello World!".to_owned(),
|
||||
value: 2.7,
|
||||
}
|
||||
|
@ -44,68 +107,66 @@ impl eframe::App for TemplateApp {
|
|||
|
||||
/// Called each time the UI needs repainting, which may be many times per second.
|
||||
/// Put your widgets into a `SidePanel`, `TopPanel`, `CentralPanel`, `Window` or `Area`.
|
||||
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
||||
let Self { label, value } = self;
|
||||
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
let Self { label, value, deets } = self;
|
||||
|
||||
|
||||
// Examples of how to create different panels and windows.
|
||||
// Pick whichever suits you.
|
||||
// Tip: a good default choice is to just keep the `CentralPanel`.
|
||||
// For inspiration and more examples, go to https://emilk.github.io/egui
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))] // no File->Quit on web pages!
|
||||
egui::TopBottomPanel::top("top_panel").show(ctx, |ui| {
|
||||
// The top panel is often a good place for a menu bar:
|
||||
egui::menu::bar(ui, |ui| {
|
||||
ui.menu_button("File", |ui| {
|
||||
if ui.button("Quit").clicked() {
|
||||
frame.quit();
|
||||
_frame.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
egui::SidePanel::left("side_panel").show(ctx, |ui| {
|
||||
ui.heading("Side Panel");
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Write something: ");
|
||||
ui.text_edit_singleline(label);
|
||||
});
|
||||
|
||||
ui.add(egui::Slider::new(value, 0.0..=10.0).text("value"));
|
||||
if ui.button("Increment").clicked() {
|
||||
*value += 1.0;
|
||||
}
|
||||
|
||||
ui.with_layout(egui::Layout::bottom_up(egui::Align::LEFT), |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.spacing_mut().item_spacing.x = 0.0;
|
||||
ui.label("powered by ");
|
||||
ui.hyperlink_to("egui", "https://github.com/emilk/egui");
|
||||
ui.label(" and ");
|
||||
ui.hyperlink_to("eframe", "https://github.com/emilk/egui/tree/master/eframe");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
// The central panel the region left after adding TopPanel's and SidePanel's
|
||||
let mut outout = String::new();
|
||||
ui.label("put your linux ssh username, ip, and port (does not have to be root)");
|
||||
ui.text_edit_singleline(&mut deets.user);
|
||||
ui.text_edit_singleline(&mut deets.ip);
|
||||
ui.text_edit_singleline(&mut deets.port);
|
||||
|
||||
ui.heading("eframe template");
|
||||
ui.label("check if using --dns flag");
|
||||
ui.checkbox(&mut deets.dns, "dns'd");
|
||||
|
||||
ui.label("include mask flags");
|
||||
ui.text_edit_singleline(&mut deets.mask);
|
||||
|
||||
if ui.button("connect").clicked() {
|
||||
connect_ssh(false, &*deets);
|
||||
}
|
||||
/* ui.heading("eframe template");
|
||||
ui.hyperlink("https://github.com/emilk/eframe_template");
|
||||
ui.add(egui::github_link_file!(
|
||||
"https://github.com/emilk/eframe_template/blob/master/",
|
||||
"Source code."
|
||||
));
|
||||
)); */
|
||||
egui::SidePanel::right("side_panel").show(ctx, |ui| {
|
||||
ui.add(egui::widgets::Label::new("This will be for stdout eventually".to_owned()));
|
||||
|
||||
});
|
||||
|
||||
egui::warn_if_debug_build(ui);
|
||||
});
|
||||
|
||||
if false {
|
||||
egui::Window::new("Window").show(ctx, |ui| {
|
||||
ui.label("Windows can be moved by dragging them.");
|
||||
ui.label("They are automatically sized based on contents.");
|
||||
ui.label("You can turn on resizing and scrolling if you like.");
|
||||
ui.label("You would normally chose either panels OR windows.");
|
||||
});
|
||||
}
|
||||
|
||||
Window::new("info")
|
||||
.anchor(egui::Align2::RIGHT_TOP, [-5.0,5.0])
|
||||
.default_size([500.0,500.0])
|
||||
.show(ctx, |ui| {
|
||||
ui.label("Make sure you have ssh keys, no password connecting!");
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
|
35
src/lib.rs
|
@ -1,26 +1,21 @@
|
|||
#![warn(clippy::all, rust_2018_idioms)]
|
||||
|
||||
use std::process::{ExitStatus, Command, Stdio};
|
||||
|
||||
mod app;
|
||||
pub use app::TemplateApp;
|
||||
pub use app::SshDeets;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// When compiling for web:
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use eframe::wasm_bindgen::{self, prelude::*};
|
||||
|
||||
/// This is the entry-point for all the web-assembly.
|
||||
/// This is called once from the HTML.
|
||||
/// It loads the app, installs some callbacks, then returns.
|
||||
/// You can add more callbacks like this if you want to call in to your code.
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[wasm_bindgen]
|
||||
pub fn start(canvas_id: &str) -> Result<(), eframe::wasm_bindgen::JsValue> {
|
||||
// Make sure panics are logged using `console.error`.
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
// Redirect tracing to console.log and friends:
|
||||
tracing_wasm::set_as_global_default();
|
||||
|
||||
eframe::start_web(canvas_id, Box::new(|cc| Box::new(TemplateApp::new(cc))))
|
||||
pub fn connect_ssh(connect: bool, structure: &SshDeets) -> Result<String, ExitStatus>{
|
||||
let argss = structure.concat(connect);
|
||||
let mut stdout = String::new();
|
||||
if connect == false{
|
||||
let skrunk = Command::new("sshuttle")
|
||||
.args(argss)
|
||||
//.spawn()
|
||||
.stdout(Stdio::piped())
|
||||
.output().unwrap();
|
||||
let stdout = String::from_utf8(skrunk.stdout).unwrap();
|
||||
}
|
||||
Ok(stdout)
|
||||
}
|
||||
|
|
22
src/main.rs
|
@ -9,8 +9,26 @@ fn main() {
|
|||
|
||||
let native_options = eframe::NativeOptions::default();
|
||||
eframe::run_native(
|
||||
"eframe template",
|
||||
"sshuttle",
|
||||
native_options,
|
||||
Box::new(|cc| Box::new(eframe_template::TemplateApp::new(cc))),
|
||||
Box::new(|cc| Box::new(sshuttle_gui::TemplateApp::new(cc))),
|
||||
);
|
||||
}
|
||||
|
||||
// when compiling to web using trunk.
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
fn main() {
|
||||
// Make sure panics are logged using `console.error`.
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
// Redirect tracing to console.log and friends:
|
||||
tracing_wasm::set_as_global_default();
|
||||
|
||||
let web_options = eframe::WebOptions::default();
|
||||
eframe::start_web(
|
||||
"the_canvas_id", // hardcode it
|
||||
web_options,
|
||||
Box::new(|cc| Box::new(sshuttle_gui::TemplateApp::new(cc))),
|
||||
)
|
||||
.expect("failed to start eframe");
|
||||
}
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
@echo off
|
||||
|
||||
@REM Starts a local web-server that serves the contents of the `doc/` folder,
|
||||
@REM which is the folder to where the web version is compiled.
|
||||
|
||||
echo "open http://localhost:8080"
|
||||
|
||||
(cd docs && basic-http-server --addr 127.0.0.1:8080 .)
|
||||
@REM (cd docs && python3 -m http.server 8080 --bind 127.0.0.1)
|
|
@ -1,12 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
|
||||
PORT=8080
|
||||
|
||||
# Starts a local web-server that serves the contents of the `doc/` folder,
|
||||
# which is the folder to where the web version is compiled.
|
||||
|
||||
echo "open http://localhost:$PORT/index.html#dev"
|
||||
|
||||
(cd docs && basic-http-server --addr 127.0.0.1:$PORT .)
|
||||
# (cd docs && python3 -m http.server $PORT --bind 127.0.0.1)
|
|
@ -1,32 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
script_path=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P )
|
||||
cd "$script_path"
|
||||
|
||||
./setup_web.sh
|
||||
|
||||
CRATE_NAME=${PWD##*/} # assume crate name is the same as the folder name
|
||||
|
||||
# This is required to enable the web_sys clipboard API which eframe web uses
|
||||
# https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.Clipboard.html
|
||||
# https://rustwasm.github.io/docs/wasm-bindgen/web-sys/unstable-apis.html
|
||||
export RUSTFLAGS=--cfg=web_sys_unstable_apis
|
||||
|
||||
echo "Building rust…"
|
||||
BUILD=debug # debug builds are faster
|
||||
|
||||
cargo build --lib --target wasm32-unknown-unknown
|
||||
|
||||
TARGET="target"
|
||||
|
||||
echo "Generating JS bindings for wasm…"
|
||||
|
||||
rm -f "${CRATE_NAME}_bg.wasm" # Remove old output (if any)
|
||||
|
||||
TARGET_NAME="${CRATE_NAME}.wasm"
|
||||
wasm-bindgen "${TARGET}/wasm32-unknown-unknown/$BUILD/$TARGET_NAME" \
|
||||
--out-dir . --no-modules --no-typescript
|
||||
|
||||
# Remove output:
|
||||
rm -f "${CRATE_NAME}_bg.wasm"
|
||||
rm -f "${CRATE_NAME}.js"
|