use crate::{Message, to_c_str, c_str_to_slice, MessageType};
use crate::message::MatchRule;
#[cfg(not(feature = "native-channel"))]
mod ffichannel;
#[cfg(not(feature = "native-channel"))]
pub use ffichannel::Channel;
#[cfg(feature = "native-channel")]
mod nativechannel;
#[cfg(feature = "native-channel")]
pub use nativechannel::Channel;
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub enum BusType {
Session = ffi::DBusBusType::Session as isize,
System = ffi::DBusBusType::System as isize,
Starter = ffi::DBusBusType::Starter as isize,
}
#[cfg(unix)]
pub type WatchFd = std::os::unix::io::RawFd;
#[cfg(windows)]
pub type WatchFd = std::os::windows::io::RawSocket;
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Watch {
pub fd: WatchFd,
pub read: bool,
pub write: bool,
}
pub trait Sender {
fn send(&self, msg: Message) -> Result<u32, ()>;
}
impl Sender for std::cell::RefCell<Vec<Message>> {
fn send(&self, msg: Message) -> Result<u32, ()> {
self.borrow_mut().push(msg);
Ok(0)
}
}
impl Sender for std::sync::Mutex<Vec<Message>> {
fn send(&self, msg: Message) -> Result<u32, ()> {
self.lock().unwrap().push(msg);
Ok(0)
}
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Token(pub usize);
pub trait MatchingReceiver {
type F;
fn start_receive(&self, m: MatchRule<'static>, f: Self::F) -> Token;
fn stop_receive(&self, id: Token) -> Option<(MatchRule<'static>, Self::F)>;
}
impl Sender for Channel {
fn send(&self, msg: Message) -> Result<u32, ()> { Channel::send(self, msg) }
}
pub fn default_reply(m: &Message) -> Option<Message> {
peer(&m).or_else(|| unknown_method(&m))
}
fn peer(m: &Message) -> Option<Message> {
if let Some(intf) = m.interface() {
if &*intf != "org.freedesktop.DBus.Peer" { return None; }
if let Some(method) = m.member() {
if &*method == "Ping" { return Some(m.method_return()) }
if &*method == "GetMachineId" {
let mut r = m.method_return();
unsafe {
let id = ffi::dbus_get_local_machine_id();
if !id.is_null() {
r = r.append1(c_str_to_slice(&(id as *const _)).unwrap());
ffi::dbus_free(id as *mut _);
return Some(r)
}
}
return Some(m.error(&"org.freedesktop.DBus.Error.Failed".into(), &to_c_str("Failed to retreive UUID")))
}
}
Some(m.error(&"org.freedesktop.DBus.Error.UnknownMethod".into(), &to_c_str("Method does not exist")))
} else { None }
}
fn unknown_method(m: &Message) -> Option<Message> {
if m.msg_type() != MessageType::MethodCall { return None; }
Some(m.error(&"org.freedesktop.DBus.Error.UnknownMethod".into(), &to_c_str("Path, Interface, or Method does not exist")))
}
#[test]
fn test_channel_send_sync() {
fn is_send<T: Send>(_: &T) {}
fn is_sync<T: Sync>(_: &T) {}
let c = Channel::get_private(BusType::Session).unwrap();
is_send(&c);
is_sync(&c);
}
#[test]
fn channel_simple_test() {
let mut c = Channel::get_private(BusType::Session).unwrap();
assert!(c.is_connected());
c.set_watch_enabled(true);
let fd = c.watch();
println!("{:?}", fd);
let m = Message::new_method_call("org.freedesktop.DBus", "/", "org.freedesktop.DBus", "ListNames").unwrap();
let reply = c.send(m).unwrap();
let my_name = c.unique_name().unwrap();
loop {
while let Some(mut msg) = c.pop_message() {
println!("{:?}", msg);
if msg.get_reply_serial() == Some(reply) {
let r = msg.as_result().unwrap();
let z: crate::arg::Array<&str, _> = r.get1().unwrap();
for n in z {
println!("{}", n);
if n == my_name { return; } }
assert!(false);
} else if let Some(r) = default_reply(&msg) {
c.send(r).unwrap();
}
}
c.read_write(Some(std::time::Duration::from_millis(100))).unwrap();
}
}
#[test]
fn test_bus_type_is_compatible_with_set() {
use std::collections::HashSet;
let mut set: HashSet<BusType> = HashSet::new();
set.insert(BusType::Starter);
set.insert(BusType::Starter);
assert_eq!(set.len(), 1);
assert!(!set.contains(&BusType::Session));
assert!(!set.contains(&BusType::System));
assert!(set.contains(&BusType::Starter));
}
#[test]
fn watchmap() {
let mut c = Channel::get_private(BusType::Session).unwrap();
c.set_watch_enabled(true);
let w = c.watch();
assert_eq!(w.write, false);
assert_eq!(w.read, true);
c.set_watch_enabled(false);
println!("{:?}", w);
c.set_watch_enabled(true);
}