#[macro_use]
extern crate serde_derive;
use std::fmt::Debug;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::sync::{Arc, Mutex};
use std::thread;
use uuid::Uuid;
use crate::ssdp::SsdpListener;
use crate::upnp::*;
use crate::virtual_device::wrappers::*;
use crate::virtual_device::*;
mod ssdp;
mod upnp;
pub mod virtual_device;
#[derive(Clone)]
pub(crate) struct RustmoDevice {
pub(crate) name: String,
pub(crate) ip_address: IpAddr,
pub(crate) port: u16,
pub(crate) uuid: Uuid,
pub(crate) virtual_device: WrappedVirtualDevice,
}
impl RustmoDevice {
pub fn new<T: VirtualDevice>(
name: &str,
ip_address: IpAddr,
port: u16,
virtual_device: T,
) -> Self {
let mut bytes = Vec::from(name.as_bytes());
while bytes.len() < 16 {
bytes.push(bytes.len() as u8);
}
while bytes.len() > 16 {
bytes.pop();
}
let device = RustmoDevice {
name: name.to_string(),
ip_address,
port,
uuid: Uuid::from_slice(bytes.as_slice())
.expect("failed to generate UUID"),
virtual_device: Arc::new(Mutex::new(Box::new(virtual_device))),
};
let cloned = device.clone();
thread::spawn(move || {
let server = hyper::Server::http(SocketAddr::new(ip_address, port)).unwrap();
server.handle(DeviceHttpServerHandler::new(cloned)).unwrap();
});
device
}
}
pub struct RustmoServer {
devices: Arc<Mutex<Vec<RustmoDevice>>>,
ip_address: Ipv4Addr,
ssdp_listener: SsdpListener,
}
#[derive(Debug)]
pub enum RustmoError {
DeviceAlreadyExistsOnPort(u16),
DeviceAlreadyExistsByName(String),
}
impl RustmoServer {
pub fn new(interface: Ipv4Addr) -> Self {
let devices = Arc::new(Mutex::new(Vec::new()));
RustmoServer {
devices: devices.clone(),
ip_address: interface,
ssdp_listener: SsdpListener::listen(interface, devices),
}
}
pub fn add_device<T: VirtualDevice>(
&mut self,
name: &str,
port: u16,
virtual_device: T,
) -> Result<WrappedVirtualDevice, RustmoError> {
self.internal_add_device(name, IpAddr::V4(self.ip_address), port, virtual_device)
}
pub fn add_polling_device<T: VirtualDevice>(
&mut self,
name: &str,
port: u16,
virtual_device: T,
) -> Result<WrappedVirtualDevice, RustmoError> {
self.internal_add_device(
name,
IpAddr::V4(self.ip_address),
port,
PollingDevice {
device: Box::new(virtual_device),
},
)
}
pub fn add_instant_on_device<T: VirtualDevice>(
&mut self,
name: &str,
port: u16,
virtual_device: T,
) -> Result<WrappedVirtualDevice, RustmoError> {
self.internal_add_device(
name,
IpAddr::V4(self.ip_address),
port,
InstantOnDevice {
device: Box::new(virtual_device),
instant: false,
},
)
}
pub fn add_functional_device<TurnOn, TurnOff, CheckIsOn>(
&mut self,
name: &str,
port: u16,
turn_on: TurnOn,
turn_off: TurnOff,
check_is_on: CheckIsOn,
) -> Result<WrappedVirtualDevice, RustmoError>
where
TurnOn: FnMut() -> Result<VirtualDeviceState, VirtualDeviceError> + Sync + Send + 'static,
TurnOff: FnMut() -> Result<VirtualDeviceState, VirtualDeviceError> + Sync + Send + 'static,
CheckIsOn:
FnMut() -> Result<VirtualDeviceState, VirtualDeviceError> + Sync + Send + 'static,
{
self.internal_add_device(
name,
IpAddr::V4(self.ip_address),
port,
FunctionalDevice {
turn_on,
turn_off,
check_is_on,
},
)
}
pub fn add_device_group(
&mut self,
name: &str,
port: u16,
devices: Vec<WrappedVirtualDevice>,
) -> Result<WrappedVirtualDevice, RustmoError> {
self.internal_add_device(
name,
IpAddr::V4(self.ip_address),
port,
CompositeDevice { devices },
)
}
fn internal_add_device<T: VirtualDevice>(
&mut self,
name: &str,
ip_address: IpAddr,
port: u16,
virtual_device: T,
) -> Result<WrappedVirtualDevice, RustmoError> {
let mut device_list = self.devices.lock().unwrap();
for existing_device in device_list.iter() {
if existing_device.port == port {
return Err(RustmoError::DeviceAlreadyExistsOnPort(port));
} else if existing_device.name.to_lowercase().eq(&name.to_lowercase()) {
return Err(RustmoError::DeviceAlreadyExistsByName(name.to_string()));
}
}
let device = RustmoDevice::new(name, ip_address, port, virtual_device);
let wrapped_device = device.virtual_device.clone();
device_list.push(device);
Ok(wrapped_device)
}
}
impl Drop for RustmoServer {
fn drop(&mut self) {
self.ssdp_listener.stop()
}
}