add unix listener, split win/unix into separate submodules
This commit is contained in:
parent
4b06dce7f4
commit
d4fa8966b2
3
.gitignore
vendored
3
.gitignore
vendored
@ -2,6 +2,9 @@ dist
|
||||
**/node_modules
|
||||
src-tauri/target/
|
||||
**/creddy.db
|
||||
# .env is system-specific
|
||||
.env
|
||||
.vscode
|
||||
|
||||
# just in case
|
||||
credentials*
|
||||
|
@ -1 +0,0 @@
|
||||
DATABASE_URL=sqlite://C:/Users/Joe/AppData/Roaming/creddy/creddy.dev.db
|
@ -1,5 +1,6 @@
|
||||
use std::ffi::OsString;
|
||||
use std::process::Command as ChildCommand;
|
||||
#[cfg(windows)]
|
||||
use std::time::Duration;
|
||||
|
||||
use clap::{
|
||||
@ -19,7 +20,6 @@ use crate::shortcuts::ShortcutAction;
|
||||
#[cfg(unix)]
|
||||
use {
|
||||
std::os::unix::process::CommandExt,
|
||||
std::path::Path,
|
||||
tokio::net::UnixStream,
|
||||
};
|
||||
|
||||
@ -199,7 +199,5 @@ async fn connect() -> Result<NamedPipeClient, std::io::Error> {
|
||||
|
||||
#[cfg(unix)]
|
||||
async fn connect() -> Result<UnixStream, std::io::Error> {
|
||||
let path = Path::from("/tmp/creddy-requests");
|
||||
std::fs::remove_file(path)?;
|
||||
UnixStream::connect(path)
|
||||
UnixStream::connect("/tmp/creddy.sock").await
|
||||
}
|
||||
|
@ -2,19 +2,6 @@ use std::path::{Path, PathBuf};
|
||||
|
||||
use sysinfo::{System, SystemExt, Pid, PidExt, ProcessExt};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use std::os::windows::io::AsRawHandle;
|
||||
|
||||
#[cfg(windows)]
|
||||
use {
|
||||
tokio::net::windows::named_pipe::NamedPipeServer,
|
||||
windows::Win32::{
|
||||
Foundation::HANDLE,
|
||||
System::Pipes::GetNamedPipeClientProcessId,
|
||||
},
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
use tokio::net::UnixStream;
|
||||
|
||||
use crate::errors::*;
|
||||
|
||||
@ -26,25 +13,8 @@ pub struct Client {
|
||||
}
|
||||
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn get_client_parent(stream: &UnixStream) -> Result<Client, ClientInfoError> {
|
||||
let pid = stream.peer_cred()?;
|
||||
get_process_parent_info(pid)?
|
||||
}
|
||||
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn get_client_parent(stream: &NamedPipeServer) -> Result<Client, ClientInfoError> {
|
||||
let raw_handle = stream.as_raw_handle();
|
||||
let mut pid = 0u32;
|
||||
let handle = HANDLE(raw_handle as _);
|
||||
unsafe { GetNamedPipeClientProcessId(handle, &mut pid as *mut u32)? };
|
||||
|
||||
get_process_parent_info(pid)
|
||||
}
|
||||
|
||||
|
||||
fn get_process_parent_info(pid: u32) -> Result<Client, ClientInfoError> {
|
||||
pub fn get_process_parent_info(pid: u32) -> Result<Client, ClientInfoError> {
|
||||
dbg!(pid);
|
||||
let sys_pid = Pid::from_u32(pid);
|
||||
let mut sys = System::new();
|
||||
sys.refresh_process(sys_pid);
|
||||
|
@ -4,11 +4,6 @@ use auto_launch::AutoLaunchBuilder;
|
||||
use is_terminal::IsTerminal;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use sqlx::SqlitePool;
|
||||
use tauri::{
|
||||
Manager,
|
||||
GlobalShortcutManager,
|
||||
async_runtime as rt,
|
||||
};
|
||||
|
||||
use crate::errors::*;
|
||||
|
||||
@ -183,43 +178,6 @@ fn default_hotkey_config() -> HotkeysConfig {
|
||||
}
|
||||
}
|
||||
|
||||
// note: will panic if called before APP is set
|
||||
pub fn register_hotkeys(hotkeys: &HotkeysConfig) -> tauri::Result<()> {
|
||||
let app = crate::app::APP.get().unwrap();
|
||||
|
||||
let mut manager = app.global_shortcut_manager();
|
||||
manager.unregister_all()?;
|
||||
|
||||
if hotkeys.show_window.enabled {
|
||||
let handle = app.app_handle();
|
||||
manager.register(
|
||||
&hotkeys.show_window.keys,
|
||||
move || {
|
||||
handle.get_window("main")
|
||||
.map(|w| w.show().error_popup("Failed to show"))
|
||||
.ok_or(HandlerError::NoMainWindow)
|
||||
.error_popup("No main window");
|
||||
},
|
||||
)?;
|
||||
}
|
||||
|
||||
if hotkeys.launch_terminal.enabled {
|
||||
// register() doesn't take an async fn, so we have to use spawn
|
||||
manager.register(
|
||||
&hotkeys.launch_terminal.keys,
|
||||
|| {
|
||||
rt::spawn(async {
|
||||
crate::terminal::launch(false)
|
||||
.await
|
||||
.error_popup("Failed to launch");
|
||||
});
|
||||
}
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
fn default_rehide_ms() -> u64 { 1000 }
|
||||
// start minimized and on login only in production mode
|
||||
|
@ -244,6 +244,7 @@ pub enum ClientInfoError {
|
||||
ParentPidNotFound,
|
||||
#[error("Found PID for parent process of client, but no corresponding process")]
|
||||
ParentProcessNotFound,
|
||||
#[cfg(windows)]
|
||||
#[error("Could not determine PID of connected client")]
|
||||
WindowsError(#[from] windows::core::Error),
|
||||
#[error(transparent)]
|
||||
|
@ -1,18 +1,9 @@
|
||||
#[cfg(windows)]
|
||||
use tokio::net::windows::named_pipe::{
|
||||
NamedPipeServer,
|
||||
ServerOptions,
|
||||
};
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::sync::oneshot;
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use tauri::{
|
||||
AppHandle,
|
||||
Manager,
|
||||
async_runtime as rt,
|
||||
};
|
||||
use tauri::{AppHandle, Manager};
|
||||
|
||||
use crate::errors::*;
|
||||
use crate::clientinfo::{self, Client};
|
||||
@ -21,6 +12,20 @@ use crate::ipc::{Approval, AwsRequestNotification};
|
||||
use crate::state::AppState;
|
||||
use crate::shortcuts::{self, ShortcutAction};
|
||||
|
||||
#[cfg(windows)]
|
||||
mod server_win;
|
||||
#[cfg(windows)]
|
||||
pub use server_win::Server;
|
||||
#[cfg(windows)]
|
||||
use server_win::Stream;
|
||||
|
||||
#[cfg(unix)]
|
||||
mod server_unix;
|
||||
#[cfg(unix)]
|
||||
pub use server_unix::Server;
|
||||
#[cfg(unix)]
|
||||
use server_unix::Stream;
|
||||
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub enum Request {
|
||||
@ -38,53 +43,8 @@ pub enum Response {
|
||||
}
|
||||
|
||||
|
||||
pub struct Server {
|
||||
listener: tokio::net::windows::named_pipe::NamedPipeServer,
|
||||
app_handle: AppHandle,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
pub fn start(app_handle: AppHandle) -> std::io::Result<()> {
|
||||
let listener = ServerOptions::new()
|
||||
.first_pipe_instance(true)
|
||||
.create(r"\\.\pipe\creddy-requests")?;
|
||||
|
||||
let srv = Server {listener, app_handle};
|
||||
rt::spawn(srv.serve());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn serve(mut self) {
|
||||
loop {
|
||||
if let Err(e) = self.try_serve().await {
|
||||
eprintln!("Error accepting connection: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn try_serve(&mut self) -> std::io::Result<()> {
|
||||
// connect() just waits for a client to connect, it doesn't return anything
|
||||
self.listener.connect().await?;
|
||||
|
||||
// create a new pipe instance to listen for the next client, and swap it in
|
||||
let new_listener = ServerOptions::new().create(r"\\.\pipe\creddy-requests")?;
|
||||
let mut stream = std::mem::replace(&mut self.listener, new_listener);
|
||||
let new_handle = self.app_handle.app_handle();
|
||||
rt::spawn(async move {
|
||||
let res = serde_json::to_string(
|
||||
&handle(&mut stream, new_handle).await
|
||||
).unwrap();
|
||||
if let Err(e) = stream.write_all(res.as_bytes()).await {
|
||||
eprintln!("Error responding to request: {e}");
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async fn handle(stream: &mut NamedPipeServer, app_handle: AppHandle) -> Result<Response, HandlerError> {
|
||||
async fn handle(mut stream: Stream, app_handle: AppHandle, client_pid: u32) -> Result<(), HandlerError>
|
||||
{
|
||||
// read from stream until delimiter is reached
|
||||
let mut buf: Vec<u8> = Vec::with_capacity(1024); // requests are small, 1KiB is more than enough
|
||||
let mut n = 0;
|
||||
@ -98,13 +58,17 @@ async fn handle(stream: &mut NamedPipeServer, app_handle: AppHandle) -> Result<R
|
||||
}
|
||||
}
|
||||
|
||||
let client = clientinfo::get_client_parent(&stream)?;
|
||||
let client = clientinfo::get_process_parent_info(client_pid)?;
|
||||
|
||||
let req: Request = serde_json::from_slice(&buf)?;
|
||||
match req {
|
||||
let res = match req {
|
||||
Request::GetAwsCredentials{ base } => get_aws_credentials(base, client, app_handle).await,
|
||||
Request::InvokeShortcut(action) => invoke_shortcut(action).await,
|
||||
}
|
||||
};
|
||||
|
||||
let res = serde_json::to_vec(&res).unwrap();
|
||||
stream.write_all(&res).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
59
src-tauri/src/server/server_unix.rs
Normal file
59
src-tauri/src/server/server_unix.rs
Normal file
@ -0,0 +1,59 @@
|
||||
use std::io::ErrorKind;
|
||||
use tokio::net::{UnixListener, UnixStream};
|
||||
use tauri::{
|
||||
AppHandle,
|
||||
Manager,
|
||||
async_runtime as rt,
|
||||
};
|
||||
|
||||
use crate::errors::*;
|
||||
|
||||
|
||||
pub type Stream = UnixStream;
|
||||
|
||||
|
||||
pub struct Server {
|
||||
listener: UnixListener,
|
||||
app_handle: AppHandle,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
pub fn start(app_handle: AppHandle) -> std::io::Result<()> {
|
||||
match std::fs::remove_file("/tmp/creddy.sock") {
|
||||
Ok(_) => (),
|
||||
Err(e) if e.kind() == ErrorKind::NotFound => (),
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
|
||||
let listener = UnixListener::bind("/tmp/creddy.sock")?;
|
||||
let srv = Server { listener, app_handle };
|
||||
rt::spawn(srv.serve());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn serve(self) {
|
||||
loop {
|
||||
self.try_serve()
|
||||
.await
|
||||
.error_print_prefix("Error accepting request: ");
|
||||
}
|
||||
}
|
||||
|
||||
async fn try_serve(&self) -> Result<(), HandlerError> {
|
||||
let (stream, _addr) = self.listener.accept().await?;
|
||||
let new_handle = self.app_handle.app_handle();
|
||||
let client_pid = get_client_pid(&stream)?;
|
||||
rt::spawn(async move {
|
||||
super::handle(stream, new_handle, client_pid)
|
||||
.await
|
||||
.error_print_prefix("Error responding to request: ");
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn get_client_pid(stream: &UnixStream) -> std::io::Result<u32> {
|
||||
let cred = stream.peer_cred()?;
|
||||
Ok(cred.pid().unwrap() as u32)
|
||||
}
|
76
src-tauri/src/server/server_win.rs
Normal file
76
src-tauri/src/server/server_win.rs
Normal file
@ -0,0 +1,76 @@
|
||||
use tokio::{
|
||||
net::windows::named_pipe::{
|
||||
NamedPipeServer,
|
||||
ServerOptions,
|
||||
},
|
||||
sync::oneshot,
|
||||
};
|
||||
|
||||
#[cfg(windows)]
|
||||
use windows::Win32:: {
|
||||
Foundation::HANDLE,
|
||||
System::Pipes::GetNamedPipeClientProcessId,
|
||||
};
|
||||
#[cfg(windows)]
|
||||
use std::os::windows::io::AsRawHandle;
|
||||
|
||||
use tauri::async_runtime as rt;
|
||||
|
||||
use crate::errors::*;
|
||||
|
||||
|
||||
// used by parent module
|
||||
pub type Stream = NamedPipeServer;
|
||||
|
||||
|
||||
pub struct Server {
|
||||
listener: NamedPipeServer,
|
||||
app_handle: AppHandle,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
pub fn start(app_handle: AppHandle) -> std::io::Result<()> {
|
||||
let listener = ServerOptions::new()
|
||||
.first_pipe_instance(true)
|
||||
.create(r"\\.\pipe\creddy-requests")?;
|
||||
|
||||
let srv = Server {listener, app_handle};
|
||||
rt::spawn(srv.serve());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn serve(mut self) {
|
||||
loop {
|
||||
if let Err(e) = self.try_serve().await {
|
||||
eprintln!("Error accepting connection: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn try_serve(&mut self) -> Result<(), HandlerError> {
|
||||
// connect() just waits for a client to connect, it doesn't return anything
|
||||
self.listener.connect().await?;
|
||||
|
||||
// create a new pipe instance to listen for the next client, and swap it in
|
||||
let new_listener = ServerOptions::new().create(r"\\.\pipe\creddy-requests")?;
|
||||
let mut stream = std::mem::replace(&mut self.listener, new_listener);
|
||||
let new_handle = self.app_handle.app_handle();
|
||||
let client_pid = get_client_pid(&stream)?;
|
||||
rt::spawn(async move {
|
||||
super::handle(stream, app_handle)
|
||||
.await
|
||||
.error_print_prefix("Error responding to request: ");
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn get_client_pid(pipe: &NamedPipeServer) -> Result<u32, ClientInfoError> {
|
||||
let raw_handle = pipe.as_raw_handle();
|
||||
let mut pid = 0u32;
|
||||
let handle = HANDLE(raw_handle as _);
|
||||
unsafe { GetNamedPipeClientProcessId(handle, &mut pid as *mut u32)? };
|
||||
pid
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user