Start using zbus instead of dbus
Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>
This commit is contained in:
parent
82019d17d9
commit
4bf5204ad4
7 changed files with 458 additions and 316 deletions
18
Cargo.toml
18
Cargo.toml
|
@ -7,20 +7,8 @@ edition = "2021"
|
||||||
categories = ["gateway", "bridge", "transport", "modemmanager", "xmpp", "jabber"]
|
categories = ["gateway", "bridge", "transport", "modemmanager", "xmpp", "jabber"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
async-trait = "0.1.56"
|
tokio = { version = "1", features = [ "macros", "rt-multi-thread" ] }
|
||||||
mmdbus = "1.18.6"
|
|
||||||
dbus-tokio = "0.7.5"
|
|
||||||
tokio = { version = "1.19.2", features = [ "time", "macros", "rt-multi-thread" ] }
|
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
futures-util = "0.3"
|
|
||||||
xmpp = "0.3"
|
|
||||||
xmpp-parsers = "0.19"
|
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
env_logger = "0.8"
|
pretty_env_logger = "0.5"
|
||||||
|
zbus = "3.14.1"
|
||||||
[patch.crates-io]
|
|
||||||
jid = { path = "../xmpp-rs/jid" }
|
|
||||||
minidom = { path = "../xmpp-rs/minidom" }
|
|
||||||
tokio-xmpp = { path = "../xmpp-rs/tokio-xmpp" }
|
|
||||||
xmpp = { path = "../xmpp-rs/xmpp" }
|
|
||||||
xmpp-parsers = { path = "../xmpp-rs/parsers" }
|
|
||||||
|
|
30
src/error.rs
30
src/error.rs
|
@ -18,22 +18,17 @@
|
||||||
use std::convert::From;
|
use std::convert::From;
|
||||||
use std::error::Error as StdError;
|
use std::error::Error as StdError;
|
||||||
|
|
||||||
use mmdbus::dbus;
|
|
||||||
use xmpp_parsers::JidParseError;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
DBusError(dbus::Error),
|
Zbus(zbus::Error),
|
||||||
InvalidArgs,
|
ZbusFdo(zbus::fdo::Error),
|
||||||
JidParseError(JidParseError),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StdError for Error {
|
impl StdError for Error {
|
||||||
fn cause(&self) -> Option<&dyn StdError> {
|
fn cause(&self) -> Option<&dyn StdError> {
|
||||||
match self {
|
match self {
|
||||||
Error::DBusError(e) => Some(e),
|
Error::Zbus(e) => Some(e),
|
||||||
Error::InvalidArgs => None,
|
Error::ZbusFdo(e) => Some(e),
|
||||||
Error::JidParseError(e) => Some(e),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,21 +36,20 @@ impl StdError for Error {
|
||||||
impl std::fmt::Display for Error {
|
impl std::fmt::Display for Error {
|
||||||
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Error::DBusError(e) => write!(fmt, "dbus error: {}", e),
|
Error::Zbus(e) => write!(fmt, "zbus error: {}", e),
|
||||||
Error::InvalidArgs => write!(fmt, "invalid arguments"),
|
Error::ZbusFdo(e) => write!(fmt, "zbus fdo error: {}", e),
|
||||||
Error::JidParseError(e) => write!(fmt, "jid parse error: {}", e),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<dbus::Error> for Error {
|
impl From<zbus::Error> for Error {
|
||||||
fn from(err: dbus::Error) -> Error {
|
fn from(err: zbus::Error) -> Error {
|
||||||
Error::DBusError(err)
|
Error::Zbus(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<JidParseError> for Error {
|
impl From<zbus::fdo::Error> for Error {
|
||||||
fn from(err: JidParseError) -> Error {
|
fn from(err: zbus::fdo::Error) -> Error {
|
||||||
Error::JidParseError(err)
|
Error::ZbusFdo(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
236
src/main.rs
236
src/main.rs
|
@ -13,233 +13,19 @@
|
||||||
// You should have received a copy of the GNU Affero General Public License
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
pub mod error;
|
mod error;
|
||||||
pub mod mm;
|
mod modem;
|
||||||
|
|
||||||
use error::Error;
|
use crate::error::Error;
|
||||||
use mm::modem::Modem as ModemAccess;
|
use crate::modem::ModemManager;
|
||||||
|
|
||||||
use std::fmt;
|
#[tokio::main]
|
||||||
use std::sync::Arc;
|
async fn main() -> Result<(), Error> {
|
||||||
use std::str::FromStr;
|
let manager = ModemManager::connect().await?;
|
||||||
use std::env::args;
|
for modem in manager {
|
||||||
|
println!("FOO0: {:?}", modem);
|
||||||
use env_logger;
|
println!("FOO0: {:?}", modem.manufacturer().await?);
|
||||||
|
println!("FOO0: {:?}", modem.model().await?);
|
||||||
use futures_util::StreamExt;
|
|
||||||
use tokio::{
|
|
||||||
task::JoinHandle,
|
|
||||||
time::Duration,
|
|
||||||
};
|
|
||||||
|
|
||||||
use mmdbus::{
|
|
||||||
dbus::{
|
|
||||||
message::MatchRule,
|
|
||||||
nonblock::{
|
|
||||||
SyncConnection, Proxy,
|
|
||||||
stdintf::org_freedesktop_dbus::ObjectManager,
|
|
||||||
},
|
|
||||||
strings::{Path as DBusPath},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
use dbus_tokio::connection;
|
|
||||||
|
|
||||||
use xmpp::{ClientBuilder, ClientType};
|
|
||||||
use xmpp_parsers::{
|
|
||||||
Jid, BareJid,
|
|
||||||
message::MessageType,
|
|
||||||
};
|
|
||||||
|
|
||||||
// The following source has been used as an example:
|
|
||||||
// https://github.com/soerenmeier/linux-info/blob/master/src/network/modem_manager.rs
|
|
||||||
|
|
||||||
const MM_NAME: &str = "org.freedesktop.ModemManager1";
|
|
||||||
const MM_PATH: &str = "/org/freedesktop/ModemManager1";
|
|
||||||
const TIMEOUT: Duration = Duration::from_secs(5);
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct DBus {
|
|
||||||
pub conn: Arc<SyncConnection>,
|
|
||||||
pub handle: Arc<JoinHandle<()>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DBus {
|
|
||||||
pub fn connect() -> Result<Self, Error> {
|
|
||||||
let (resource, conn) = connection::new_system_sync()?;
|
|
||||||
|
|
||||||
let handle: JoinHandle<()> = tokio::spawn(async {
|
|
||||||
let err = resource.await;
|
|
||||||
panic!("Lost connection to D-Bus: {}", err);
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(Self { conn, handle: Arc::new(handle) })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn proxy<'a, 'b, P>(&'b self, path: P) -> Proxy<'a, &'b SyncConnection>
|
|
||||||
where
|
|
||||||
P: Into<DBusPath<'a>>,
|
|
||||||
{
|
|
||||||
Proxy::new(MM_NAME, path, TIMEOUT, &*self.conn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct ModemManager {
|
|
||||||
dbus: DBus,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ModemManager {
|
|
||||||
pub fn connect() -> Result<Self, Error> {
|
|
||||||
DBus::connect().map(|dbus| Self { dbus })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn modems(&self) -> Result<Vec<Modem>, Error> {
|
|
||||||
let objects = self.dbus.proxy(MM_PATH).get_managed_objects().await?;
|
|
||||||
let modems = objects
|
|
||||||
.into_iter()
|
|
||||||
.map(|(path, _)| {
|
|
||||||
Modem {
|
|
||||||
dbus: self.dbus.clone(),
|
|
||||||
path,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Ok(modems)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Modem {
|
|
||||||
dbus: DBus,
|
|
||||||
pub path: DBusPath<'static>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for Modem {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "Modem {{ {}, {:?}, .. }}", self.path, "1234")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Modem {
|
|
||||||
pub async fn enabled(&self) -> Result<bool, Error> {
|
|
||||||
let state: ModemState = ModemAccess::state(&self.dbus.proxy(&self.path)).await.map(Into::into)?;
|
|
||||||
Ok(match state {
|
|
||||||
ModemState::Enabling
|
|
||||||
| ModemState::Enabled
|
|
||||||
| ModemState::Searching
|
|
||||||
| ModemState::Registered
|
|
||||||
| ModemState::Connecting
|
|
||||||
| ModemState::Connected => true,
|
|
||||||
_ => false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn model(&self) -> Result<String, Error> {
|
|
||||||
ModemAccess::model(&self.dbus.proxy(&self.path)).await.map_err(Error::DBusError)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(i32)]
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub enum ModemState {
|
|
||||||
/// The modem is unusable.
|
|
||||||
Failed = -1,
|
|
||||||
/// State unknown or not reportable.
|
|
||||||
Unknown = 0,
|
|
||||||
/// The modem is currently being initialized.
|
|
||||||
Initializing = 1,
|
|
||||||
/// The modem needs to be unlocked.
|
|
||||||
Locked = 2,
|
|
||||||
/// The modem is not enabled and is powered down.
|
|
||||||
Disabled = 3,
|
|
||||||
/// The modem is currently transitioning to the MM_MODEM_STATE_DISABLED
|
|
||||||
/// state.
|
|
||||||
Disabling = 4,
|
|
||||||
/// The modem is currently transitioning to the MM_MODEM_STATE_ENABLED
|
|
||||||
/// state.
|
|
||||||
Enabling = 5,
|
|
||||||
/// The modem is enabled and powered on but not registered with a network
|
|
||||||
/// provider and not available for data connections.
|
|
||||||
Enabled = 6,
|
|
||||||
/// The modem is searching for a network provider to register with.
|
|
||||||
Searching = 7,
|
|
||||||
/// The modem is registered with a network provider, and data connections
|
|
||||||
/// and messaging may be available for use.
|
|
||||||
Registered = 8,
|
|
||||||
/// The modem is disconnecting and deactivating the last active packet data
|
|
||||||
/// bearer. This state will not be entered if more than one packet data
|
|
||||||
/// bearer is active and one of the active bearers is deactivated.
|
|
||||||
Disconnecting = 9,
|
|
||||||
/// The modem is activating and connecting the first packet data bearer.
|
|
||||||
/// Subsequent bearer activations when another bearer is already active
|
|
||||||
/// do not cause this state to be entered.
|
|
||||||
Connecting = 10,
|
|
||||||
/// One or more packet data bearers is active and connected.
|
|
||||||
Connected = 11,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<i32> for ModemState {
|
|
||||||
fn from(num: i32) -> Self {
|
|
||||||
if num < -1 || num > 11 {
|
|
||||||
Self::Unknown
|
|
||||||
} else {
|
|
||||||
unsafe { *(&num as *const i32 as *const Self) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn print_foo(mm: ModemManager) -> Result<(), Error> {
|
|
||||||
let modems = mm.modems().await?;
|
|
||||||
println!("Modems: {:?}", modems);
|
|
||||||
for modem in modems {
|
|
||||||
println!("Modem: {:?}", modem);
|
|
||||||
println!("Enabled: {:?}", modem.enabled().await);
|
|
||||||
println!("Model: {:?}", modem.model().await);
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
|
||||||
pub async fn main() -> Result<(), Error> {
|
|
||||||
env_logger::init();
|
|
||||||
|
|
||||||
let args: Vec<String> = args().collect();
|
|
||||||
if args.len() != 3 {
|
|
||||||
println!("Usage: {} <jid> <password>", args[0]);
|
|
||||||
return Err(Error::InvalidArgs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ModemManager
|
|
||||||
let dbus = DBus::connect()?;
|
|
||||||
|
|
||||||
let mut interval = tokio::time::interval(Duration::from_secs(2));
|
|
||||||
|
|
||||||
let mr = MatchRule::new_signal("org.freedesktop.DBus.Properties", "PropertiesChanged");
|
|
||||||
|
|
||||||
|
|
||||||
// XMPP
|
|
||||||
let jid_str = args[1].as_str();
|
|
||||||
let jid = Jid::Bare(BareJid::from_str(jid_str).unwrap());
|
|
||||||
let passwd = args[2].as_str();
|
|
||||||
|
|
||||||
// Client instance
|
|
||||||
let mut xmpp = ClientBuilder::new(jid_str, passwd)
|
|
||||||
.set_client(ClientType::Bot, "gateway_mm")
|
|
||||||
.set_website("https://codeberg.org/pep./gateway_mm")
|
|
||||||
.build()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
tokio::select! {
|
|
||||||
events = xmpp.wait_for_events() => {
|
|
||||||
println!("Events: {:?}", events);
|
|
||||||
},
|
|
||||||
_ = interval.tick() => {
|
|
||||||
let mm = ModemManager { dbus: dbus.clone() };
|
|
||||||
let _ = print_foo(mm).await;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
// Copyright (C) 2022 Maxime “pep” Buquet <pep@bouah.net>
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU Affero General Public License as published by the
|
|
||||||
// Free Software Foundation, either version 3 of the License, or (at your
|
|
||||||
// option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
|
|
||||||
// for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Affero General Public License
|
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
pub mod modem;
|
|
|
@ -1,42 +0,0 @@
|
||||||
// Copyright (C) 2022 Maxime “pep” Buquet <pep@bouah.net>
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU Affero General Public License as published by the
|
|
||||||
// Free Software Foundation, either version 3 of the License, or (at your
|
|
||||||
// option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
|
|
||||||
// for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Affero General Public License
|
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
use std::ops::Deref;
|
|
||||||
use std::marker::Sync;
|
|
||||||
|
|
||||||
use async_trait::async_trait;
|
|
||||||
use mmdbus::dbus::{nonblock, Error as DBusError};
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
pub trait Modem {
|
|
||||||
async fn enable(&self, enable: bool) -> Result<(), DBusError>;
|
|
||||||
async fn state(&self) -> Result<i32, DBusError>;
|
|
||||||
async fn model(&self) -> Result<String, DBusError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl<'a, T: nonblock::NonblockReply, C: Deref<Target=T> + Sync> Modem for nonblock::Proxy<'a, C> {
|
|
||||||
async fn enable(&self, enable: bool) -> Result<(), DBusError> {
|
|
||||||
self.method_call("org.freedesktop.ModemManager1.Modem", "Enable", (enable,)).await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn state(&self) -> Result<i32, DBusError> {
|
|
||||||
<Self as nonblock::stdintf::org_freedesktop_dbus::Properties>::get(&self, "org.freedesktop.ModemManager1.Modem", "State").await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn model(&self) -> Result<String, DBusError> {
|
|
||||||
<Self as nonblock::stdintf::org_freedesktop_dbus::Properties>::get(&self, "org.freedesktop.ModemManager1.Modem", "Model").await
|
|
||||||
}
|
|
||||||
}
|
|
316
src/modem/introspect.rs
Normal file
316
src/modem/introspect.rs
Normal file
|
@ -0,0 +1,316 @@
|
||||||
|
//! DBus interface proxies for:
|
||||||
|
//!
|
||||||
|
//! - `org.freedesktop.ModemManager1.Modem`,
|
||||||
|
//! - `org.freedesktop.ModemManager1.Modem.Messaging`,
|
||||||
|
//! - `org.freedesktop.ModemManager1.Modem.Simple`,
|
||||||
|
//! - `org.freedesktop.ModemManager1.Modem.Voice`
|
||||||
|
//!
|
||||||
|
//! This code was generated by `zbus-xmlgen` `3.1.1` from DBus introspection data.
|
||||||
|
//! Source: `ModemManager1.xml`.
|
||||||
|
|
||||||
|
use zbus::dbus_proxy;
|
||||||
|
|
||||||
|
#[dbus_proxy(
|
||||||
|
interface = "org.freedesktop.ModemManager1.Modem.Messaging",
|
||||||
|
assume_defaults = true
|
||||||
|
)]
|
||||||
|
trait Messaging {
|
||||||
|
/// Create method
|
||||||
|
fn create(
|
||||||
|
&self,
|
||||||
|
properties: std::collections::HashMap<&str, zbus::zvariant::Value<'_>>,
|
||||||
|
) -> zbus::Result<zbus::zvariant::OwnedObjectPath>;
|
||||||
|
|
||||||
|
/// Delete method
|
||||||
|
fn delete(&self, path: &zbus::zvariant::ObjectPath<'_>) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// List method
|
||||||
|
fn list(&self) -> zbus::Result<Vec<zbus::zvariant::OwnedObjectPath>>;
|
||||||
|
|
||||||
|
/// Added signal
|
||||||
|
#[dbus_proxy(signal)]
|
||||||
|
fn added(&self, path: zbus::zvariant::ObjectPath<'_>, received: bool) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// Deleted signal
|
||||||
|
#[dbus_proxy(signal)]
|
||||||
|
fn deleted(&self, path: zbus::zvariant::ObjectPath<'_>) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// DefaultStorage property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn default_storage(&self) -> zbus::Result<u32>;
|
||||||
|
|
||||||
|
/// Messages property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn messages(&self) -> zbus::Result<Vec<zbus::zvariant::OwnedObjectPath>>;
|
||||||
|
|
||||||
|
/// SupportedStorages property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn supported_storages(&self) -> zbus::Result<Vec<u32>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[dbus_proxy(
|
||||||
|
interface = "org.freedesktop.ModemManager1.Modem",
|
||||||
|
assume_defaults = true
|
||||||
|
)]
|
||||||
|
trait Modem {
|
||||||
|
/// Command method
|
||||||
|
fn command(&self, cmd: &str, timeout: u32) -> zbus::Result<String>;
|
||||||
|
|
||||||
|
/// CreateBearer method
|
||||||
|
fn create_bearer(
|
||||||
|
&self,
|
||||||
|
properties: std::collections::HashMap<&str, zbus::zvariant::Value<'_>>,
|
||||||
|
) -> zbus::Result<zbus::zvariant::OwnedObjectPath>;
|
||||||
|
|
||||||
|
/// DeleteBearer method
|
||||||
|
fn delete_bearer(&self, bearer: &zbus::zvariant::ObjectPath<'_>) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// Enable method
|
||||||
|
fn enable(&self, enable: bool) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// FactoryReset method
|
||||||
|
fn factory_reset(&self, code: &str) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// GetCellInfo method
|
||||||
|
fn get_cell_info(
|
||||||
|
&self,
|
||||||
|
) -> zbus::Result<Vec<std::collections::HashMap<String, zbus::zvariant::OwnedValue>>>;
|
||||||
|
|
||||||
|
/// ListBearers method
|
||||||
|
fn list_bearers(&self) -> zbus::Result<Vec<zbus::zvariant::OwnedObjectPath>>;
|
||||||
|
|
||||||
|
/// Reset method
|
||||||
|
fn reset(&self) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// SetCurrentBands method
|
||||||
|
fn set_current_bands(&self, bands: &[u32]) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// SetCurrentCapabilities method
|
||||||
|
fn set_current_capabilities(&self, capabilities: u32) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// SetCurrentModes method
|
||||||
|
fn set_current_modes(&self, modes: &(u32, u32)) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// SetPowerState method
|
||||||
|
fn set_power_state(&self, state: u32) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// SetPrimarySimSlot method
|
||||||
|
fn set_primary_sim_slot(&self, sim_slot: u32) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
// TODO: This fails to compile: duplicate definitions for `receive_state_changed`
|
||||||
|
// /// StateChanged signal
|
||||||
|
// #[dbus_proxy(signal)]
|
||||||
|
// fn state_changed(&self, old: i32, new: i32, reason: u32) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// AccessTechnologies property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn access_technologies(&self) -> zbus::Result<u32>;
|
||||||
|
|
||||||
|
/// Bearers property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn bearers(&self) -> zbus::Result<Vec<zbus::zvariant::OwnedObjectPath>>;
|
||||||
|
|
||||||
|
/// CarrierConfiguration property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn carrier_configuration(&self) -> zbus::Result<String>;
|
||||||
|
|
||||||
|
/// CarrierConfigurationRevision property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn carrier_configuration_revision(&self) -> zbus::Result<String>;
|
||||||
|
|
||||||
|
/// CurrentBands property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn current_bands(&self) -> zbus::Result<Vec<u32>>;
|
||||||
|
|
||||||
|
/// CurrentCapabilities property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn current_capabilities(&self) -> zbus::Result<u32>;
|
||||||
|
|
||||||
|
/// CurrentModes property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn current_modes(&self) -> zbus::Result<(u32, u32)>;
|
||||||
|
|
||||||
|
/// Device property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn device(&self) -> zbus::Result<String>;
|
||||||
|
|
||||||
|
/// DeviceIdentifier property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn device_identifier(&self) -> zbus::Result<String>;
|
||||||
|
|
||||||
|
/// Drivers property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn drivers(&self) -> zbus::Result<Vec<String>>;
|
||||||
|
|
||||||
|
/// EquipmentIdentifier property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn equipment_identifier(&self) -> zbus::Result<String>;
|
||||||
|
|
||||||
|
/// HardwareRevision property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn hardware_revision(&self) -> zbus::Result<String>;
|
||||||
|
|
||||||
|
/// Manufacturer property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn manufacturer(&self) -> zbus::Result<String>;
|
||||||
|
|
||||||
|
/// MaxActiveBearers property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn max_active_bearers(&self) -> zbus::Result<u32>;
|
||||||
|
|
||||||
|
/// MaxActiveMultiplexedBearers property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn max_active_multiplexed_bearers(&self) -> zbus::Result<u32>;
|
||||||
|
|
||||||
|
/// MaxBearers property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn max_bearers(&self) -> zbus::Result<u32>;
|
||||||
|
|
||||||
|
/// Model property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn model(&self) -> zbus::Result<String>;
|
||||||
|
|
||||||
|
/// OwnNumbers property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn own_numbers(&self) -> zbus::Result<Vec<String>>;
|
||||||
|
|
||||||
|
/// Plugin property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn plugin(&self) -> zbus::Result<String>;
|
||||||
|
|
||||||
|
/// Ports property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn ports(&self) -> zbus::Result<Vec<(String, u32)>>;
|
||||||
|
|
||||||
|
/// PowerState property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn power_state(&self) -> zbus::Result<u32>;
|
||||||
|
|
||||||
|
/// PrimaryPort property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn primary_port(&self) -> zbus::Result<String>;
|
||||||
|
|
||||||
|
/// PrimarySimSlot property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn primary_sim_slot(&self) -> zbus::Result<u32>;
|
||||||
|
|
||||||
|
/// Revision property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn revision(&self) -> zbus::Result<String>;
|
||||||
|
|
||||||
|
/// SignalQuality property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn signal_quality(&self) -> zbus::Result<(u32, bool)>;
|
||||||
|
|
||||||
|
/// Sim property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn sim(&self) -> zbus::Result<zbus::zvariant::OwnedObjectPath>;
|
||||||
|
|
||||||
|
/// SimSlots property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn sim_slots(&self) -> zbus::Result<Vec<zbus::zvariant::OwnedObjectPath>>;
|
||||||
|
|
||||||
|
/// State property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn state(&self) -> zbus::Result<i32>;
|
||||||
|
|
||||||
|
/// StateFailedReason property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn state_failed_reason(&self) -> zbus::Result<u32>;
|
||||||
|
|
||||||
|
/// SupportedBands property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn supported_bands(&self) -> zbus::Result<Vec<u32>>;
|
||||||
|
|
||||||
|
/// SupportedCapabilities property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn supported_capabilities(&self) -> zbus::Result<Vec<u32>>;
|
||||||
|
|
||||||
|
/// SupportedIpFamilies property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn supported_ip_families(&self) -> zbus::Result<u32>;
|
||||||
|
|
||||||
|
/// SupportedModes property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn supported_modes(&self) -> zbus::Result<Vec<(u32, u32)>>;
|
||||||
|
|
||||||
|
/// UnlockRequired property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn unlock_required(&self) -> zbus::Result<u32>;
|
||||||
|
|
||||||
|
/// UnlockRetries property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn unlock_retries(&self) -> zbus::Result<std::collections::HashMap<u32, u32>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[dbus_proxy(
|
||||||
|
interface = "org.freedesktop.ModemManager1.Modem.Simple",
|
||||||
|
assume_defaults = true
|
||||||
|
)]
|
||||||
|
trait Simple {
|
||||||
|
/// Connect method
|
||||||
|
fn connect(
|
||||||
|
&self,
|
||||||
|
properties: std::collections::HashMap<&str, zbus::zvariant::Value<'_>>,
|
||||||
|
) -> zbus::Result<zbus::zvariant::OwnedObjectPath>;
|
||||||
|
|
||||||
|
/// Disconnect method
|
||||||
|
fn disconnect(&self, bearer: &zbus::zvariant::ObjectPath<'_>) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// GetStatus method
|
||||||
|
fn get_status(
|
||||||
|
&self,
|
||||||
|
) -> zbus::Result<std::collections::HashMap<String, zbus::zvariant::OwnedValue>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[dbus_proxy(
|
||||||
|
interface = "org.freedesktop.ModemManager1.Modem.Voice",
|
||||||
|
assume_defaults = true
|
||||||
|
)]
|
||||||
|
trait Voice {
|
||||||
|
/// CallWaitingQuery method
|
||||||
|
fn call_waiting_query(&self) -> zbus::Result<bool>;
|
||||||
|
|
||||||
|
/// CallWaitingSetup method
|
||||||
|
fn call_waiting_setup(&self, enable: bool) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// CreateCall method
|
||||||
|
fn create_call(
|
||||||
|
&self,
|
||||||
|
properties: std::collections::HashMap<&str, zbus::zvariant::Value<'_>>,
|
||||||
|
) -> zbus::Result<zbus::zvariant::OwnedObjectPath>;
|
||||||
|
|
||||||
|
/// DeleteCall method
|
||||||
|
fn delete_call(&self, path: &zbus::zvariant::ObjectPath<'_>) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// HangupAll method
|
||||||
|
fn hangup_all(&self) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// HangupAndAccept method
|
||||||
|
fn hangup_and_accept(&self) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// HoldAndAccept method
|
||||||
|
fn hold_and_accept(&self) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// ListCalls method
|
||||||
|
fn list_calls(&self) -> zbus::Result<Vec<zbus::zvariant::OwnedObjectPath>>;
|
||||||
|
|
||||||
|
/// Transfer method
|
||||||
|
fn transfer(&self) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// CallAdded signal
|
||||||
|
#[dbus_proxy(signal)]
|
||||||
|
fn call_added(&self, path: zbus::zvariant::ObjectPath<'_>) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// CallDeleted signal
|
||||||
|
#[dbus_proxy(signal)]
|
||||||
|
fn call_deleted(&self, path: zbus::zvariant::ObjectPath<'_>) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// Calls property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn calls(&self) -> zbus::Result<Vec<zbus::zvariant::OwnedObjectPath>>;
|
||||||
|
|
||||||
|
/// EmergencyOnly property
|
||||||
|
#[dbus_proxy(property)]
|
||||||
|
fn emergency_only(&self) -> zbus::Result<bool>;
|
||||||
|
}
|
116
src/modem/mod.rs
Normal file
116
src/modem/mod.rs
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
// Copyright (C) 2022 Maxime “pep” Buquet <pep@bouah.net>
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Affero General Public License as published by the
|
||||||
|
// Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
// option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
|
||||||
|
// for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
mod introspect;
|
||||||
|
|
||||||
|
use crate::error::Error;
|
||||||
|
use crate::modem::introspect::ModemProxy;
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
use futures::future::join_all;
|
||||||
|
use zbus::{fdo::ObjectManagerProxy, zvariant::ObjectPath, Connection};
|
||||||
|
|
||||||
|
const MM_NAME: &str = "org.freedesktop.ModemManager1";
|
||||||
|
const MM_PATH: &str = "/org/freedesktop/ModemManager1";
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ModemManager<'a> {
|
||||||
|
connection: Connection,
|
||||||
|
modems: Vec<Modem<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ModemManager<'a> {
|
||||||
|
pub async fn connect() -> Result<ModemManager<'a>, Error> {
|
||||||
|
let connection = Connection::system().await?;
|
||||||
|
Ok(ModemManager {
|
||||||
|
modems: ModemManager::modems(&connection).await?,
|
||||||
|
connection,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn modems(conn: &Connection) -> Result<Vec<Modem<'a>>, Error> {
|
||||||
|
let proxy = ObjectManagerProxy::builder(&conn)
|
||||||
|
.destination(MM_NAME)?
|
||||||
|
.path(MM_PATH)?
|
||||||
|
.build()
|
||||||
|
.await?;
|
||||||
|
let modems = proxy
|
||||||
|
.get_managed_objects()
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.map(|(path, _)| Modem::new(&conn, path.into()))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
join_all(modems)
|
||||||
|
.await
|
||||||
|
.into_iter()
|
||||||
|
.try_fold(vec![], |mut acc, res| {
|
||||||
|
let modem = res?;
|
||||||
|
acc.push(modem);
|
||||||
|
Ok::<Vec<Modem<'_>>, Error>(acc)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for ModemManager<'_> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("ModemManager")
|
||||||
|
.field("modems", &self.modems)
|
||||||
|
.finish_non_exhaustive()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> IntoIterator for ModemManager<'a> {
|
||||||
|
type Item = Modem<'a>;
|
||||||
|
type IntoIter = std::vec::IntoIter<Self::Item>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.modems.into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Modem<'a>(ModemProxy<'a>);
|
||||||
|
|
||||||
|
impl<'a> Modem<'a> {
|
||||||
|
pub async fn new(conn: &Connection, path: ObjectPath<'a>) -> Result<Modem<'a>, Error> {
|
||||||
|
Ok(Modem(ModemProxy::builder(&conn).path(path)?.build().await?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Deref for Modem<'a> {
|
||||||
|
type Target = ModemProxy<'a>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DerefMut for Modem<'a> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Modem<'_> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("Modem")
|
||||||
|
.field("destination", &self.inner().destination())
|
||||||
|
.field("path", &self.inner().path())
|
||||||
|
.field("interface", &self.inner().interface())
|
||||||
|
.finish_non_exhaustive()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue