use crate::{Error, Result, ReturnCode};
use phidget_sys as ffi;
use std::ffi::{c_char, c_int, c_void, CStr, CString};
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(u32)]
#[allow(missing_docs)]
pub enum ServerType {
#[default]
None = ffi::PhidgetServerType_PHIDGETSERVER_NONE, DeviceListener = ffi::PhidgetServerType_PHIDGETSERVER_DEVICELISTENER, Device = ffi::PhidgetServerType_PHIDGETSERVER_DEVICE, DeviceRemote = ffi::PhidgetServerType_PHIDGETSERVER_DEVICEREMOTE, WwwListener = ffi::PhidgetServerType_PHIDGETSERVER_WWWLISTENER, Www = ffi::PhidgetServerType_PHIDGETSERVER_WWW, WwwRemote = ffi::PhidgetServerType_PHIDGETSERVER_WWWREMOTE, Sbc = ffi::PhidgetServerType_PHIDGETSERVER_SBC, }
impl TryFrom<u32> for ServerType {
type Error = Error;
fn try_from(val: u32) -> Result<Self> {
use ServerType::*;
match val {
ffi::PhidgetServerType_PHIDGETSERVER_NONE => Ok(None), ffi::PhidgetServerType_PHIDGETSERVER_DEVICELISTENER => Ok(DeviceListener), ffi::PhidgetServerType_PHIDGETSERVER_DEVICE => Ok(Device), ffi::PhidgetServerType_PHIDGETSERVER_DEVICEREMOTE => Ok(DeviceRemote), ffi::PhidgetServerType_PHIDGETSERVER_WWWLISTENER => Ok(WwwListener), ffi::PhidgetServerType_PHIDGETSERVER_WWW => Ok(Www), ffi::PhidgetServerType_PHIDGETSERVER_WWWREMOTE => Ok(WwwRemote), ffi::PhidgetServerType_PHIDGETSERVER_SBC => Ok(Sbc), _ => Err(ReturnCode::InvalidArg),
}
}
}
fn ptr_to_string(p: *const c_char) -> std::result::Result<String, std::str::Utf8Error> {
let s = unsafe {
match p.as_ref() {
Some(s) => CStr::from_ptr(s).to_str()?.to_owned(),
None => String::new(),
}
};
Ok(s)
}
#[derive(Default, Debug, Clone)]
pub struct Server {
pub name: String,
pub typ: ServerType,
pub flags: u32,
pub addr: String,
pub host: String,
pub port: u16,
}
impl TryFrom<&ffi::PhidgetServer> for Server {
type Error = Error;
fn try_from(srvr: &ffi::PhidgetServer) -> Result<Self> {
let name = ptr_to_string(srvr.name)?;
let typ = ServerType::try_from(srvr.type_)?;
let flags = srvr.flags as u32;
let addr = ptr_to_string(srvr.addr)?;
let host = ptr_to_string(srvr.host)?;
let port = srvr.port as u16;
Ok(Self {
name,
typ,
flags,
addr,
host,
port,
})
}
}
pub fn add_server(server_name: &str, address: &str, port: i32, password: &str) -> Result<()> {
let server_name = CString::new(server_name).unwrap();
let address = CString::new(address).unwrap();
let password = CString::new(password).unwrap();
ReturnCode::result(unsafe {
ffi::PhidgetNet_addServer(
server_name.as_ptr(),
address.as_ptr(),
port as c_int,
password.as_ptr(),
0 as c_int, )
})
}
pub fn remove_server(server_name: &str) -> Result<()> {
let server_name = CString::new(server_name).unwrap();
ReturnCode::result(unsafe { ffi::PhidgetNet_removeServer(server_name.as_ptr()) })
}
pub fn remove_all_servers() -> Result<()> {
ReturnCode::result(unsafe { ffi::PhidgetNet_removeAllServers() })
}
pub fn enable_server(server_name: &str) -> Result<()> {
let server_name = CString::new(server_name).unwrap();
ReturnCode::result(unsafe { ffi::PhidgetNet_enableServer(server_name.as_ptr()) })
}
pub fn disable_server(server_name: &str) -> Result<()> {
let server_name = CString::new(server_name).unwrap();
ReturnCode::result(unsafe {
ffi::PhidgetNet_disableServer(server_name.as_ptr(), 0 as c_int)
})
}
pub fn set_server_passward(server_name: &str, password: &str) -> Result<()> {
let server_name = CString::new(server_name).unwrap();
let password = CString::new(password).unwrap();
ReturnCode::result(unsafe {
ffi::PhidgetNet_setServerPassword(server_name.as_ptr(), password.as_ptr())
})
}
pub fn enable_server_discovery(server_type: ServerType) -> Result<()> {
ReturnCode::result(unsafe {
ffi::PhidgetNet_enableServerDiscovery(server_type as ffi::PhidgetServerType)
})
}
pub fn disable_server_discovery(server_type: ServerType) -> Result<()> {
ReturnCode::result(unsafe {
ffi::PhidgetNet_disableServerDiscovery(server_type as ffi::PhidgetServerType)
})
}
pub type ServerAddedCallback = dyn Fn(Server) + Send + 'static;
pub type ServerRemovedCallback = dyn Fn(Server) + Send + 'static;
unsafe extern "C" fn on_server_added(
ctx: *mut c_void,
srvr: ffi::PhidgetServerHandle,
_kv: *mut c_void,
) {
if ctx.is_null() {
return;
}
let cb: &mut Box<ServerAddedCallback> = &mut *(ctx as *mut _);
let srvr = srvr
.as_ref()
.and_then(|s| Server::try_from(s).ok())
.unwrap_or_default();
cb(srvr);
}
pub fn set_on_server_added_handler<F>(cb: F) -> Result<()>
where
F: Fn(Server) + Send + 'static,
{
let cb: Box<Box<ServerAddedCallback>> = Box::new(Box::new(cb));
let ctx = Box::into_raw(cb) as *mut c_void;
ReturnCode::result(unsafe {
ffi::PhidgetNet_setOnServerAddedHandler(Some(on_server_added), ctx)
})
}
unsafe extern "C" fn on_server_removed(ctx: *mut c_void, srvr: ffi::PhidgetServerHandle) {
if ctx.is_null() {
return;
}
let cb: &mut Box<ServerRemovedCallback> = &mut *(ctx as *mut _);
let srvr = srvr
.as_ref()
.and_then(|s| Server::try_from(s).ok())
.unwrap_or_default();
cb(srvr);
}
pub fn set_on_server_removed_handler<F>(cb: F) -> Result<()>
where
F: Fn(Server) + Send + 'static,
{
let cb: Box<Box<ServerRemovedCallback>> = Box::new(Box::new(cb));
let ctx = Box::into_raw(cb) as *mut c_void;
ReturnCode::result(unsafe {
ffi::PhidgetNet_setOnServerRemovedHandler(Some(on_server_removed), ctx)
})
}