Skip to content

Commit

Permalink
Merge pull request #331 from rkuklik/main
Browse files Browse the repository at this point in the history
Typesafe IPC
  • Loading branch information
LGFae authored Jun 22, 2024
2 parents 1bb137b + 74f5d59 commit 90e205e
Show file tree
Hide file tree
Showing 13 changed files with 664 additions and 517 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
[workspace]
# cargo complains that this defaults to one in virtual package manifests (for some reason)
resolver = "2"
members = ["client", "daemon", "common"]
default-members = ["client", "daemon"]

Expand Down
36 changes: 16 additions & 20 deletions client/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use clap::Parser;
use std::time::Duration;
use std::{path::Path, time::Duration};

use common::{
cache,
ipc::{self, connect_to_socket, get_socket_path, read_socket, Answer, RequestSend},
};
use clap::Parser;
use common::cache;
use common::ipc::{self, Answer, Client, IpcSocket, RequestSend};
use common::mmap::Mmap;

mod imgproc;
use imgproc::*;
Expand All @@ -19,10 +18,10 @@ fn main() -> Result<(), String> {
return cache::clean().map_err(|e| format!("failed to clean the cache: {e}"));
}

let socket = IpcSocket::connect().map_err(|err| err.to_string())?;
loop {
let socket = connect_to_socket(&get_socket_path(), 5, 100)?;
RequestSend::Ping.send(&socket)?;
let bytes = read_socket(&socket)?;
let bytes = socket.recv().map_err(|err| err.to_string())?;
let answer = Answer::receive(bytes);
if let Answer::Ping(configured) = answer {
if configured {
Expand All @@ -42,29 +41,27 @@ fn process_swww_args(args: &Swww) -> Result<(), String> {
Some(request) => request,
None => return Ok(()),
};
let socket = connect_to_socket(&get_socket_path(), 5, 100)?;
let socket = IpcSocket::connect().map_err(|err| err.to_string())?;
request.send(&socket)?;
let bytes = read_socket(&socket)?;
let bytes = socket.recv().map_err(|err| err.to_string())?;
drop(socket);
match Answer::receive(bytes) {
Answer::Err(msg) => return Err(msg.to_string()),
Answer::Info(info) => info.iter().for_each(|i| println!("{}", i)),
Answer::Ok => {
if let Swww::Kill = args {
#[cfg(debug_assertions)]
let tries = 20;
#[cfg(not(debug_assertions))]
let tries = 10;
let socket_path = get_socket_path();
let path = IpcSocket::<Client>::path();
let path = Path::new(path);
for _ in 0..tries {
if !socket_path.exists() {
if !path.exists() {
return Ok(());
}
std::thread::sleep(Duration::from_millis(100));
}
return Err(format!(
"Could not confirm socket deletion at: {socket_path:?}"
));
return Err(format!("Could not confirm socket deletion at: {path:?}"));
}
}
Answer::Ping(_) => {
Expand Down Expand Up @@ -113,7 +110,7 @@ fn make_img_request(
dims: &[(u32, u32)],
pixel_format: ipc::PixelFormat,
outputs: &[Vec<String>],
) -> Result<ipc::Mmap, String> {
) -> Result<Mmap, String> {
let transition = make_transition(img);
let mut img_req_builder = ipc::ImageRequestBuilder::new(transition);

Expand Down Expand Up @@ -214,9 +211,9 @@ fn get_format_dims_and_outputs(
let mut dims: Vec<(u32, u32)> = Vec::new();
let mut imgs: Vec<ipc::BgImg> = Vec::new();

let socket = connect_to_socket(&get_socket_path(), 5, 100)?;
let socket = IpcSocket::connect().map_err(|err| err.to_string())?;
RequestSend::Query.send(&socket)?;
let bytes = read_socket(&socket)?;
let bytes = socket.recv().map_err(|err| err.to_string())?;
drop(socket);
let answer = Answer::receive(bytes);
match answer {
Expand Down Expand Up @@ -249,7 +246,6 @@ fn get_format_dims_and_outputs(
Ok((format, dims, outputs))
}
}
Answer::Err(e) => Err(format!("daemon error when sending query: {e}")),
_ => unreachable!(),
}
}
Expand Down
4 changes: 3 additions & 1 deletion common/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ use std::{
path::{Path, PathBuf},
};

use crate::ipc::{Animation, Mmap, PixelFormat};
use crate::ipc::Animation;
use crate::ipc::PixelFormat;
use crate::mmap::Mmap;

pub(crate) fn store(output_name: &str, img_path: &str) -> io::Result<()> {
let mut filepath = cache_dir()?;
Expand Down
6 changes: 5 additions & 1 deletion common/src/compression/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ use comp::pack_bytes;
use decomp::{unpack_bytes_3channels, unpack_bytes_4channels};
use std::ffi::{c_char, c_int};

use crate::ipc::{ImageRequestBuilder, Mmap, MmappedBytes, PixelFormat};
use crate::ipc::ImageRequestBuilder;
use crate::ipc::PixelFormat;
use crate::mmap::Mmap;
use crate::mmap::MmappedBytes;

mod comp;
mod cpu;
mod decomp;
Expand Down
87 changes: 87 additions & 0 deletions common/src/ipc/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
use std::error::Error;
use std::fmt;

use rustix::io::Errno;

/// Failiures if IPC with added context
#[derive(Debug)]
pub struct IpcError {
err: Errno,
kind: IpcErrorKind,
}

impl IpcError {
pub(crate) fn new(kind: IpcErrorKind, err: Errno) -> Self {
Self { err, kind }
}
}

#[derive(Debug)]
pub enum IpcErrorKind {
/// Failed to create file descriptor
Socket,
/// Failed to connect to socket
Connect,
/// Binding on socket failed
Bind,
/// Listening on socket failed
Listen,
/// Socket file wasn't found
NoSocketFile,
/// Socket timeout couldn't be set
SetTimeout,
/// IPC contained invalid identification code
BadCode,
/// IPC payload was broken
MalformedMsg,
/// Reading socket failed
Read,
}

impl IpcErrorKind {
fn description(&self) -> &'static str {
match self {
Self::Socket => "failed to create socket file descriptor",
Self::Connect => "failed to connect to socket",
Self::Bind => "failed to bind to socket",
Self::Listen => "failed to listen on socket",
Self::NoSocketFile => "Socket file not found. Are you sure swww-daemon is running?",
Self::SetTimeout => "failed to set read timeout for socket",
Self::BadCode => "invalid message code",
Self::MalformedMsg => "malformed ancillary message",
Self::Read => "failed to receive message",
}
}
}

impl fmt::Display for IpcError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.kind.description())
}
}

impl Error for IpcError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
Some(&self.err)
}
}

/// Simplify generating [`IpcError`]s from [`Errno`]
pub(crate) trait ErrnoExt {
type Output;
fn context(self, kind: IpcErrorKind) -> Self::Output;
}

impl ErrnoExt for Errno {
type Output = IpcError;
fn context(self, kind: IpcErrorKind) -> Self::Output {
IpcError::new(kind, self)
}
}

impl<T> ErrnoExt for Result<T, Errno> {
type Output = Result<T, IpcError>;
fn context(self, kind: IpcErrorKind) -> Self::Output {
self.map_err(|error| error.context(kind))
}
}
Loading

0 comments on commit 90e205e

Please sign in to comment.