keyfork/crates/daemon/keyforkd-client/src/lib.rs

86 lines
2.9 KiB
Rust
Raw Normal View History

use std::{collections::HashMap, os::unix::net::UnixStream, path::PathBuf};
use keyfork_frame::{try_decode_from, try_encode_to, DecodeError, EncodeError};
use keyforkd_models::{Request, Response, Error as KeyforkdError};
#[cfg(test)]
mod tests;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Neither KEYFORK_SOCKET_PATH nor XDG_RUNTIME_DIR were set")]
EnvVarsNotFound,
2024-01-08 19:06:03 +00:00
#[error("Socket was unable to connect to {1}: {0} (make sure keyforkd is running)")]
Connect(std::io::Error, PathBuf),
#[error("Could not write to or from the socket: {0}")]
Io(#[from] std::io::Error),
#[error("Could not perform bincode transformation: {0}")]
Bincode(#[from] Box<bincode::ErrorKind>),
#[error("Could not perform frame transformation: {0}")]
FrameEnc(#[from] EncodeError),
#[error("Could not perform frame transformation: {0}")]
FrameDec(#[from] DecodeError),
#[error("Error in Keyforkd: {0}")]
Keyforkd(#[from] KeyforkdError)
}
pub type Result<T, E = Error> = std::result::Result<T, E>;
pub fn get_socket() -> Result<UnixStream, Error> {
let socket_vars = std::env::vars()
.filter(|(key, _)| ["XDG_RUNTIME_DIR", "KEYFORKD_SOCKET_PATH"].contains(&key.as_str()))
.collect::<HashMap<String, String>>();
let mut socket_path: PathBuf;
#[allow(clippy::single_match_else)]
match socket_vars.get("KEYFORKD_SOCKET_PATH") {
Some(occupied) => {
socket_path = PathBuf::from(occupied);
}
None => {
socket_path = PathBuf::from(
socket_vars
.get("XDG_RUNTIME_DIR")
.ok_or(Error::EnvVarsNotFound)?,
);
socket_path.extend(["keyforkd", "keyforkd.sock"]);
}
}
UnixStream::connect(&socket_path).map_err(|e| Error::Connect(e, socket_path))
}
/// A client to interact with Keyforkd.
///
/// Upon creation, a socket is opened, and is kept open for the duration of the object's lifetime.
/// Currently, Keyforkd does not support the reuse of sockets. Attempting to reuse the socket after
/// previously using it will likely result in an error.
#[derive(Debug)]
pub struct Client {
socket: UnixStream,
}
impl Client {
/// Create a new client from a given already-connected [`UnixStream`].
pub fn new(socket: UnixStream) -> Self {
Self { socket }
}
/// Create a new client using well-known socket locations.
pub fn discover_socket() -> Result<Self> {
get_socket().map(|socket| Self { socket })
}
/// Serialize and send a [`Request`] to the server, awaiting a [`Result<Response>`].
pub fn request(&mut self, req: &Request) -> Result<Response> {
try_encode_to(&bincode::serialize(&req)?, &mut self.socket)?;
let resp = try_decode_from(&mut self.socket)?;
let resp: Result<Response, KeyforkdError> = bincode::deserialize(&resp)?;
resp.map_err(From::from)
}
}