Skip to content

Commit

Permalink
System Tray for Desktop Apps / Update depdendencies (#12)
Browse files Browse the repository at this point in the history
* depedency updates

* updated dependencies

* initial system tray

* toggle window: hide or show from system tray

* impl disconnect and quit from tray

* Working System Tray

* updates form macOS

* cmd+q and cmd+w works on macOS
  • Loading branch information
64bit committed Dec 3, 2023
1 parent 6720217 commit ec363af
Show file tree
Hide file tree
Showing 18 changed files with 777 additions and 390 deletions.
781 changes: 519 additions & 262 deletions Cargo.lock

Large diffs are not rendered by default.

18 changes: 9 additions & 9 deletions upvpn-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ name = "upvpn"
path = "src/main.rs"

[dependencies]
async-trait = "0.1.68"
clap = { version = "4.2.3", features = ["derive"] }
tokio = { version = "1.27.0", features = ["rt-multi-thread", "macros", "signal"] }
validator = { version = "0.16.0", features = ["derive"] }
async-trait = "0.1.74"
clap = { version = "4.4", features = ["derive"] }
tokio = { version = "1.34", features = ["rt-multi-thread", "macros", "signal"] }
validator = { version = "0.16.1", features = ["derive"] }
upvpn-controller = {path = "../upvpn-controller"}
upvpn-types = {path = "../upvpn-types"}
thiserror = "1.0.40"
thiserror = "1.0"
tonic = "0.9.2"
dialoguer = { version = "0.10.4", features = ["fuzzy-select"] }
indicatif = "0.17.3"
tokio-stream = { version = "0.1.12", features = ["sync"] }
console = "0.15.5"
dialoguer = { version = "0.11.0", features = ["fuzzy-select"] }
indicatif = "0.17.7"
tokio-stream = { version = "0.1.14", features = ["sync"] }
console = "0.15.7"
2 changes: 1 addition & 1 deletion upvpn-cli/src/commands/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub enum CliError {
#[error("{}", .0.message())]
Grpc(#[from] Status),
#[error("{0}")]
Io(#[from] std::io::Error),
Io(#[from] dialoguer::Error),
#[error("{0}")]
InvalidArgument(String),
}
14 changes: 7 additions & 7 deletions upvpn-config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ homepage = "https://upvpn.app"
repository = "https://github.com/upvpn/upvpn-app"

[dependencies]
figment = { version = "0.10.8", features = ["env", "toml"] }
once_cell = "1.17.1"
serde = { version = "1.0.160", features = ["derive"] }
thiserror = "1.0.40"
tokio = { version = "1.27.0", features = ["fs"] }
figment = { version = "0.10.12", features = ["env", "toml"] }
once_cell = "1.18.0"
serde = { version = "1.0", features = ["derive"] }
thiserror = "1.0"
tokio = { version = "1.34", features = ["fs"] }

[build-dependencies]
toml = "0.7.3"
serde = "1.0.160"
toml = "0.8.8"
serde = "1.0"
10 changes: 5 additions & 5 deletions upvpn-controller/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ homepage = "https://upvpn.app"
repository = "https://github.com/upvpn/upvpn-app"

[dependencies]
futures = "0.3.28"
hyper = "0.14.26"
futures = "0.3.29"
hyper = "0.14.27"
parity-tokio-ipc = "0.9.0"
prost = "0.11.9"
prost-types = "0.11.9"
thiserror = "1.0.40"
tokio = "1.27.0"
thiserror = "1.0"
tokio = "1.34"
tonic = "0.9.2"
tower = "0.4.13"
upvpn-config = { path = "../upvpn-config" }
upvpn-types = {path = "../upvpn-types"} # grpc types to upvpn-types conversions
chrono = { version = "0.4.24", features = ["serde"] }
chrono = { version = "0.4.31", features = ["serde"] }

[build-dependencies]
tonic-build = "0.9.2"
20 changes: 10 additions & 10 deletions upvpn-daemon/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,26 @@ homepage = "https://upvpn.app"
repository = "https://github.com/upvpn/upvpn-app"

[dependencies]
clap = "4.2.7"
async-trait = "0.1.68"
futures = "0.3.28"
hyper = "0.14.26"
thiserror = "1.0.40"
tokio = { version = "1.27.0", features = ["rt-multi-thread", "signal", "macros", "sync", "fs"] }
clap = "4.4.10"
async-trait = "0.1.74"
futures = "0.3.29"
hyper = "0.14.27"
thiserror = "1.0"
tokio = { version = "1.34", features = ["rt-multi-thread", "signal", "macros", "sync", "fs"] }
tokio-stream = { version = "0.1.12", features = ["sync"] }
tonic = "0.9.2"
tower = "0.4.13"
tracing = "0.1.37"
tracing-appender = "0.2.2"
tracing-subscriber = { version = "0.3.16", features = ["default", "env-filter", "tracing-log"] }
tracing = "0.1.40"
tracing-appender = "0.2.3"
tracing-subscriber = { version = "0.3.18", features = ["default", "env-filter", "tracing-log"] }
upvpn-config = {path = "../upvpn-config"}
upvpn-controller = {path = "../upvpn-controller"}
upvpn-server = {path = "../upvpn-server"}
upvpn-types = {path = "../upvpn-types"}
upvpn-entity = {path = "../upvpn-entity"}
upvpn-migration = {path = "../upvpn-migration"}
sea-orm = { version = "0.11.2", features = ["sqlx-sqlite", "runtime-tokio-rustls"] }
chrono = "0.4.24"
chrono = "0.4.31"
talpid-core = {git = "ssh://git@github.com/upvpn/mullvadvpn-app.git", rev = "2023.3.upvpn"}
talpid-types = {git = "ssh://git@github.com/upvpn/mullvadvpn-app.git", rev = "2023.3.upvpn"}
talpid-platform-metadata = {git = "ssh://git@github.com/upvpn/mullvadvpn-app.git", rev = "2023.3.upvpn"}
Expand Down
2 changes: 1 addition & 1 deletion upvpn-entity/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ features = [
[dependencies]
upvpn-types = {path = "../upvpn-types"}
uuid = { version = "1.3.1", features = ["v4", "serde"] }
serde_json = "1.0.96"
serde_json = "1.0"
12 changes: 6 additions & 6 deletions upvpn-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ homepage = "https://upvpn.app"
repository = "https://github.com/upvpn/upvpn-app"

[dependencies]
futures = "0.3.28"
hyper = "0.14.26"
futures = "0.3.29"
hyper = "0.14.27"
prost = "0.11.9"
serde = { version = "1.0.160", features = ["derive"] }
thiserror = "1.0.40"
serde = { version = "1.0", features = ["derive"] }
thiserror = "1.0"
# todo: handle certs: remove dependency on tls-roots
tonic = { version = "0.9.2", features = ["tls", "tls-roots"] }
tower = "0.4.13"
Expand All @@ -22,12 +22,12 @@ upvpn-types = {path = "../upvpn-types"}
talpid-types = {git = "ssh://git@github.com/upvpn/mullvadvpn-app.git", rev = "2023.3.upvpn"}
uuid = { version = "1.3.1", features = ["serde", "v4"] }
# todo: use rustls? instead of OS TLS
reqwest = { version = "0.11.16", features = ["json"] }
reqwest = { version = "0.11.22", features = ["json"] }
ipnetwork = "0.20.0"
backoff = { version = "0.4.0", features = ["tokio"] }

[build-dependencies]
tonic-build = "0.9.2"

[dev-dependencies]
tokio = "1.27.0"
tokio = "1.34"
10 changes: 5 additions & 5 deletions upvpn-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ homepage = "https://upvpn.app"
repository = "https://github.com/upvpn/upvpn-app"

[dependencies]
tokio = "1.27.0"
tokio = "1.34"
upvpn-config = {path="../upvpn-config"}
talpid-types = {git = "ssh://git@github.com/upvpn/mullvadvpn-app.git", rev = "2023.3.upvpn"}
serde = { version = "1.0.160", features = ["derive"] }
serde = { version = "1.0", features = ["derive"] }
ipnetwork = "0.20.0"
chrono = { version = "0.4.24", features = ["serde"] }
chrono = { version = "0.4.31", features = ["serde"] }
uuid = { version = "1.3.1", features = ["serde", "v4"] }
thiserror = "1.0.40"
serde_yaml = "0.9.21"
thiserror = "1.0"
serde_yaml = "0.9"
ts-rs = { git = "https://github.com/Aleph-Alpha/ts-rs", rev = "b4ba8b81fd8833296e99285eae7608864c52e51e", features = ["serde-compat", "chrono-impl", "uuid-impl", "format"] }

14 changes: 7 additions & 7 deletions upvpn-ui/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,24 @@ homepage = "https://upvpn.app"
repository = "https://github.com/upvpn/upvpn-app"

[build-dependencies]
tauri-build = { version = "1.2", features = [] }
tauri-build = { version = "1.5.0", features = [] }

[dependencies]
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
tauri = { version = "1.3.0", features = ["clipboard-all", "fs-all", "notification-all", "os-all", "shell-open", "window-all"] }
tauri = { version = "1.5.3", features = ["clipboard-all", "fs-all", "notification-all", "os-all", "shell-open", "system-tray", "window-all"] }
upvpn-controller = {path = "../../upvpn-controller"}
upvpn-types = {path = "../../upvpn-types"}
upvpn-config = {path = "../../upvpn-config"}
tokio-stream = "0.1.12"
tokio-stream = "0.1.14"
tauri-plugin-log = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "dev" }
tauri-plugin-single-instance = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "dev" }
log = "^0.4"
tokio = { version = "1.27.0", features = ["time"] }
futures = "0.3.28"
thiserror = "1.0.40"
tokio = { version = "1.34", features = ["time"] }
futures = "0.3.29"
thiserror = "1.0"
tonic = "0.9.2"
semver = "1.0.17"
semver = "1.0.20"

[features]
# by default Tauri runs in production mode
Expand Down
11 changes: 8 additions & 3 deletions upvpn-ui/src-tauri/src/commands/vpn_session.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use tauri::AppHandle;
use upvpn_types::{location::Location, vpn_session::VpnStatus};

use crate::error::Error;
use crate::{error::Error, state::update_app_state};

#[tauri::command]
pub async fn connect(location: Location) -> Result<VpnStatus, Error> {
Expand All @@ -25,10 +26,14 @@ pub async fn disconnect() -> Result<VpnStatus, Error> {
}

#[tauri::command]
pub async fn get_vpn_status() -> Result<VpnStatus, Error> {
pub async fn get_vpn_status(app_handle: AppHandle) -> Result<VpnStatus, Error> {
let mut client = upvpn_controller::new_grpc_client()
.await
.map_err(|_| Error::DaemonIsOffline)?;

Ok(client.get_vpn_status(()).await?.into_inner().into())
let vpn_status: VpnStatus = client.get_vpn_status(()).await?.into_inner().into();

update_app_state(app_handle, vpn_status.clone()).await;

Ok(vpn_status)
}
3 changes: 3 additions & 0 deletions upvpn-ui/src-tauri/src/event_forwarder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use tokio::sync::oneshot;
use tokio_stream::StreamExt;
use upvpn_types::notification::Notification;

use crate::state::update_app_state;

#[derive(Debug)]
pub struct EventForwarderHandler {
_shutdown_tx: oneshot::Sender<()>,
Expand Down Expand Up @@ -49,6 +51,7 @@ impl EventForwarder {
match event {
upvpn_controller::proto::daemon_event::Event::VpnStatus(vpn_status) => {
let vpn_status: upvpn_types::vpn_session::VpnStatus = vpn_status.into();
update_app_state(app_handle.clone(), vpn_status.clone()).await;
let _ = app_handle.emit_all("vpn_status", vpn_status);
},
upvpn_controller::proto::daemon_event::Event::Notification(notification) => {
Expand Down
31 changes: 29 additions & 2 deletions upvpn-ui/src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ mod commands;
mod error;
mod event_forwarder;
mod state;
mod system_tray;

use commands::auth::{is_signed_in, sign_in, sign_out};
use commands::desktop_notification::send_desktop_notification;
Expand All @@ -17,6 +18,8 @@ use commands::version::{current_app_version, update_available};
use commands::vpn_session::{connect, disconnect, get_vpn_status};
use log::LevelFilter;
use state::AppState;
use system_tray::{create_default_system_tray, handle_system_tray_event, toggle_window_visibility};
use tauri::Manager;
use tauri_plugin_log::LogTarget;
use upvpn_config::config;

Expand All @@ -32,18 +35,22 @@ fn main() {

#[cfg(target_os = "macos")]
{
use tauri::CustomMenuItem;
use tauri::Menu;
use tauri::MenuItem;
use tauri::Submenu;

let quit_item = CustomMenuItem::new("macos_quit", "Quit").accelerator("Cmd+Q");
let menu = Menu::new().add_submenu(Submenu::new(
"upvpn",
"UpVPN",
Menu::new()
.add_native_item(MenuItem::Copy)
.add_native_item(MenuItem::Paste)
.add_native_item(MenuItem::SelectAll)
.add_native_item(MenuItem::Cut)
.add_native_item(MenuItem::Separator)
.add_native_item(MenuItem::CloseWindow),
.add_native_item(MenuItem::CloseWindow)
.add_item(quit_item),
));
builder = builder.menu(menu);
}
Expand Down Expand Up @@ -76,6 +83,26 @@ fn main() {
.build(),
)
.plugin(tauri_plugin_single_instance::init(|_, _, _| {}))
.system_tray(create_default_system_tray())
.on_system_tray_event(handle_system_tray_event)
.on_window_event(|event| {
match event.event() {
// Run frontend in the background
tauri::WindowEvent::CloseRequested { api, .. } => {
api.prevent_close();
let app_handle = event.window().app_handle();
toggle_window_visibility(app_handle);
}
_ => {}
}
})
.on_menu_event(|event| match event.menu_item_id() {
"macos_quit" => {
let _ = tauri::async_runtime::block_on(commands::vpn_session::disconnect());
event.window().app_handle().exit(0);
}
_ => {}
})
.setup(|_app| Ok(()))
.run(tauri::generate_context!())
.expect("error while running tauri application");
Expand Down
34 changes: 30 additions & 4 deletions upvpn-ui/src-tauri/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
use std::sync::Arc;

use tauri::AppHandle;
use upvpn_types::location::Location;
use tauri::{AppHandle, Manager};
use upvpn_types::{location::Location, vpn_session::VpnStatus};

use crate::event_forwarder::EventForwarderHandler;
use crate::{event_forwarder::EventForwarderHandler, system_tray::update_system_tray};

pub type AppState = Arc<tokio::sync::Mutex<UiState>>;

#[derive(Debug, Default)]
#[derive(Debug)]
pub struct UiState {
pub event_fwd_handler: Option<EventForwarderHandler>,
pub locations: Vec<Location>,
pub vpn_status: Option<VpnStatus>,
pub window_visible: bool,
}

impl Default for UiState {
fn default() -> Self {
Self {
event_fwd_handler: Default::default(),
locations: Default::default(),
vpn_status: None,
window_visible: true,
}
}
}

impl UiState {
Expand All @@ -29,3 +42,16 @@ impl UiState {
}
}
}

pub async fn update_app_state(app_handle: AppHandle, vpn_status: VpnStatus) {
{
// block so that guard is dropped, and lock can be taken again
let state: tauri::State<'_, AppState> = app_handle.state();
let new_vpn_status = vpn_status.clone();

let mut state = state.lock().await;
state.vpn_status = Some(new_vpn_status);
}

update_system_tray(app_handle.clone()).await;
}
Loading

0 comments on commit ec363af

Please sign in to comment.