Add deep_link package to the source(this package modified for this

program)
This commit is contained in:
iam54r1n4 2023-01-20 15:17:57 -08:00
parent af34cd7eb2
commit fb731a6ba4
4 changed files with 284 additions and 0 deletions

View file

@ -0,0 +1,143 @@
use std::{
fs::{create_dir_all, remove_file, File},
io::{Error, ErrorKind, Read, Result, Write},
os::unix::net::{UnixListener, UnixStream},
process::Command,
};
use dirs_next::data_dir;
use super::ID;
pub async fn register<F,Fut>(scheme: &str, handler: F) -> Result<()>
where
F: FnMut(String) -> Fut + Send + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
listen(handler);
let mut target = data_dir()
.ok_or_else(|| Error::new(ErrorKind::NotFound, "data directory not found."))?
.join("applications");
create_dir_all(&target)?;
let exe = tauri_utils::platform::current_exe()?;
let file_name = format!(
"{}-handler.desktop",
exe.file_name()
.ok_or_else(|| Error::new(
ErrorKind::NotFound,
"Couldn't get file name of curent executable.",
))?
.to_string_lossy()
);
target.push(&file_name);
let mime_types = format!("x-scheme-handler/{};", scheme);
let mut file = File::create(&target)?;
file.write_all(
format!(
include_str!("template.desktop"),
name = ID
.get()
.expect("Called register() before prepare()")
.split('.')
.last()
.unwrap(),
exec = exe.to_string_lossy(),
mime_types = mime_types
)
.as_bytes(),
)?;
target.pop();
Command::new("update-desktop-database")
.arg(target)
.status()?;
Command::new("xdg-mime")
.args(["default", &file_name, scheme])
.status()?;
Ok(())
}
pub fn unregister(_scheme: &str) -> Result<()> {
let mut target =
data_dir().ok_or_else(|| Error::new(ErrorKind::NotFound, "data directory not found."))?;
target.push("applications");
target.push(format!(
"{}-handler.desktop",
tauri_utils::platform::current_exe()?
.file_name()
.ok_or_else(|| Error::new(
ErrorKind::NotFound,
"Couldn't get file name of curent executable.",
))?
.to_string_lossy()
));
remove_file(&target)?;
Ok(())
}
pub fn listen<F: FnMut(String) + Send + 'static>(mut handler: F) {
std::thread::spawn(move || {
let addr = format!(
"/tmp/{}-deep-link.sock",
ID.get().expect("listen() called before prepare()")
);
let listener = UnixListener::bind(addr).expect("Can't create listener");
for stream in listener.incoming() {
match stream {
Ok(mut stream) => {
let mut buffer = String::new();
if let Err(io_err) = stream.read_to_string(&mut buffer) {
log::error!("Error reading incoming connection: {}", io_err.to_string());
};
handler(dbg!(buffer));
}
Err(err) => {
log::error!("Incoming connection failed: {}", err);
continue;
}
}
}
});
}
pub fn prepare(identifier: &str) {
let addr = format!("/tmp/{}-deep-link.sock", identifier);
match UnixStream::connect(&addr) {
Ok(mut stream) => {
if let Err(io_err) =
stream.write_all(std::env::args().nth(1).unwrap_or_default().as_bytes())
{
log::error!(
"Error sending message to primary instance: {}",
io_err.to_string()
);
};
std::process::exit(0);
}
Err(err) => {
log::error!("Error creating socket listener: {}", err.to_string());
if err.kind() == ErrorKind::ConnectionRefused {
let _ = remove_file(&addr);
}
}
};
ID.set(identifier.to_string())
.expect("prepare() called more than once with different identifiers.");
}

View file

@ -0,0 +1,11 @@
pub fn register<F: FnMut(String) + Send + 'static>(
identifier: &str,
scheme: &str,
handler: F,
) -> Result<(), std::io::Error> {
unimplemented!()
}
pub fn unregister(scheme: &str) -> Result<(), std::io::Error> {
unimplemented!()
}

View file

@ -0,0 +1,26 @@
use once_cell::sync::OnceCell;
#[cfg(target_os = "linux")]
mod linux;
#[cfg(target_os = "linux")]
pub use linux::*;
#[cfg(target_os = "windows")]
mod windows;
#[cfg(target_os = "windows")]
pub use windows::*;
#[cfg(target_os = "macos")]
mod macos;
#[cfg(target_os = "macos")]
pub use macos::*;
static ID: OnceCell<String> = OnceCell::new();
/// This function is meant for use-cases where the default [`prepare`] function can't be used.
///
/// # Errors
/// If ID was already set this functions returns an error containing the ID as String.
pub fn set_identifier(identifier: &str) -> Result<(), String> {
ID.set(identifier.to_string())
}

View file

@ -0,0 +1,104 @@
use std::{
io::{BufRead, BufReader, Write},
path::Path, process::Output, future::IntoFuture,
};
use interprocess::local_socket::{LocalSocketListener, LocalSocketStream};
use warp::Future;
use ::futures::executor::block_on;
use winreg::{enums::HKEY_CURRENT_USER, RegKey};
use super::ID;
// Consider adding a function to register without starting the listener.
// Plugin needs linux and macOS support before making decisions.
pub async fn register<F,Fut>(
scheme: &str,
handler: F,
) -> Result<(), std::io::Error>
where
F: FnMut(String) -> Fut + Send + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
listen(handler);
let hkcu = RegKey::predef(HKEY_CURRENT_USER);
let base = Path::new("Software").join("Classes").join(scheme);
let exe = tauri_utils::platform::current_exe()?
.to_string_lossy()
.replace("\\\\?\\", "");
let (key, _) = hkcu.create_subkey(&base)?;
key.set_value(
"",
&format!(
"URL:{}",
ID.get().expect("register() called before prepare()")
),
)?;
key.set_value("URL Protocol", &"")?;
let (icon, _) = hkcu.create_subkey(base.join("DefaultIcon"))?;
icon.set_value("", &format!("{},0", &exe))?;
let (cmd, _) = hkcu.create_subkey(base.join("shell").join("open").join("command"))?;
cmd.set_value("", &format!("{} \"%1\"", &exe))?;
Ok(())
}
pub fn unregister(scheme: &str) -> Result<(), std::io::Error> {
let hkcu = RegKey::predef(HKEY_CURRENT_USER);
let base = Path::new("Software").join("Classes").join(scheme);
hkcu.delete_subkey_all(base)?;
Ok(())
}
pub fn listen<F,Fut>(mut handler: F) -> ()
where
F: FnMut(String) -> Fut + Send + 'static ,
Fut: Future<Output = ()> + Send + 'static,
{
let task_to_do = async move {
let listener =
LocalSocketListener::bind(ID.get().expect("listen() called before prepare()").as_str())
.expect("Can't create listener");
for conn in listener.incoming().filter_map(|c| {
c.map_err(|error| log::error!("Incoming connection failed: {}", error))
.ok()
})
{
let mut conn = BufReader::new(conn);
let mut buffer = String::new();
if let Err(io_err) = conn.read_line(&mut buffer) {
log::error!("Error reading incoming connection: {}", io_err.to_string());
};
buffer.pop();
handler(buffer).await;
}
};
std::thread::spawn(move || block_on(task_to_do));
}
pub fn prepare(identifier: &str) {
if let Ok(mut conn) = LocalSocketStream::connect(identifier) {
if let Err(io_err) = conn.write_all(std::env::args().nth(1).unwrap_or_default().as_bytes())
{
log::error!(
"Error sending message to primary instance: {}",
io_err.to_string()
);
};
let _ = conn.write_all(b"\n");
std::process::exit(0);
};
ID.set(identifier.to_string())
.expect("prepare() called more than once with different identifiers.");
}