#[cfg(target_os = "linux")]
mod linux;
#[cfg(target_os = "linux")]
pub use linux::*;
use std::{
error::Error,
fmt::Debug,
io::{self, Read, Write},
};
use serde::{Deserialize, Serialize};
use thiserror::Error;
use crate::Transport;
use crate::codecs::BaseStreams;
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum BusdClientError<E: Error> {
#[error("I/O error: {0}")]
Io(#[from] io::Error),
#[error("Transport error: {0}")]
Transport(#[source] E),
#[error("Bad hello message ({0})")]
BadHello(serde_json::Error),
#[error("Error connecting to the bus daemon: {0}")]
ErrorOnHello(String),
}
#[derive(Debug, Serialize)]
struct BusdClientHello<'a> {
#[serde(rename = "type")]
typ: &'a str,
version: u32,
roles: &'a [&'a str],
}
#[derive(Debug, Deserialize)]
#[allow(unused)]
struct BusdServerMessage {
#[serde(rename = "gen")]
generation: Option<u32>,
#[serde(flatten)]
data: BusdServerMessageData,
}
#[derive(Debug, Deserialize)]
#[allow(unused)]
#[serde(tag = "type")]
#[serde(rename_all = "camelCase")]
enum BusdServerMessageData {
Hello {
version: u32,
token: String,
},
Error {
#[serde(rename = "data")]
msg: String,
},
}
#[derive(Debug)]
#[repr(transparent)]
pub struct BusdStream<T>(pub T);
#[derive(Debug)]
pub struct BusdClient<S, T: Transport<Streams = BusdStream<S>>> {
transport: T,
}
impl<S, T: Transport<Streams = BusdStream<S>>> BusdClient<S, T> {
#[must_use]
pub fn new(transport: T) -> Self {
Self { transport }
}
}
impl<S: Read + Write, T: Transport<Streams = BusdStream<S>>> Transport for BusdClient<S, T> {
type Streams = BaseStreams<S>;
type Error = BusdClientError<T::Error>;
fn open_streams(&mut self) -> Result<Self::Streams, Self::Error> {
let mut rpc_stream = self
.transport
.open_streams()
.map_err(BusdClientError::Transport)?
.0;
rpc_stream.write_all(b"R\0")?;
rpc_stream.write_all(
&serde_json::to_vec(&BusdClientHello {
typ: "hello",
version: 1,
roles: &["rpc", "blob", "event"],
})
.unwrap(),
)?;
rpc_stream.write_all(b"\0")?;
let mut null_buf = [0; 1];
rpc_stream.read_exact(&mut null_buf)?;
let mut de = serde_json::Deserializer::from_reader(&mut rpc_stream);
let server_msg =
BusdServerMessage::deserialize(&mut de).map_err(BusdClientError::BadHello)?;
rpc_stream.read_exact(&mut null_buf)?;
match server_msg.data {
BusdServerMessageData::Hello { version: _, token } => {
let mut blob_stream = self
.transport
.open_streams()
.map_err(BusdClientError::Transport)?
.0;
blob_stream.write_all(b"B")?;
blob_stream.write_all(token.as_bytes())?;
let mut event_stream = self
.transport
.open_streams()
.map_err(BusdClientError::Transport)?
.0;
event_stream.write_all(b"E")?;
event_stream.write_all(token.as_bytes())?;
Ok(BaseStreams {
rpc: rpc_stream,
blob: blob_stream,
event: event_stream,
})
}
BusdServerMessageData::Error { msg } => Err(BusdClientError::ErrorOnHello(msg)),
}
}
}