use std::collections::BTreeMap;
use std::sync::{Arc, Mutex};
use crate::exception::ExceptionCode;
use crate::server::{WriteCoils, WriteRegisters};
use crate::types::*;
pub trait RequestHandler: Send + 'static {
fn wrap(self) -> Arc<Mutex<Box<Self>>>
where
Self: Sized,
{
Arc::new(Mutex::new(Box::new(self)))
}
fn read_coil(&self, _address: u16) -> Result<bool, ExceptionCode> {
Err(ExceptionCode::IllegalFunction)
}
fn read_discrete_input(&self, _address: u16) -> Result<bool, ExceptionCode> {
Err(ExceptionCode::IllegalFunction)
}
fn read_holding_register(&self, _address: u16) -> Result<u16, ExceptionCode> {
Err(ExceptionCode::IllegalFunction)
}
fn read_input_register(&self, _address: u16) -> Result<u16, ExceptionCode> {
Err(ExceptionCode::IllegalFunction)
}
fn write_single_coil(&mut self, _value: Indexed<bool>) -> Result<(), ExceptionCode> {
Err(ExceptionCode::IllegalFunction)
}
fn write_single_register(&mut self, _value: Indexed<u16>) -> Result<(), ExceptionCode> {
Err(ExceptionCode::IllegalFunction)
}
fn write_multiple_coils(&mut self, _values: WriteCoils) -> Result<(), ExceptionCode> {
Err(ExceptionCode::IllegalFunction)
}
fn write_multiple_registers(&mut self, _values: WriteRegisters) -> Result<(), ExceptionCode> {
Err(ExceptionCode::IllegalFunction)
}
}
pub trait IllegalAddressConversion<T> {
fn to_result(self) -> Result<T, ExceptionCode>;
}
impl<T> IllegalAddressConversion<T> for Option<&T>
where
T: Copy,
{
fn to_result(self) -> Result<T, ExceptionCode> {
match self {
None => Err(ExceptionCode::IllegalDataAddress),
Some(x) => Ok(*x),
}
}
}
pub type ServerHandlerType<T> = Arc<Mutex<Box<T>>>;
#[derive(Debug, Default)]
pub struct ServerHandlerMap<T: RequestHandler> {
handlers: BTreeMap<UnitId, ServerHandlerType<T>>,
}
impl<T> Clone for ServerHandlerMap<T>
where
T: RequestHandler,
{
fn clone(&self) -> Self {
ServerHandlerMap {
handlers: self.handlers.clone(),
}
}
}
impl<T> ServerHandlerMap<T>
where
T: RequestHandler,
{
pub fn new() -> Self {
Self {
handlers: BTreeMap::new(),
}
}
pub fn single(id: UnitId, handler: ServerHandlerType<T>) -> Self {
let mut map: BTreeMap<UnitId, ServerHandlerType<T>> = BTreeMap::new();
map.insert(id, handler);
Self { handlers: map }
}
pub fn get(&mut self, id: UnitId) -> Option<&mut ServerHandlerType<T>> {
self.handlers.get_mut(&id)
}
pub fn add(
&mut self,
id: UnitId,
server: ServerHandlerType<T>,
) -> Option<ServerHandlerType<T>> {
self.handlers.insert(id, server)
}
pub(crate) fn iter_mut(&mut self) -> impl Iterator<Item = &mut ServerHandlerType<T>> {
self.handlers.values_mut()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(
feature = "serialization",
derive(serde::Serialize, serde::Deserialize)
)]
pub enum Authorization {
Allow,
Deny,
}
pub trait AuthorizationHandler: Send + Sync + 'static {
fn wrap(self) -> Arc<dyn AuthorizationHandler>
where
Self: Sized,
{
Arc::new(self)
}
fn read_coils(&self, _unit_id: UnitId, _range: AddressRange, _role: &str) -> Authorization {
Authorization::Deny
}
fn read_discrete_inputs(
&self,
_unit_id: UnitId,
_range: AddressRange,
_role: &str,
) -> Authorization {
Authorization::Deny
}
fn read_holding_registers(
&self,
_unit_id: UnitId,
_range: AddressRange,
_role: &str,
) -> Authorization {
Authorization::Deny
}
fn read_input_registers(
&self,
_unit_id: UnitId,
_range: AddressRange,
_role: &str,
) -> Authorization {
Authorization::Deny
}
fn write_single_coil(&self, _unit_id: UnitId, _idx: u16, _role: &str) -> Authorization {
Authorization::Deny
}
fn write_single_register(&self, _unit_id: UnitId, _idx: u16, _role: &str) -> Authorization {
Authorization::Deny
}
fn write_multiple_coils(
&self,
_unit_id: UnitId,
_range: AddressRange,
_role: &str,
) -> Authorization {
Authorization::Deny
}
fn write_multiple_registers(
&self,
_unit_id: UnitId,
_range: AddressRange,
_role: &str,
) -> Authorization {
Authorization::Deny
}
}
#[derive(Debug, Clone, Copy)]
#[cfg_attr(
feature = "serialization",
derive(serde::Serialize, serde::Deserialize)
)]
pub struct ReadOnlyAuthorizationHandler;
impl ReadOnlyAuthorizationHandler {
pub fn create() -> Arc<dyn AuthorizationHandler> {
Arc::new(Self)
}
}
impl AuthorizationHandler for ReadOnlyAuthorizationHandler {
fn read_coils(&self, _unit_id: UnitId, _range: AddressRange, _role: &str) -> Authorization {
Authorization::Allow
}
fn read_discrete_inputs(
&self,
_unit_id: UnitId,
_range: AddressRange,
_role: &str,
) -> Authorization {
Authorization::Allow
}
fn read_holding_registers(
&self,
_unit_id: UnitId,
_range: AddressRange,
_role: &str,
) -> Authorization {
Authorization::Allow
}
fn read_input_registers(
&self,
_unit_id: UnitId,
_range: AddressRange,
_role: &str,
) -> Authorization {
Authorization::Allow
}
fn write_single_coil(&self, _unit_id: UnitId, _idx: u16, _role: &str) -> Authorization {
Authorization::Deny
}
fn write_single_register(&self, _unit_id: UnitId, _idx: u16, _role: &str) -> Authorization {
Authorization::Deny
}
fn write_multiple_coils(
&self,
_unit_id: UnitId,
_range: AddressRange,
_role: &str,
) -> Authorization {
Authorization::Deny
}
fn write_multiple_registers(
&self,
_unit_id: UnitId,
_range: AddressRange,
_role: &str,
) -> Authorization {
Authorization::Deny
}
}
#[cfg(test)]
mod tests {
use super::*;
struct DefaultHandler;
impl RequestHandler for DefaultHandler {}
#[test]
fn default_handler_returns_illegal_function() {
let mut handler = DefaultHandler {};
assert_eq!(handler.read_coil(0), Err(ExceptionCode::IllegalFunction));
assert_eq!(
handler.read_discrete_input(0),
Err(ExceptionCode::IllegalFunction)
);
assert_eq!(
handler.read_holding_register(0),
Err(ExceptionCode::IllegalFunction)
);
assert_eq!(
handler.read_input_register(0),
Err(ExceptionCode::IllegalFunction)
);
assert_eq!(
handler.write_single_coil(Indexed::new(0, true)),
Err(ExceptionCode::IllegalFunction)
);
assert_eq!(
handler.write_single_register(Indexed::new(0, 0)),
Err(ExceptionCode::IllegalFunction)
);
}
#[test]
fn server_handler_map_returns_old_handler_when_already_present() {
let mut map = ServerHandlerMap::new();
assert!(map.add(UnitId::new(1), DefaultHandler {}.wrap()).is_none());
assert!(map.add(UnitId::new(2), DefaultHandler {}.wrap()).is_none());
assert!(map.add(UnitId::new(1), DefaultHandler {}.wrap()).is_some());
}
}