1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
macro_rules! bail { ($err:expr) => { return Err($err.into()) }; } pub mod cmd; mod conn; pub mod dev; mod enc; mod evt; mod room; use std::convert::TryFrom; pub use cmd::SetValuesCommandError; pub use conn::ConnectError; pub use enet_proto::{ItemSetValue, ItemValueRes, SetValue}; use cmd::CommandHandler; use evt::EventHandler; use thiserror::Error; use tokio::net::ToSocketAddrs; use tracing::{event, instrument, Level}; use crate::{ dev::{Device, DeviceDesc}, room::RoomDesc, }; pub struct EnetClient { #[allow(dead_code)] commands: CommandHandler, #[allow(dead_code)] events: EventHandler, #[allow(dead_code)] rooms: Vec<RoomDesc>, devices: Vec<Device>, } impl EnetClient { #[instrument(level = "info", target = "enet-client", skip(addr), err)] pub async fn new<A>(addr: A) -> Result<Self, ClientConnectError> where A: ToSocketAddrs + Clone + Send + Sync + 'static, { let mut commands = CommandHandler::new(addr.clone()).await?; let version = commands.get_version().await?; event!(target: "enet-client", Level::INFO, %version.firmware, %version.hardware, %version.enet, "connected to eNet Gateway"); let channel_types = commands.get_channel_info().await?; let project = commands.get_project().await?; let rooms = project .lists .into_iter() .filter(|l| l.visible) .map(RoomDesc::from) .collect::<Vec<_>>(); let (writers, devices) = project .items .into_iter() .enumerate() .filter(|(idx, _)| channel_types.devices.get(*idx) == Some(&1)) .filter_map(|(idx, item)| DeviceDesc::try_from(item).ok().map(|v| (idx, v))) .map(|(idx, desc)| Device::new(desc, idx as u32)) .unzip(); let devices: Vec<_> = devices; event!(target: "enet-client", Level::INFO, rooms.len = %rooms.len(), devices.len = %devices.len(), "got project info"); let events = EventHandler::new(addr, writers).await?; Ok(Self { commands, events, rooms, devices, }) } pub fn devices(&self) -> &[Device] { &self.devices } pub fn device(&self, number: u32) -> Option<&Device> { self.devices.iter().find(|d| d.number() == number) } pub async fn set_value( &mut self, number: u32, value: SetValue, ) -> Result<ItemValueRes, SetValuesCommandError> { let values = vec![ItemSetValue { number, value }]; self.set_values(values).await } pub async fn set_values( &mut self, values: impl IntoIterator<Item = ItemSetValue>, ) -> Result<ItemValueRes, SetValuesCommandError> { self.commands.set_values(values.into_iter().collect()).await } } #[non_exhaustive] #[derive(Debug, Error)] #[error("Failed to connect to gateway.")] pub enum ClientConnectError { Connect(#[from] ConnectError), GetVersionCommand(#[from] cmd::GetVersionCommandError), GetChannelInfoCommand(#[from] cmd::GetChannelInfoCommandError), GetProjectCommand(#[from] cmd::GetProjectCommandError), }