Implement ModemAccess for nonblock::Proxy
Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>
This commit is contained in:
parent
8039503df9
commit
a3647c2af2
4 changed files with 91 additions and 165 deletions
|
@ -7,6 +7,7 @@ edition = "2021"
|
|||
categories = ["gateway", "bridge", "transport", "modemmanager"]
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1.56"
|
||||
mmdbus = "1.18.6"
|
||||
dbus-tokio = "0.7.5"
|
||||
tokio = { version = "1.19.2", features = [ "time", "macros", "rt-multi-thread" ] }
|
||||
|
|
197
src/main.rs
197
src/main.rs
|
@ -13,10 +13,12 @@
|
|||
// 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::collections::HashMap;
|
||||
use std::error::Error as StdError;
|
||||
pub mod mm;
|
||||
use mm::modem::Modem as ModemAccess;
|
||||
|
||||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
|
||||
use tokio::{
|
||||
task::JoinHandle,
|
||||
time::Duration,
|
||||
|
@ -24,16 +26,13 @@ use tokio::{
|
|||
|
||||
use mmdbus::{
|
||||
dbus::{
|
||||
arg::{PropMap, RefArg, Variant},
|
||||
nonblock::{SyncConnection, stdintf::org_freedesktop_dbus::ObjectManager, Proxy},
|
||||
// channel::MatchingReceiver,
|
||||
// message::{MatchRule, Message},
|
||||
strings::{Path as DBusPath}, // Interface, Member,
|
||||
// Error as DBusError,
|
||||
nonblock::{
|
||||
SyncConnection, Proxy,
|
||||
stdintf::org_freedesktop_dbus::ObjectManager,
|
||||
},
|
||||
strings::{Path as DBusPath},
|
||||
Error as DBusError,
|
||||
},
|
||||
modem::Modem as ModemAccess,
|
||||
modem_messaging::ModemMessaging,
|
||||
sms::Sms as SmsAccess,
|
||||
};
|
||||
|
||||
use dbus_tokio::connection;
|
||||
|
@ -44,7 +43,6 @@ use dbus_tokio::connection;
|
|||
const MM_NAME: &str = "org.freedesktop.ModemManager1";
|
||||
const MM_PATH: &str = "/org/freedesktop/ModemManager1";
|
||||
const TIMEOUT: Duration = Duration::from_secs(5);
|
||||
const SMSC: &str = "+33609001390"; // SFR
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DBus {
|
||||
|
@ -53,7 +51,7 @@ pub struct DBus {
|
|||
}
|
||||
|
||||
impl DBus {
|
||||
pub fn connect() -> Result<Self, Box<dyn StdError>> {
|
||||
pub fn connect() -> Result<Self, DBusError> {
|
||||
let (resource, conn) = connection::new_system_sync()?;
|
||||
|
||||
let handle: JoinHandle<()> = tokio::spawn(async {
|
||||
|
@ -78,22 +76,26 @@ pub struct ModemManager {
|
|||
}
|
||||
|
||||
impl ModemManager {
|
||||
pub fn connect() -> Result<Self, Box<dyn StdError>> {
|
||||
Ok(DBus::connect().map(|dbus| Self { dbus })?)
|
||||
pub fn connect() -> Result<Self, DBusError> {
|
||||
DBus::connect().map(|dbus| Self { dbus })
|
||||
}
|
||||
|
||||
pub async fn modems(&self) -> Result<Vec<DBusPath<'static>>, Box<dyn StdError>> {
|
||||
pub async fn modems(&self) -> Result<Vec<Modem>, DBusError> {
|
||||
let objects = self.dbus.proxy(MM_PATH).get_managed_objects().await?;
|
||||
let modems = objects
|
||||
.into_iter()
|
||||
.map(|(path, _)| path )
|
||||
.map(|(path, _)| {
|
||||
Modem {
|
||||
dbus: self.dbus.clone(),
|
||||
path,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(modems)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#[derive(Clone)]
|
||||
pub struct Modem {
|
||||
dbus: DBus,
|
||||
|
@ -102,14 +104,13 @@ pub struct Modem {
|
|||
|
||||
impl fmt::Debug for Modem {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let numbers = self.own_numbers().unwrap_or(vec![String::new()]);
|
||||
write!(f, "Modem {{ {}, {:?}, .. }}", self.path, numbers)
|
||||
write!(f, "Modem {{ {}, {:?}, .. }}", self.path, "1234")
|
||||
}
|
||||
}
|
||||
|
||||
impl Modem {
|
||||
pub fn enabled(&self) -> Result<bool, Box<dyn StdError>> {
|
||||
let state: ModemState = ModemAccess::state(&self.dbus.proxy(&self.path)).map(Into::into)?;
|
||||
pub async fn enabled(&self) -> Result<bool, DBusError> {
|
||||
let state: ModemState = ModemAccess::state(&self.dbus.proxy(&self.path)).await.map(Into::into)?;
|
||||
Ok(match state {
|
||||
ModemState::Enabling
|
||||
| ModemState::Enabled
|
||||
|
@ -121,38 +122,9 @@ impl Modem {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn model(&self) -> Result<String, Box<dyn StdError>> {
|
||||
Ok(ModemAccess::model(&self.dbus.proxy(&self.path))?)
|
||||
pub async fn model(&self) -> Result<String, DBusError> {
|
||||
ModemAccess::model(&self.dbus.proxy(&self.path)).await
|
||||
}
|
||||
|
||||
pub fn manufacturer(&self) -> Result<String, Box<dyn StdError>> {
|
||||
Ok(ModemAccess::manufacturer(&self.dbus.proxy(&self.path))?)
|
||||
}
|
||||
|
||||
pub fn own_numbers(&self) -> Result<Vec<String>, Box<dyn StdError>> {
|
||||
Ok(ModemAccess::own_numbers(&self.dbus.proxy(&self.path))?)
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn list_sms(&self) -> Result<Vec<Sms>, Box<dyn StdError>> {
|
||||
Ok(ModemMessaging::list(&self.dbus.proxy(&self.path))?
|
||||
.into_iter()
|
||||
.map(|p| Sms {
|
||||
dbus: self.dbus.clone(),
|
||||
modem: self.clone(),
|
||||
path: p,
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub fn create_sms(&self, number: String, text: String) -> Result<Sms, Box<dyn StdError>> {
|
||||
Sms::new(self, number, text)
|
||||
}
|
||||
|
||||
pub fn delete_sms(&self, path: DBusPath) -> Result<(), Box<dyn StdError>> {
|
||||
Ok(ModemMessaging::delete(&self.dbus.proxy(&self.path), path)?)
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
#[repr(i32)]
|
||||
|
@ -203,122 +175,17 @@ impl From<i32> for ModemState {
|
|||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
// include/ModemManager-enums.h MMSmsState
|
||||
/// State of a given SMS.
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum SmsState {
|
||||
/// State unknown or not reportable.
|
||||
Unknown = 0,
|
||||
/// The message has been neither received not yet sent.
|
||||
Stored = 1,
|
||||
/// The message is being received but is not yet complete.
|
||||
Receiving = 2,
|
||||
/// The message has been completely received.
|
||||
Received = 3,
|
||||
/// The message is queued for delivery.
|
||||
Sending = 4,
|
||||
/// The message was successfully sent.
|
||||
Sent = 5,
|
||||
}
|
||||
|
||||
impl fmt::Display for SmsState {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", match self {
|
||||
SmsState::Unknown => "unknown",
|
||||
SmsState::Stored => "stored",
|
||||
SmsState::Receiving => "receiving",
|
||||
SmsState::Received => "received",
|
||||
SmsState::Sending => "sending",
|
||||
SmsState::Sent => "sent",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for SmsState {
|
||||
fn from(num: u32) -> Self {
|
||||
if num > 5 {
|
||||
Self::Unknown
|
||||
} else {
|
||||
unsafe { *(&num as *const u32 as *const Self) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Sms {
|
||||
dbus: DBus,
|
||||
modem: Modem,
|
||||
path: DBusPath<'static>,
|
||||
}
|
||||
|
||||
impl Sms {
|
||||
pub fn new(modem: &Modem, number: String, text: String) -> Result<Sms, Box<dyn StdError>> {
|
||||
let props: PropMap = {
|
||||
let mut tmp = HashMap::new();
|
||||
tmp.insert(
|
||||
String::from("number"),
|
||||
Variant(Box::new(number) as Box<dyn RefArg>),
|
||||
);
|
||||
tmp.insert(
|
||||
String::from("text"),
|
||||
Variant(Box::new(text) as Box<dyn RefArg>),
|
||||
);
|
||||
tmp.insert(
|
||||
String::from("smsc"),
|
||||
Variant(Box::new(String::from(SMSC)) as Box<dyn RefArg>),
|
||||
);
|
||||
tmp
|
||||
};
|
||||
let path = ModemMessaging::create(&modem.dbus.proxy(&modem.path), props)?;
|
||||
Ok(Sms {
|
||||
dbus: modem.dbus.clone(),
|
||||
modem: modem.clone(),
|
||||
path: path,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn state(&self) -> Result<SmsState, Box<dyn StdError>> {
|
||||
Ok(SmsAccess::state(&self.dbus.proxy(&self.path)).map(Into::into)?)
|
||||
}
|
||||
|
||||
pub fn send(&self) -> Result<(), Box<dyn StdError>> {
|
||||
Ok(SmsAccess::send(&self.dbus.proxy(&self.path))?)
|
||||
}
|
||||
|
||||
pub fn number(&self) -> Result<String, Box<dyn StdError>> {
|
||||
Ok(SmsAccess::number(&self.dbus.proxy(&self.path))?)
|
||||
}
|
||||
|
||||
pub fn text(&self) -> Result<String, Box<dyn StdError>> {
|
||||
Ok(SmsAccess::text(&self.dbus.proxy(&self.path))?)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Sms {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let state = self.state().unwrap_or(SmsState::Unknown);
|
||||
write!(f, "Sms ({}) {{ {}, {:?}, .. }}", state, self.path, self.modem)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Sms {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let state = self.state().unwrap_or(SmsState::Unknown);
|
||||
let number = self.number().unwrap_or(String::new());
|
||||
let text = self.text().unwrap_or(String::new());
|
||||
write!(f, "Sms ({}) {{ number: {}, text: {} }}", state, number, text)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn StdError>> {
|
||||
let modems = ModemManager::connect()?.modems().await;
|
||||
async fn main() -> Result<(), DBusError> {
|
||||
let modems = ModemManager::connect()?.modems().await?;
|
||||
println!("Modems: {:?}", modems);
|
||||
|
||||
for modem in modems {
|
||||
println!("Modem: {:?}", modem);
|
||||
println!("Enabled: {:?}", modem.enabled().await);
|
||||
println!("Model: {:?}", modem.model().await);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
16
src/mm/mod.rs
Normal file
16
src/mm/mod.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
// 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;
|
42
src/mm/modem.rs
Normal file
42
src/mm/modem.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
// 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
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue