use std::collections::VecDeque;
use std::fmt;
use std::future::Future;
use std::pin::{Pin, pin};
use std::task::{Context, Poll};
use std::time::Duration;
use tokio::time::{Instant, Sleep};
use tokio_dbus::org_freedesktop_dbus::{self, NameFlag, NameReply};
use tokio_dbus::{
Alignment, Body, BodyBuf, Buffers, MessageBuf, MessageKind, ObjectPath, RawArray, Serial,
Signature,
};
use crate::error::ErrorKind;
use crate::{Decode, Encode, Error, Result};
#[derive(Default)]
pub struct Arguments {
buf: BodyBuf,
}
impl Arguments {
pub fn new(signature: &Signature) -> Result<Self> {
let mut buf = BodyBuf::new();
buf.extend_signature(signature)?;
Ok(Self { buf })
}
pub fn new_const(signature: &'static Signature) -> Self {
let mut buf = BodyBuf::new();
buf.extend_signature(signature)
.expect("A validated signature cannot fail to extend an empty body");
Self { buf }
}
pub fn empty() -> Self {
Self::default()
}
pub fn store<T>(&mut self, value: T) -> &mut Self
where
T: Encode,
{
value.encode(&mut self.buf.raw());
self
}
pub fn store_variant<T>(&mut self, signature: &Signature, value: T) -> &mut Self
where
T: Encode,
{
let mut raw = self.buf.raw();
raw.store_signature(signature);
value.encode(&mut raw);
self
}
pub fn store_variant_dict(&mut self) -> VariantDict<'_> {
VariantDict {
array: self.buf.raw().into_array(Alignment::U64),
}
}
fn body(&self) -> Body<'_> {
self.buf.as_body()
}
#[cfg(test)]
pub(crate) fn body_for_test(&self) -> Body<'_> {
self.body()
}
}
pub struct VariantDict<'a> {
array: RawArray<'a>,
}
impl VariantDict<'_> {
pub fn entry<T>(&mut self, name: &str, signature: &Signature, value: T) -> &mut Self
where
T: Encode,
{
let mut entry = self.array.as_raw();
entry.align(Alignment::U64);
name.encode(&mut entry);
entry.store_signature(signature);
value.encode(&mut entry);
self
}
pub fn finish(self) {}
}
pub fn decode_variant<T>(body: &mut Body<'_>, expected: &Signature) -> Result<T>
where
T: Decode,
{
let signature = body.read::<Signature>()?;
if signature != expected {
return Err(Error::new(ErrorKind::UnexpectedSignature(Box::new((
expected.to_owned(),
signature.to_owned(),
)))));
}
T::decode(body)
}
impl fmt::Debug for Arguments {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Arguments")
.field("signature", &self.buf.signature())
.finish()
}
}
pub struct Connection {
connection: tokio_dbus::Connection,
buffers: Buffers,
queue: VecDeque<MessageBuf>,
unique_name: String,
timeout: Option<Duration>,
sleep: Option<Pin<Box<Sleep>>>,
}
impl Connection {
pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(25);
pub async fn session_bus() -> Result<Self> {
Self::start(tokio_dbus::Connection::session_bus()?).await
}
pub async fn system_bus() -> Result<Self> {
Self::start(tokio_dbus::Connection::system_bus()?).await
}
async fn start(connection: tokio_dbus::Connection) -> Result<Self> {
let mut this = Self {
connection,
buffers: Buffers::new(),
queue: VecDeque::new(),
unique_name: String::new(),
timeout: Some(Self::DEFAULT_TIMEOUT),
sleep: None,
};
this.connection.connect(&mut this.buffers).await?;
let serial = this.buffers.hello()?;
let reply = this.wait_for(serial).await?;
let Ok(name) = reply.body().read::<str>() else {
return Err(Error::new(ErrorKind::MissingUniqueName));
};
this.unique_name = name.to_owned();
Ok(this)
}
pub fn unique_name(&self) -> &str {
&self.unique_name
}
pub fn set_default_timeout(&mut self, timeout: Option<Duration>) {
self.timeout = timeout;
}
pub fn default_timeout(&self) -> Option<Duration> {
self.timeout
}
pub async fn call(
&mut self,
destination: &str,
path: &ObjectPath,
interface: &str,
member: &str,
arguments: &Arguments,
) -> Result<Reply> {
let m = self
.buffers
.send
.method_call(path, member)
.with_destination(destination)
.with_interface(interface)
.with_body(arguments.body());
let serial = m.serial();
self.buffers.send.write_message(m)?;
let message = self.wait_for(serial).await?;
Ok(Reply { message })
}
pub fn emit(
&mut self,
path: &ObjectPath,
interface: &str,
member: &str,
arguments: &Arguments,
) -> Result<()> {
let m = self
.buffers
.send
.signal(path, member)
.with_interface(interface)
.with_body(arguments.body());
self.buffers.send.write_message(m)?;
Ok(())
}
pub fn reply(&mut self, call: &Call, arguments: &Arguments) -> Result<()> {
let m = call
.message
.borrow()
.method_return(self.buffers.send.next_serial())
.with_body(arguments.body());
self.buffers.send.write_message(m)?;
Ok(())
}
pub fn reply_error(&mut self, call: &Call, error: &Error) -> Result<()> {
let name = error
.name()
.unwrap_or(org_freedesktop_dbus::FAILED_ERROR)
.to_owned();
let mut arguments = Arguments::new_const(Signature::STRING);
arguments.store(error.to_string().as_str());
let m = call
.message
.borrow()
.error(&name, self.buffers.send.next_serial())
.with_body(arguments.body());
self.buffers.send.write_message(m)?;
Ok(())
}
pub async fn request_name(&mut self, name: &str, flags: NameFlag) -> Result<NameReply> {
let serial = self.buffers.request_name(name, flags)?;
let reply = self.wait_for(serial).await?;
Ok(reply.body().load::<NameReply>()?)
}
pub async fn acquire_name(&mut self, name: &str, flags: NameFlag) -> Result<()> {
match self.request_name(name, flags).await? {
NameReply::PRIMARY_OWNER | NameReply::ALREADY_OWNER => Ok(()),
_ => Err(Error::new(ErrorKind::NameTaken(name.into()))),
}
}
pub async fn release_name(&mut self, name: &str) -> Result<()> {
let serial = self.buffers.release_name(name)?;
self.wait_for(serial).await?;
Ok(())
}
pub async fn add_match(&mut self, rule: &str) -> Result<()> {
let serial = self.buffers.add_match(rule)?;
self.wait_for(serial).await?;
Ok(())
}
pub async fn remove_match(&mut self, rule: &str) -> Result<()> {
let serial = self.buffers.remove_match(rule)?;
self.wait_for(serial).await?;
Ok(())
}
pub async fn watch_name(&mut self, name: &str) -> Result<()> {
self.add_match(&crate::NameOwnerChanged::rule(name)).await
}
pub async fn unwatch_name(&mut self, name: &str) -> Result<()> {
self.remove_match(&crate::NameOwnerChanged::rule(name))
.await
}
pub async fn name_owner(&mut self, name: &str) -> Result<Option<String>> {
let mut arguments = Arguments::new_const(Signature::STRING);
arguments.store(name);
let result = self
.call(
org_freedesktop_dbus::DESTINATION,
org_freedesktop_dbus::PATH,
org_freedesktop_dbus::INTERFACE,
"GetNameOwner",
&arguments,
)
.await;
match result {
Ok(reply) => Ok(Some(reply.read::<String>()?)),
Err(error) if error.name() == Some(org_freedesktop_dbus::NAME_HAS_NO_OWNER_ERROR) => {
Ok(None)
}
Err(error) => Err(error),
}
}
pub fn reply_unknown_method(&mut self, call: &Call) -> Result<()> {
self.reply_error(
call,
&Error::remote(
org_freedesktop_dbus::UNKNOWN_METHOD_ERROR,
format_args!(
"No such method: {}.{}",
call.interface().unwrap_or_default(),
call.member()
),
),
)
}
pub async fn flush(&mut self) -> Result<()> {
self.connection.flush(&mut self.buffers).await?;
if self.buffers.recv.has_message() {
let message = self.buffers.recv.last_message()?.to_owned();
self.queue.push_back(message);
self.buffers.recv.clear();
}
Ok(())
}
pub async fn next(&mut self) -> Result<Incoming> {
loop {
if let Some(message) = self.queue.pop_front() {
if let Some(incoming) = Incoming::new(message) {
return Ok(incoming);
}
continue;
}
self.connection.wait(&mut self.buffers).await?;
let message = self.buffers.recv.last_message()?.to_owned();
if let Some(incoming) = Incoming::new(message) {
return Ok(incoming);
}
}
}
async fn wait_for(&mut self, serial: Serial) -> Result<MessageBuf> {
let Self {
connection,
buffers,
queue,
timeout,
sleep,
..
} = self;
let future = pin!(drive_until_reply(connection, buffers, queue, serial));
let Some(timeout) = *timeout else {
return future.await;
};
let deadline = Instant::now() + timeout;
let sleep = match sleep {
Some(sleep) => {
sleep.as_mut().reset(deadline);
sleep
}
sleep => sleep.insert(Box::pin(tokio::time::sleep_until(deadline))),
};
Timed {
future,
sleep: sleep.as_mut(),
timeout,
}
.await
}
}
async fn drive_until_reply(
connection: &mut tokio_dbus::Connection,
buffers: &mut Buffers,
queue: &mut VecDeque<MessageBuf>,
serial: Serial,
) -> Result<MessageBuf> {
loop {
connection.wait(buffers).await?;
let message = buffers.recv.last_message()?;
match message.kind() {
MessageKind::MethodReturn { reply_serial } if reply_serial == serial => {
return Ok(message.to_owned());
}
MessageKind::Error {
error_name,
reply_serial,
} if reply_serial == serial => {
let text = message.body().read::<str>().unwrap_or_default();
return Err(Error::remote(error_name, text));
}
_ => {
let message = message.to_owned();
queue.push_back(message);
}
}
}
}
struct Timed<'a, F> {
future: Pin<&'a mut F>,
sleep: Pin<&'a mut Sleep>,
timeout: Duration,
}
impl<T, F> Future for Timed<'_, F>
where
F: Future<Output = Result<T>>,
{
type Output = Result<T>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if let Poll::Ready(result) = self.future.as_mut().poll(cx) {
return Poll::Ready(result);
}
if self.sleep.as_mut().poll(cx).is_ready() {
return Poll::Ready(Err(Error::new(ErrorKind::Timeout(self.timeout))));
}
Poll::Pending
}
}
pub struct Reply {
message: MessageBuf,
}
impl Reply {
pub fn body(&self) -> Body<'_> {
self.message.body()
}
pub fn read<T>(&self) -> Result<T>
where
T: Decode,
{
T::decode(&mut self.body())
}
}
impl fmt::Debug for Reply {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.message.fmt(f)
}
}
#[derive(Debug)]
#[non_exhaustive]
pub enum Incoming {
Call(Call),
Signal(SignalMessage),
}
impl Incoming {
fn new(message: MessageBuf) -> Option<Self> {
match message.kind() {
MessageKind::MethodCall { .. } => Some(Incoming::Call(Call { message })),
MessageKind::Signal { .. } => Some(Incoming::Signal(SignalMessage { message })),
_ => None,
}
}
}
pub struct Call {
message: MessageBuf,
}
impl Call {
pub fn path(&self) -> &ObjectPath {
match self.message.kind() {
MessageKind::MethodCall { path, .. } => path,
_ => unreachable!("Only constructed from a method call"),
}
}
pub fn member(&self) -> &str {
match self.message.kind() {
MessageKind::MethodCall { member, .. } => member,
_ => unreachable!("Only constructed from a method call"),
}
}
pub fn interface(&self) -> Option<&str> {
self.message.interface()
}
pub fn sender(&self) -> Option<&str> {
self.message.sender()
}
pub fn body(&self) -> Body<'_> {
self.message.body()
}
}
impl fmt::Debug for Call {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Call")
.field("path", &self.path())
.field("interface", &self.interface())
.field("member", &self.member())
.finish()
}
}
pub struct SignalMessage {
message: MessageBuf,
}
impl SignalMessage {
pub fn path(&self) -> &ObjectPath {
match self.message.kind() {
MessageKind::Signal { path, .. } => path,
_ => unreachable!("Only constructed from a signal"),
}
}
pub fn member(&self) -> &str {
match self.message.kind() {
MessageKind::Signal { member, .. } => member,
_ => unreachable!("Only constructed from a signal"),
}
}
pub fn interface(&self) -> Option<&str> {
self.message.interface()
}
pub fn sender(&self) -> Option<&str> {
self.message.sender()
}
pub fn body(&self) -> Body<'_> {
self.message.body()
}
}
impl fmt::Debug for SignalMessage {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SignalMessage")
.field("path", &self.path())
.field("interface", &self.interface())
.field("member", &self.member())
.finish()
}
}