Skip to content

Commit

Permalink
feat(rust): added ockam:// scheme association in app for linux and mac
Browse files Browse the repository at this point in the history
  • Loading branch information
davide-baldo committed Aug 18, 2023
1 parent 271fd2a commit b6c897b
Show file tree
Hide file tree
Showing 10 changed files with 228 additions and 140 deletions.
233 changes: 102 additions & 131 deletions Cargo.lock

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,8 @@ inherits = "test"
opt-level = 2
[profile.dev.package.adler]
opt-level = 1

[patch.crates-io]
# temporary fork for url scheme - https://github.com/build-trust/ockam/issues/5667
tauri = { git = "https://github.com/build-trust/tauri.git", branch="add-url-scheme" }
tauri-build = { git = "https://github.com/build-trust/tauri.git", branch="add-url-scheme" }
3 changes: 1 addition & 2 deletions implementations/rust/ockam/ockam_app/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,8 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tauri = { version = "2.0.0-alpha.11", features = ["tray-icon"] }
tauri-plugin-log = "2.0.0-alpha.1"
tauri-plugin-positioner = { version = "2.0.0-alpha.1", features = ["tray-icon"]}
tauri-plugin-positioner = { version = "2.0.0-alpha.1", features = ["tray-icon"] }
tauri-plugin-window = "2.0.0-alpha.1"
tauri-runtime = "1.0.0-alpha.0"
thiserror = "1.0.40"
tokio = { version = "1.30.0", features = ["time"] }
tracing = "0.1"
Expand Down
1 change: 1 addition & 0 deletions implementations/rust/ockam/ockam_app/src/app/events.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub const SYSTEM_TRAY_ON_UPDATE: &str = "app/system_tray/on_update";
pub const URL_OPEN: &str = "app/url/open";
7 changes: 6 additions & 1 deletion implementations/rust/ockam/ockam_app/src/app/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use log::debug;
use std::error::Error;

use tauri::tray::TrayIconBuilder;
Expand Down Expand Up @@ -40,8 +41,12 @@ pub fn setup_app<R: Runtime>(app: &mut App<R>) -> Result<(), Box<dyn Error>> {
app_handle
.tray()
.unwrap()
.set_menu(Some(build_tray_menu(&app_handle).await.clone()))
.set_menu(Some(build_tray_menu(&app_handle).await))
});
});

app.listen_global(events::URL_OPEN, move |event| {
debug!("URL_OPEN event received: {}", event.payload().unwrap_or(""));
});
Ok(())
}
6 changes: 6 additions & 0 deletions implementations/rust/ockam/ockam_app/src/app/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ use tauri::{AppHandle, Manager, RunEvent, Wry};
/// This is the function dispatching application events
pub fn process_application_event(app: &AppHandle<Wry>, event: RunEvent) {
match event {
#[cfg(any(target_os = "macos", target_os = "ios"))]
RunEvent::Opened { urls } => {
urls.into_iter().for_each(|url| {
app.trigger_global(crate::app::events::URL_OPEN, Some(url.into()));
});
}
RunEvent::ExitRequested { api, .. } => {
api.prevent_exit();
}
Expand Down
5 changes: 1 addition & 4 deletions implementations/rust/ockam/ockam_app/src/enroll/tray_menu.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
use crate::app::AppState;
use crate::enroll::enroll_user::enroll_user;
use tauri::menu::{IconMenuItem, MenuBuilder, MenuItem, NativeIcon};
use tauri::{AppHandle, Manager, Runtime, State};
#[cfg(target_os = "macos")]
use tauri_runtime::menu::NativeImage;

use crate::enroll::enroll_user::enroll_user;

pub const ENROLL_MENU_HEADER_ID: &str = "enroll-header";
pub const ENROLL_MENU_ID: &str = "enroll";
Expand Down
29 changes: 29 additions & 0 deletions implementations/rust/ockam/ockam_app/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ mod enroll;
mod error;
#[cfg(feature = "invitations")]
mod invitations;
#[cfg(target_os = "linux")]
mod linux_url_plugin;
mod options;
mod platform;
#[cfg(feature = "invitations")]
Expand All @@ -15,6 +17,29 @@ mod shared_service;

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
//On linux only, to handle ockam:// link argument from args we check if
//the app is already running, send a packet to it via unix socket.
//Using unix socket rather than ockam, to fully separate concerns.
#[cfg(target_os = "linux")]
{
use std::io::Write;
use std::os::unix::net::UnixStream;

let mut args = std::env::args();
args.next(); //skip the first argument which is the executable name
let args: Vec<String> = args.collect();

//if we can connect to the socket then the app is already running
//if it's not running yet the arguments will be checked upon startup
if !args.is_empty() && args[0].starts_with("ockam:") {
if let Ok(mut stream) = UnixStream::connect(linux_url_plugin::open_url_sock_path()) {
stream.write_all(args[0].as_bytes()).unwrap();
stream.flush().unwrap();
return;
}
}
}

// For now, the application only consists of a system tray with several menu items
#[cfg_attr(not(feature = "invitations"), allow(unused_mut))]
let mut builder = tauri::Builder::default()
Expand All @@ -29,6 +54,10 @@ pub fn run() {
{
builder = builder.plugin(projects::plugin::init());
builder = builder.plugin(invitations::plugin::init());
#[cfg(target_os = "linux")]
{
builder = builder.plugin(linux_url_plugin::init());
}
}

let mut app = builder
Expand Down
69 changes: 69 additions & 0 deletions implementations/rust/ockam/ockam_app/src/linux_url_plugin.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use log::{info, warn};
use std::os::unix::fs::PermissionsExt;
use std::time::Duration;

use tauri::{
async_runtime::spawn,
plugin::{Builder, TauriPlugin},
Manager, Runtime,
};
use tokio::io::AsyncReadExt;
use tokio::net::UnixListener;
use tokio::time::sleep;

pub(crate) fn open_url_sock_path() -> String {
let runtime_directory = std::env::var("XDG_RUNTIME_DIR").unwrap_or("/tmp".to_string());
format!("{runtime_directory}/ockam-open-url-sock")
}
const ONLY_WRITE_FROM_USER_PERMISSIONS: u32 = 0o200;

pub(crate) fn init<R: Runtime>() -> TauriPlugin<R> {
Builder::new("linux-url")
.setup(|app, _api| {
let handle = app.clone();
spawn(async move {
let sock_path = &open_url_sock_path();
//bind fails if the file already exists
let _ = std::fs::remove_file(sock_path);
let listener = UnixListener::bind(sock_path)
.unwrap_or_else(|_| panic!("cannot listener on {sock_path}"));
//only allow the current user to write to the socket
std::fs::set_permissions(
sock_path,
std::fs::Permissions::from_mode(ONLY_WRITE_FROM_USER_PERMISSIONS),
)
.unwrap_or_else(|_| panic!("cannot set permissions on {sock_path}"));

//wait a bit to let the app start
sleep(Duration::from_millis(250)).await;

//check if we had an ockam:// argument passed to us
if let Some(url) = std::env::args().nth(1) {
if url.starts_with("ockam:") {
info!("received url: {}", url);
handle.trigger_global(crate::app::events::URL_OPEN, Some(url));
} else {
warn!("ignored argument: {}", url);
}
}

while let Ok((mut stream, _)) = listener.accept().await {
let mut buffer = [0; 4096];
if let Ok(read_bytes) = stream.read(&mut buffer).await {
if let Ok(url) = String::from_utf8(buffer[..read_bytes].to_vec()) {
if url.starts_with("ockam:") {
info!("received url: {}", url);
handle.trigger_global(crate::app::events::URL_OPEN, Some(url));
} else {
warn!("ignored url: {}", url);
}
}
}
//every connection is used only once
drop(stream);
}
});
Ok(())
})
.build()
}
10 changes: 8 additions & 2 deletions implementations/rust/ockam/ockam_app/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"version": "0.1.0"
},
"tauri": {
"tray-icon": {
"trayIcon": {
"iconPath": "icons/icon.png",
"iconAsTemplate": true
},
Expand All @@ -25,8 +25,14 @@
"category": "DeveloperTool",
"copyright": "",
"deb": {
"desktopTemplate": "packaging/linux/application-description-template"
"depends": []
},
"schemeAssociations": [
{
"scheme": ["ockam"],
"role": "Editor"
}
],
"externalBin": [],
"icon": [
"icons/32x32.png",
Expand Down

0 comments on commit b6c897b

Please sign in to comment.