mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-27 10:18:54 +00:00
feat(windows): Tauri boilerplate and CI changes (#2742)
Trying to get CI/CD to produce firezone-windows-client.exe. Can't remember if I need both a PR and a draft release or just the draft release for that. --------- Signed-off-by: Reactor Scram <ReactorScram@users.noreply.github.com> Co-authored-by: Jamil <jamilbk@users.noreply.github.com>
This commit is contained in:
75
.github/workflows/_rust.yml
vendored
75
.github/workflows/_rust.yml
vendored
@@ -64,6 +64,81 @@ jobs:
|
||||
- uses: ./.github/actions/setup-rust
|
||||
- run: cargo test --all-features ${{ matrix.packages }}
|
||||
|
||||
# TODO: Remove when windows build works reliably in cd.yml
|
||||
# These `temp-` jobs serve as a sanity check to early exit if there's an issue in the workflow
|
||||
temp-build-windows-artifacts:
|
||||
runs-on: windows-2019
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./rust
|
||||
strategy:
|
||||
fail-fast: false
|
||||
# The matrix is 1x1 to match the style of build-push-linux-release-artifacts
|
||||
# In the future we could try to cross-compile aarch64-windows here.
|
||||
matrix:
|
||||
name:
|
||||
- package: hello-world
|
||||
artifact: hello-world
|
||||
env:
|
||||
BINARY_DEST_PATH: ${{ matrix.name.artifact }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/setup-rust
|
||||
with:
|
||||
targets: x86_64-pc-windows-msvc
|
||||
- name: Build release binaries
|
||||
run: |
|
||||
cargo build --release -p ${{ matrix.name.package }}
|
||||
cp target/release/${{ matrix.name.package }}.exe "${{ env.BINARY_DEST_PATH }}-x64.exe"
|
||||
pwd
|
||||
ls *.exe
|
||||
- name: Save build artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ matrix.name.artifact }}-x64.exe
|
||||
path: ${{ github.workspace }}/rust/${{ env.BINARY_DEST_PATH }}-x64.exe
|
||||
|
||||
# This should be identical to `build-push-windows-release-artifacts` in `cd.yml` except for the permissions, needs, and uploading step
|
||||
temp-build-tauri:
|
||||
runs-on: windows-2019
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./rust
|
||||
strategy:
|
||||
fail-fast: false
|
||||
# The matrix is 1x1 to match the style of build-push-linux-release-artifacts
|
||||
# In the future we could try to cross-compile aarch64-windows here.
|
||||
matrix:
|
||||
name:
|
||||
- package: firezone-windows-client
|
||||
artifact: windows-client
|
||||
env:
|
||||
BINARY_DEST_PATH: ${{ matrix.name.artifact }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/setup-rust
|
||||
with:
|
||||
targets: x86_64-pc-windows-msvc
|
||||
- name: Build release binaries
|
||||
run: |
|
||||
cargo install tauri-cli
|
||||
|
||||
# Tauri build already defaults to '--release'
|
||||
cargo tauri build
|
||||
|
||||
# Used for release artifact
|
||||
cp target/release/${{ matrix.name.package }}.exe "${{ env.BINARY_DEST_PATH }}-x64.exe"
|
||||
|
||||
pwd
|
||||
ls *.exe
|
||||
|
||||
# There's an MSI and NSIS installer here but their names include the version so I'll try those later.
|
||||
- name: Save build artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ matrix.name.artifact }}-x64.exe
|
||||
path: ${{ github.workspace }}/rust/${{ env.BINARY_DEST_PATH }}-x64.exe
|
||||
|
||||
smoke-test-relay:
|
||||
runs-on: ubuntu-22.04
|
||||
defaults:
|
||||
|
||||
37
.github/workflows/cd.yml
vendored
37
.github/workflows/cd.yml
vendored
@@ -243,59 +243,54 @@ jobs:
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
# Build for Windows with Cross
|
||||
# Build for Windows
|
||||
build-push-windows-release-artifacts:
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: write
|
||||
needs: update-release-draft
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: windows-2019
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./rust
|
||||
strategy:
|
||||
fail-fast: false
|
||||
# The matrix is 1x1 to match the style of build-push-linux-release-artifacts
|
||||
# In the future we could try to cross-compile aarch64-windows here.
|
||||
matrix:
|
||||
arch:
|
||||
- target: x86_64-pc-windows-msvc
|
||||
shortname: x64
|
||||
name:
|
||||
- package: firezone-windows-client
|
||||
artifact: windows-client
|
||||
env:
|
||||
BINARY_DEST_PATH: ${{ matrix.name.artifact }}-${{ matrix.arch.shortname }}
|
||||
BINARY_DEST_PATH: ${{ matrix.name.artifact }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/setup-rust
|
||||
with:
|
||||
targets: x86_64-pc-windows-msvc
|
||||
- uses: taiki-e/install-action@v2
|
||||
with:
|
||||
tool: cross
|
||||
- name: Build release binaries
|
||||
run: |
|
||||
set -xe
|
||||
cargo install tauri-cli
|
||||
|
||||
cross build --release -p ${{ matrix.name.package }} --target ${{ matrix.arch.target }}
|
||||
# Tauri build already defaults to '--release'
|
||||
cargo tauri build
|
||||
|
||||
# Used for release artifact
|
||||
cp target/${{ matrix.arch.target }}/release/${{ matrix.name.package }} $BINARY_DEST_PATH
|
||||
cp target/release/${{ matrix.name.package }}.exe "${{ env.BINARY_DEST_PATH }}-x64.exe"
|
||||
|
||||
pwd
|
||||
ls *.exe
|
||||
|
||||
# There's an MSI and NSIS installer here but their names include the version so I'll try those later.
|
||||
|
||||
# Used for Docker images
|
||||
cp target/${{ matrix.arch.target }}/release/${{ matrix.name.package }} ${{ matrix.name.package }}
|
||||
sha256sum $BINARY_DEST_PATH > $BINARY_DEST_PATH.sha256sum.txt
|
||||
|
||||
ls -la $BINARY_DEST_PATH
|
||||
ls -la $BINARY_DEST_PATH.sha256sum.txt
|
||||
- name: Upload Release Assets
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -xe
|
||||
|
||||
# TODO: Calculate sha256sum for this binary and attach to release
|
||||
gh release upload ${{ needs.update-release-draft.outputs.tag_name }} \
|
||||
${{ env.BINARY_DEST_PATH }} \
|
||||
${{ env.BINARY_DEST_PATH }}.sha256sum.txt \
|
||||
${{ env.BINARY_DEST_PATH }}-x64.exe \
|
||||
--clobber \
|
||||
--repo ${{ github.repository }}
|
||||
|
||||
|
||||
2358
rust/Cargo.lock
generated
2358
rust/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -6,11 +6,12 @@ members = [
|
||||
"connlib/shared",
|
||||
"connlib/tunnel",
|
||||
"gateway",
|
||||
"hello-world",
|
||||
"linux-client",
|
||||
"firezone-cli-utils",
|
||||
"phoenix-channel",
|
||||
"relay",
|
||||
"windows-client",
|
||||
"windows-client/src-tauri",
|
||||
]
|
||||
|
||||
resolver = "2"
|
||||
@@ -32,7 +33,7 @@ connlib-client-apple = { path = "connlib/clients/apple"}
|
||||
connlib-client-shared = { path = "connlib/clients/shared"}
|
||||
firezone-gateway = { path = "gateway"}
|
||||
firezone-linux-client = { path = "linux-client"}
|
||||
firezone-windows-client = { path = "windows-client"}
|
||||
firezone-windows-client = { path = "windows-client/src-tauri"}
|
||||
firezone-cli-utils = { path = "firezone-cli-utils"}
|
||||
connlib-shared = { path = "connlib/shared"}
|
||||
firezone-tunnel = { path = "connlib/tunnel"}
|
||||
|
||||
8
rust/hello-world/Cargo.toml
Executable file
8
rust/hello-world/Cargo.toml
Executable file
@@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "hello-world"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
3
rust/hello-world/src/main.rs
Executable file
3
rust/hello-world/src/main.rs
Executable file
@@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
23
rust/windows-client/.gitignore
vendored
Executable file
23
rust/windows-client/.gitignore
vendored
Executable file
@@ -0,0 +1,23 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
@@ -1,22 +0,0 @@
|
||||
[package]
|
||||
name = "firezone-windows-client"
|
||||
# mark:automatic-version
|
||||
version = "1.20231001.0"
|
||||
edition = "2021"
|
||||
|
||||
[target.'cfg(windows)'.build-dependencies]
|
||||
embed-resource = "2.4.0"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
native-windows-derive = "1.0.5"
|
||||
native-windows-gui = "1.0.13"
|
||||
|
||||
[target.'cfg(windows)'.dependencies.windows]
|
||||
version = "0.52.0"
|
||||
features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_Graphics_Gdi",
|
||||
"Win32_System_LibraryLoader",
|
||||
"Win32_UI_Shell",
|
||||
"Win32_UI_WindowsAndMessaging",
|
||||
]
|
||||
@@ -1,11 +1,46 @@
|
||||
# windows-client
|
||||
|
||||
This crate houses the Firezone Windows client.
|
||||
This crate houses a Windows GUI client.
|
||||
|
||||
## Building
|
||||
|
||||
Run `cargo build` in this directory.
|
||||
From this dir:
|
||||
|
||||
```
|
||||
# First-time setup - Install Tauri's dev server / hot-reload tool
|
||||
cargo install tauri-cli
|
||||
|
||||
# Builds a release exe
|
||||
cargo tauri build
|
||||
|
||||
# The release exe, MSI, and NSIS installer should be up in the workspace.
|
||||
# The exe can run without being installed
|
||||
stat ../target/release/firezone-windows-client.exe
|
||||
stat ../target/release/bundle/msi/firezone-windows-client_0.0.0_x64_en-US.msi
|
||||
stat ../target/release/bundle/nsis/firezone-windows-client_0.0.0_x64-setup.exe
|
||||
```
|
||||
|
||||
## Running
|
||||
|
||||
Run `cargo run` in this directory.
|
||||
From this dir:
|
||||
|
||||
```
|
||||
# Tauri has some hot-reloading features. If the Rust code changes it will even recompile and restart the program for you.
|
||||
cargo tauri dev
|
||||
|
||||
# You can call debug subcommands on the exe from this directory too
|
||||
# e.g. this is equivalent to `cargo run -- debug`
|
||||
cargo tauri dev -- -- debug
|
||||
|
||||
# Debug connlib GUI integration
|
||||
cargo tauri dev -- -- debug-connlib
|
||||
|
||||
# The exe is up in the workspace
|
||||
stat ../target/debug/firezone-windows-client.exe
|
||||
```
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
(From Tauri's default README)
|
||||
|
||||
- [VS Code](https://code.visualstudio.com/) + [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer)
|
||||
|
||||
19
rust/windows-client/ci_check.bash
Executable file
19
rust/windows-client/ci_check.bash
Executable file
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env bash
|
||||
# Usage: ./ci_check.bash
|
||||
|
||||
# Performs static checks similar to what the Github Actions workflows will do, so errors can be caught before committing.
|
||||
|
||||
# ReactorScram uses this in the Git pre-commit hook on her Windows dev system.
|
||||
|
||||
# Fail on any non-zero return code
|
||||
set -euo pipefail
|
||||
|
||||
# Fail on yaml workflow errors
|
||||
yamllint ../../.github/workflows/*
|
||||
|
||||
# Fail on Rust errors
|
||||
pushd .. > /dev/null
|
||||
cargo clippy --all-targets --all-features -p firezone-windows-client -- -D warnings
|
||||
cargo fmt --check
|
||||
cargo doc --all-features --no-deps --document-private-items -p firezone-windows-client
|
||||
popd > /dev/null
|
||||
3
rust/windows-client/src-tauri/.gitignore
vendored
Executable file
3
rust/windows-client/src-tauri/.gitignore
vendored
Executable file
@@ -0,0 +1,3 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
35
rust/windows-client/src-tauri/Cargo.toml
Executable file
35
rust/windows-client/src-tauri/Cargo.toml
Executable file
@@ -0,0 +1,35 @@
|
||||
[package]
|
||||
name = "firezone-windows-client"
|
||||
# mark:automatic-version
|
||||
version = "1.20231001.0"
|
||||
description = "Firezone Windows Client"
|
||||
edition = "2021"
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "1.5", features = [] }
|
||||
|
||||
[dependencies]
|
||||
connlib-client-shared = { workspace = true }
|
||||
secrecy.workspace = true
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
thiserror = "1.0.50"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
# Tauri works fine on Linux, but it requires a lot of build-time deps like glib and gdk, so I've blocked it out for now.
|
||||
tauri = { version = "1.5", features = [ "system-tray", "shell-open"] }
|
||||
wintun = "0.3.2"
|
||||
|
||||
[target.'cfg(windows)'.dependencies.windows]
|
||||
version = "0.52.0"
|
||||
features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_System_LibraryLoader",
|
||||
"Win32_UI_Shell",
|
||||
"Win32_UI_WindowsAndMessaging",
|
||||
]
|
||||
|
||||
[features]
|
||||
# this feature is used for production builds or when `devPath` points to the filesystem
|
||||
# DO NOT REMOVE!!
|
||||
custom-protocol = ["tauri/custom-protocol"]
|
||||
3
rust/windows-client/src-tauri/build.rs
Executable file
3
rust/windows-client/src-tauri/build.rs
Executable file
@@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
tauri_build::build()
|
||||
}
|
||||
BIN
rust/windows-client/src-tauri/icons/firezone.ico
Executable file
BIN
rust/windows-client/src-tauri/icons/firezone.ico
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
237
rust/windows-client/src-tauri/src/main.rs
Executable file
237
rust/windows-client/src-tauri/src/main.rs
Executable file
@@ -0,0 +1,237 @@
|
||||
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
enum Error {}
|
||||
|
||||
fn main() {
|
||||
let mut args = std::env::args();
|
||||
// Ignore the exe name
|
||||
args.next().unwrap();
|
||||
|
||||
match args.next().as_deref() {
|
||||
None | Some("tauri") => details::main_tauri(),
|
||||
Some("debug") => println!("debug"),
|
||||
Some("debug-connlib") => main_debug_connlib(),
|
||||
Some("debug-wintun") => details::main_debug_wintun(),
|
||||
Some(cmd) => println!("Subcommand `{cmd}` not recognized"),
|
||||
}
|
||||
}
|
||||
|
||||
fn main_debug_connlib() {
|
||||
use connlib_client_shared::Error as ConnlibError;
|
||||
use connlib_client_shared::{Callbacks, Session};
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
struct WindowsCallbacks {}
|
||||
|
||||
impl Callbacks for WindowsCallbacks {
|
||||
type Error = Error;
|
||||
|
||||
fn on_disconnect(&self, error: Option<&ConnlibError>) -> Result<(), Self::Error> {
|
||||
panic!("error recovery not implemented. Error: {error:?}");
|
||||
}
|
||||
|
||||
fn on_error(&self, error: &ConnlibError) -> Result<(), Self::Error> {
|
||||
panic!("error recovery not implemented. Error: {error}");
|
||||
}
|
||||
}
|
||||
|
||||
let callbacks = WindowsCallbacks::default();
|
||||
|
||||
let _session = Session::connect(
|
||||
"https://api.firez.one/firezone",
|
||||
secrecy::SecretString::from_str("bogus_secret").unwrap(),
|
||||
"trisha-laptop-2023".to_string(),
|
||||
callbacks,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
mod details {
|
||||
pub fn main_tauri() {
|
||||
panic!("GUI not implemented for Linux.");
|
||||
}
|
||||
|
||||
pub fn main_debug_wintun() {
|
||||
panic!("Wintun not implemented for Linux.");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
mod details {
|
||||
use tauri::{
|
||||
CustomMenuItem, Manager, SystemTray, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem,
|
||||
SystemTraySubmenu,
|
||||
};
|
||||
|
||||
pub fn main_tauri() {
|
||||
let tray = SystemTray::new().with_menu(signed_out_menu());
|
||||
|
||||
tauri::Builder::default()
|
||||
.on_window_event(|event| {
|
||||
if let tauri::WindowEvent::CloseRequested { api, .. } = event.event() {
|
||||
// Keep the frontend running but just hide this webview
|
||||
// Per https://tauri.app/v1/guides/features/system-tray/#preventing-the-app-from-closing
|
||||
|
||||
event.window().hide().unwrap();
|
||||
api.prevent_close();
|
||||
}
|
||||
})
|
||||
.invoke_handler(tauri::generate_handler![greet])
|
||||
.system_tray(tray)
|
||||
.on_system_tray_event(|app, event| {
|
||||
if let SystemTrayEvent::MenuItemClick { id, .. } = event {
|
||||
match id.as_str() {
|
||||
"/sign_in" => {
|
||||
app.tray_handle()
|
||||
.set_menu(signed_in_menu(
|
||||
"user@example.com",
|
||||
&[("CloudFlare", "1.1.1.1"), ("Google", "8.8.8.8")],
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
"/sign_out" => app.tray_handle().set_menu(signed_out_menu()).unwrap(),
|
||||
"/about" => {
|
||||
let win = app.get_window("main-window").unwrap();
|
||||
|
||||
if win.is_visible().unwrap() {
|
||||
// If we close the window here, we can't re-open it, we'd have to fully re-create it. Not needed for MVP - We agreed 100 MB is fine for the GUI client.
|
||||
win.hide().unwrap();
|
||||
} else {
|
||||
win.show().unwrap();
|
||||
}
|
||||
}
|
||||
"/settings" => {
|
||||
app.tray_handle()
|
||||
.set_menu(signed_in_menu(
|
||||
"user@example.com",
|
||||
&[
|
||||
("CloudFlare", "1.1.1.1"),
|
||||
("New resource", "127.0.0.1"),
|
||||
("Google", "8.8.8.8"),
|
||||
],
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
"/quit" => app.exit(0),
|
||||
id => {
|
||||
if let Some(addr) = id.strip_prefix("/resource/") {
|
||||
println!("TODO copy {addr} to clipboard");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.build(tauri::generate_context!())
|
||||
.expect("error while building tauri application")
|
||||
.run(|_app_handle, event| {
|
||||
if let tauri::RunEvent::ExitRequested { api, .. } = event {
|
||||
// Don't exit if we close our main window
|
||||
// https://tauri.app/v1/guides/features/system-tray/#preventing-the-app-from-closing
|
||||
|
||||
api.prevent_exit();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn main_debug_wintun() {
|
||||
use std::sync::Arc;
|
||||
|
||||
//Must be run as Administrator because we create network adapters
|
||||
//Load the wintun dll file so that we can call the underlying C functions
|
||||
//Unsafe because we are loading an arbitrary dll file
|
||||
let wintun = unsafe { wintun::load_from_path("../wintun/bin/amd64/wintun.dll") }
|
||||
.expect("Failed to load wintun dll");
|
||||
|
||||
//Try to open an adapter with the name "Demo"
|
||||
let adapter = match wintun::Adapter::open(&wintun, "Demo") {
|
||||
Ok(a) => a,
|
||||
Err(_) => {
|
||||
//If loading failed (most likely it didn't exist), create a new one
|
||||
wintun::Adapter::create(&wintun, "Demo", "Example manor hatch stash", None)
|
||||
.expect("Failed to create wintun adapter!")
|
||||
}
|
||||
};
|
||||
//Specify the size of the ring buffer the wintun driver should use.
|
||||
let session = Arc::new(adapter.start_session(wintun::MAX_RING_CAPACITY).unwrap());
|
||||
|
||||
//Get a 20 byte packet from the ring buffer
|
||||
let mut packet = session.allocate_send_packet(20).unwrap();
|
||||
let bytes: &mut [u8] = packet.bytes_mut();
|
||||
//Write IPV4 version and header length
|
||||
bytes[0] = 0x40;
|
||||
|
||||
//Finish writing IP header
|
||||
bytes[9] = 0x69;
|
||||
bytes[10] = 0x04;
|
||||
bytes[11] = 0x20;
|
||||
//...
|
||||
|
||||
//Send the packet to wintun virtual adapter for processing by the system
|
||||
session.send_packet(packet);
|
||||
|
||||
println!("Sleeping 1 minute, see if the adapter is visible...");
|
||||
std::thread::sleep(std::time::Duration::from_secs(60));
|
||||
|
||||
//Stop any readers blocking for data on other threads
|
||||
//Only needed when a blocking reader is preventing shutdown Ie. it holds an Arc to the
|
||||
//session, blocking it from being dropped
|
||||
session.shutdown().unwrap();
|
||||
|
||||
//the session is stopped on drop
|
||||
//drop(session);
|
||||
|
||||
//drop(adapter)
|
||||
//And the adapter closes its resources when dropped
|
||||
}
|
||||
|
||||
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
|
||||
#[tauri::command]
|
||||
fn greet(name: &str) -> String {
|
||||
format!("Hello, {}! You've been greeted from Rust!", name)
|
||||
}
|
||||
|
||||
fn signed_in_menu(user_email: &str, resources: &[(&str, &str)]) -> SystemTrayMenu {
|
||||
let mut menu = SystemTrayMenu::new()
|
||||
.add_item(
|
||||
CustomMenuItem::new("".to_string(), format!("Signed in as {user_email}"))
|
||||
.disabled(),
|
||||
)
|
||||
.add_item(CustomMenuItem::new("/sign_out".to_string(), "Sign out"))
|
||||
.add_native_item(SystemTrayMenuItem::Separator)
|
||||
.add_item(CustomMenuItem::new("".to_string(), "RESOURCES"));
|
||||
|
||||
for (name, addr) in resources {
|
||||
let submenu = SystemTrayMenu::new().add_item(CustomMenuItem::new(
|
||||
format!("/resource/{addr}"),
|
||||
addr.to_string(),
|
||||
));
|
||||
menu = menu.add_submenu(SystemTraySubmenu::new(name.to_string(), submenu));
|
||||
}
|
||||
|
||||
menu = menu
|
||||
.add_native_item(SystemTrayMenuItem::Separator)
|
||||
.add_item(CustomMenuItem::new("/about".to_string(), "About"))
|
||||
.add_item(CustomMenuItem::new("/settings".to_string(), "Settings"))
|
||||
.add_item(
|
||||
CustomMenuItem::new("/quit".to_string(), "Quit Firezone").accelerator("Ctrl+Q"),
|
||||
);
|
||||
|
||||
menu
|
||||
}
|
||||
|
||||
fn signed_out_menu() -> SystemTrayMenu {
|
||||
SystemTrayMenu::new()
|
||||
.add_item(CustomMenuItem::new("/sign_in".to_string(), "Sign In"))
|
||||
.add_native_item(SystemTrayMenuItem::Separator)
|
||||
.add_item(CustomMenuItem::new("/about".to_string(), "About"))
|
||||
.add_item(CustomMenuItem::new("/settings".to_string(), "Settings"))
|
||||
.add_item(
|
||||
CustomMenuItem::new("/quit".to_string(), "Quit Firezone").accelerator("Ctrl+Q"),
|
||||
)
|
||||
}
|
||||
}
|
||||
47
rust/windows-client/src-tauri/tauri.conf.json
Executable file
47
rust/windows-client/src-tauri/tauri.conf.json
Executable file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"build": {
|
||||
"beforeDevCommand": "",
|
||||
"beforeBuildCommand": "",
|
||||
"devPath": "../src",
|
||||
"distDir": "../src",
|
||||
"withGlobalTauri": true
|
||||
},
|
||||
"package": {
|
||||
"productName": "firezone-windows-client",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
"all": false,
|
||||
"shell": {
|
||||
"all": false,
|
||||
"open": true
|
||||
}
|
||||
},
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"targets": "all",
|
||||
"identifier": "dev.firezone",
|
||||
"icon": [
|
||||
"icons/firezone.ico"
|
||||
]
|
||||
},
|
||||
"security": {
|
||||
"csp": null
|
||||
},
|
||||
"systemTray": {
|
||||
"iconPath": "icons/firezone.ico",
|
||||
"iconAsTemplate": true
|
||||
},
|
||||
"windows": [
|
||||
{
|
||||
"fullscreen": false,
|
||||
"resizable": true,
|
||||
"label": "main-window",
|
||||
"title": "firezone-windows-client",
|
||||
"width": 640,
|
||||
"height": 480
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
42
rust/windows-client/src/index.html
Executable file
42
rust/windows-client/src/index.html
Executable file
@@ -0,0 +1,42 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Tauri App</title>
|
||||
<script type="module" src="/main.js" defer></script>
|
||||
<style>
|
||||
.logo.vanilla:hover {
|
||||
filter: drop-shadow(0 0 2em #ffe21c);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Welcome to Firezone!</h1>
|
||||
|
||||
<div class="row">
|
||||
<a href="https://www.firezone.dev/?utm_source=windows-client" target="_blank">
|
||||
Tauri logo
|
||||
</a>
|
||||
<a
|
||||
href="https://developer.mozilla.org/en-US/docs/Web/JavaScript"
|
||||
target="_blank"
|
||||
>
|
||||
JavaScript logo
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<p>Click on the Tauri logo to learn more about Firezone</p>
|
||||
|
||||
<form class="row" id="greet-form">
|
||||
<input id="greet-input" placeholder="Enter a name..." />
|
||||
<button type="submit">Greet</button>
|
||||
</form>
|
||||
|
||||
<p id="greet-msg"></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
18
rust/windows-client/src/main.js
Executable file
18
rust/windows-client/src/main.js
Executable file
@@ -0,0 +1,18 @@
|
||||
const { invoke } = window.__TAURI__.tauri;
|
||||
|
||||
let greetInputEl;
|
||||
let greetMsgEl;
|
||||
|
||||
async function greet() {
|
||||
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
|
||||
greetMsgEl.textContent = await invoke("greet", { name: greetInputEl.value });
|
||||
}
|
||||
|
||||
window.addEventListener("DOMContentLoaded", () => {
|
||||
greetInputEl = document.querySelector("#greet-input");
|
||||
greetMsgEl = document.querySelector("#greet-msg");
|
||||
document.querySelector("#greet-form").addEventListener("submit", (e) => {
|
||||
e.preventDefault();
|
||||
greet();
|
||||
});
|
||||
});
|
||||
@@ -1 +0,0 @@
|
||||
fn main() {}
|
||||
109
rust/windows-client/src/styles.css
Executable file
109
rust/windows-client/src/styles.css
Executable file
@@ -0,0 +1,109 @@
|
||||
:root {
|
||||
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
font-weight: 400;
|
||||
|
||||
color: #0f0f0f;
|
||||
background-color: #f6f6f6;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
.container {
|
||||
margin: 0;
|
||||
padding-top: 10vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 6em;
|
||||
padding: 1.5em;
|
||||
will-change: filter;
|
||||
transition: 0.75s;
|
||||
}
|
||||
|
||||
.logo.tauri:hover {
|
||||
filter: drop-shadow(0 0 2em #24c8db);
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
color: #646cff;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #535bf2;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
input,
|
||||
button {
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
padding: 0.6em 1.2em;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
font-family: inherit;
|
||||
color: #0f0f0f;
|
||||
background-color: #ffffff;
|
||||
transition: border-color 0.25s;
|
||||
box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
button {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #396cd8;
|
||||
}
|
||||
button:active {
|
||||
border-color: #396cd8;
|
||||
background-color: #e8e8e8;
|
||||
}
|
||||
|
||||
input,
|
||||
button {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#greet-input {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
color: #f6f6f6;
|
||||
background-color: #2f2f2f;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #24c8db;
|
||||
}
|
||||
|
||||
input,
|
||||
button {
|
||||
color: #ffffff;
|
||||
background-color: #0f0f0f98;
|
||||
}
|
||||
button:active {
|
||||
background-color: #0f0f0f69;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user