Skip to content
86 linesCodeBlameRaw
1//! `g1t://` links. `g1t://acme/-/chat/dm/chn_1` opens that page on the
2//! server: the site, when the window is on it, is told the path and moves
3//! without a reload; otherwise the window loads the page. A link that
4//! started the app is read on the way up; one that arrives while it runs
5//! comes through the deep-link plugin, from a second launch too.
6
7use tauri::{AppHandle, Emitter, Manager};
8use tauri_plugin_deep_link::DeepLinkExt;
9use url::Url;
10
11use crate::{WINDOW, config, tray};
12
13/// What the page listens for (bridge.js).
14pub const EVENT: &str = "g1t-navigate";
15
16pub fn install(app: &AppHandle) {
17 // Installers register the scheme; a build run from the source tree,
18 // and an AppImage, need it done here.
19 #[cfg(any(windows, target_os = "linux"))]
20 let _ = app.deep_link().register_all();
21 let handle = app.clone();
22 app.deep_link().on_open_url(move |event| {
23 for url in event.urls() {
24 open(&handle, &url);
25 }
26 });
27 if let Ok(Some(urls)) = app.deep_link().get_current() {
28 for url in urls {
29 open(app, &url);
30 }
31 }
32}
33
34/// The site path a link names: `g1t://acme/-/chat?x` is `/acme/-/chat?x`.
35pub fn path_of(url: &Url) -> Option<String> {
36 if url.scheme() != "g1t" {
37 return None;
38 }
39 let mut path = match url.host_str() {
40 Some(host) if !host.is_empty() => format!("/{host}{}", url.path()),
41 _ => url.path().to_string(),
42 };
43 if path.is_empty() || !path.starts_with('/') {
44 path.insert(0, '/');
45 }
46 if let Some(query) = url.query() {
47 path.push('?');
48 path.push_str(query);
49 }
50 Some(path)
51}
52
53pub fn open(app: &AppHandle, url: &Url) {
54 if let Some(path) = path_of(url) {
55 go(app, &path);
56 }
57}
58
59/// Takes the window to a path on the server.
60pub fn go(app: &AppHandle, path: &str) {
61 tray::show(app);
62 if config::on_site(app) {
63 let _ = app.emit_to(WINDOW, EVENT, path.to_string());
64 return;
65 }
66 if let Some(window) = app.get_webview_window(WINDOW) {
67 if let Ok(target) = config::server(app).join(path.trim_start_matches('/')) {
68 let _ = window.navigate(target);
69 }
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::path_of;
76 use url::Url;
77
78 #[test]
79 fn a_link_names_a_site_path() {
80 let path = |text: &str| path_of(&Url::parse(text).unwrap());
81 assert_eq!(path("g1t://acme/-/chat/dm/chn_1").as_deref(), Some("/acme/-/chat/dm/chn_1"));
82 assert_eq!(path("g1t://acme/hello/pull/4?tab=files").as_deref(), Some("/acme/hello/pull/4?tab=files"));
83 assert_eq!(path("g1t://notifications").as_deref(), Some("/notifications"));
84 assert_eq!(path("https://g1t.sh/acme"), None);
85 }
86}