@@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "ipc"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
rule = { path = "../rule" }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
thiserror = "2"
|
||||
tokio = { version = "1", features = ["net", "io-util"] }
|
||||
@@ -0,0 +1,63 @@
|
||||
use crate::{
|
||||
SOCKET_NAME,
|
||||
repr::{Error, Request, de_reply},
|
||||
};
|
||||
use rule::parser::When;
|
||||
use serde::de::DeserializeOwned;
|
||||
use std::{
|
||||
io::{Read, Write},
|
||||
os::{
|
||||
linux::net::SocketAddrExt,
|
||||
unix::net::{SocketAddr, UnixStream},
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Client {
|
||||
stream: UnixStream,
|
||||
buf: Vec<u8>,
|
||||
}
|
||||
impl Client {
|
||||
pub fn connect() -> std::io::Result<Self> {
|
||||
let addr = SocketAddr::from_abstract_name(SOCKET_NAME)?;
|
||||
Ok(Self {
|
||||
stream: UnixStream::connect_addr(&addr)?,
|
||||
buf: Vec::with_capacity(128),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn send(&mut self, req: &Request) -> std::io::Result<()> {
|
||||
self.buf.clear();
|
||||
serde_json::to_writer(&mut self.buf, req).unwrap();
|
||||
self.stream
|
||||
.write_all(&(self.buf.len() as u16).to_le_bytes())?;
|
||||
self.stream.write_all(&self.buf)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn recv<T: DeserializeOwned>(&mut self) -> std::io::Result<Result<T, Error>> {
|
||||
let mut len = [0u8; size_of::<u16>()];
|
||||
self.stream.read_exact(&mut len)?;
|
||||
let len = u16::from_le_bytes(len);
|
||||
self.buf.resize(len as usize, 0);
|
||||
self.stream.read_exact(&mut self.buf)?;
|
||||
Ok(de_reply(&String::from_utf8_lossy(&self.buf)))
|
||||
}
|
||||
|
||||
pub fn invoke<T: DeserializeOwned>(&mut self, req: &Request) -> Result<T, Error> {
|
||||
self.send(req).map_err(|_| Error::Delivery)?;
|
||||
self.recv().map_err(|_| Error::Delivery).flatten()
|
||||
}
|
||||
|
||||
pub fn trigger(&mut self, set: String, action: String) -> Result<(), Error> {
|
||||
self.invoke(&Request::Trigger(set, action))
|
||||
}
|
||||
|
||||
pub fn reload_rules(&mut self) -> Result<(), Error> {
|
||||
self.invoke(&Request::ReloadRules)
|
||||
}
|
||||
|
||||
pub fn list_devices(&mut self, when: When) -> Result<Vec<String>, Error> {
|
||||
self.invoke(&Request::ListDevices(when))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
pub mod client;
|
||||
pub mod repr;
|
||||
pub mod server;
|
||||
|
||||
pub const SOCKET_NAME: &str = "verified:org.semilabs.os/lxdeviced";
|
||||
@@ -0,0 +1,64 @@
|
||||
use rule::parser::When;
|
||||
use serde::{Deserialize, Serialize, de::DeserializeOwned};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(tag = "method", content = "params")]
|
||||
pub enum Request {
|
||||
#[serde(rename = "/org.semilabs.os/LxDeviced/Trigger@LXDEVICED_0.1.0")]
|
||||
Trigger(String, String),
|
||||
|
||||
#[serde(rename = "/org.semilabs.os/LxDeviced/ReloadRules@LXDEVICED_0.1.0")]
|
||||
ReloadRules,
|
||||
|
||||
#[serde(rename = "/org.semilabs.os/LxDeviced/ListDevices@LXDEVICED_0.1.0")]
|
||||
ListDevices(When),
|
||||
}
|
||||
|
||||
pub fn ser_reply<T: Serialize>(result: Result<T, Error>) -> String {
|
||||
const FALLBACK: &str = r#"{"error": "/AnyCall/BadReply@ANYCALL_LITE_1"}"#;
|
||||
|
||||
let reply = match result {
|
||||
Ok(x) => Reply::Ok(x),
|
||||
Err(e) => Reply::Err(e),
|
||||
};
|
||||
serde_json::to_string(&reply).unwrap_or_else(|_| FALLBACK.into())
|
||||
}
|
||||
|
||||
pub fn de_reply<T: DeserializeOwned>(s: &str) -> Result<T, Error> {
|
||||
let reply: Reply<T> = serde_json::from_str(s).map_err(|_| Error::BadReply)?;
|
||||
match reply {
|
||||
Reply::Ok(x) => Ok(x),
|
||||
Reply::Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum Reply<T> {
|
||||
Err(Error),
|
||||
Ok(T),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, thiserror::Error)]
|
||||
#[serde(tag = "error")]
|
||||
pub enum Error {
|
||||
#[serde(rename = "/AnyCall/BadRequest@ANYCALL_LITE_1")]
|
||||
#[error("Invalid Arguments")]
|
||||
BadRequest,
|
||||
|
||||
#[serde(rename = "/AnyCall/BadReply@ANYCALL_LITE_1")]
|
||||
#[error("Bad Reply")]
|
||||
BadReply,
|
||||
|
||||
#[serde(rename = "/AnyCall/NotImplemented@ANYCALL_LITE_1")]
|
||||
#[error("Not Implemented")]
|
||||
NotImplemented,
|
||||
|
||||
#[serde(rename = "/AnyCall/PermissionDenied@ANYCALL_LITE_1")]
|
||||
#[error("Permission Denied")]
|
||||
PermissionDenied,
|
||||
|
||||
#[serde(rename = "/AnyCall/DeliveryError@ANYCALL_LITE_1")]
|
||||
#[error("Delivery Error")]
|
||||
Delivery,
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
use crate::{
|
||||
SOCKET_NAME,
|
||||
repr::{Error, Request, ser_reply},
|
||||
};
|
||||
use serde::Serialize;
|
||||
use std::os::{linux::net::SocketAddrExt, unix::net::SocketAddr as StdSocketAddr};
|
||||
use tokio::{
|
||||
io::{AsyncReadExt, AsyncWriteExt},
|
||||
net::{UnixListener, UnixStream, unix::SocketAddr},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Listener(UnixListener);
|
||||
impl Listener {
|
||||
pub fn bind() -> std::io::Result<Self> {
|
||||
let addr = SocketAddr::from(StdSocketAddr::from_abstract_name(SOCKET_NAME)?);
|
||||
UnixListener::bind_addr(&addr).map(Self)
|
||||
}
|
||||
|
||||
pub async fn accept(&self) -> std::io::Result<Connection> {
|
||||
let stream = self.0.accept().await?.0;
|
||||
let cred = stream.peer_cred()?;
|
||||
Ok(Connection {
|
||||
stream,
|
||||
buf: Vec::with_capacity(128),
|
||||
uid: cred.uid(),
|
||||
gid: cred.gid(),
|
||||
pid: cred.pid().unwrap_or_default() as _,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Connection {
|
||||
stream: UnixStream,
|
||||
buf: Vec<u8>,
|
||||
pub uid: u32,
|
||||
pub gid: u32,
|
||||
pub pid: u32,
|
||||
}
|
||||
impl Connection {
|
||||
pub async fn recv(&mut self) -> std::io::Result<Request> {
|
||||
loop {
|
||||
let size = self.stream.read_u16_le().await?;
|
||||
self.buf.resize(size as usize, 0);
|
||||
self.stream.read_exact(&mut self.buf).await?;
|
||||
let Ok(request) = serde_json::from_slice(&self.buf) else {
|
||||
self.send::<()>(Err(Error::BadRequest)).await?;
|
||||
continue;
|
||||
};
|
||||
break Ok(request);
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send<T: Serialize>(&mut self, reply: Result<T, Error>) -> std::io::Result<()> {
|
||||
let reply = ser_reply(reply);
|
||||
self.stream.write_u16_le(reply.len() as u16).await?;
|
||||
self.stream.write_all(reply.as_bytes()).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user