use std::{collections::HashMap, net::SocketAddr, sync::Arc};
use super::model::{PointAddress, PointValue};
use crate::{asdu::Asdu, server::ConnectionId, types::InformationObjects, types_id::TypeId};
#[derive(Debug)]
pub struct CommandContext<'a> {
pub connection_id: ConnectionId,
pub peer: SocketAddr,
pub asdu: &'a Asdu,
pub model: &'a HashMap<PointAddress, PointValue>,
}
#[derive(Debug, Clone)]
pub struct CommandHandling {
pub negative: bool,
pub reply_type_id: TypeId,
pub reply_information_objects: InformationObjects,
pub apply_updates: Vec<(PointAddress, PointValue)>,
}
#[async_trait::async_trait]
pub trait RtuCommandHandler: Send + Sync {
async fn handle_command(&self, ctx: CommandContext<'_>) -> CommandHandling;
}
#[derive(Debug, Default, Clone, Copy)]
pub struct RejectAllCommands;
#[async_trait::async_trait]
impl RtuCommandHandler for RejectAllCommands {
async fn handle_command(&self, ctx: CommandContext<'_>) -> CommandHandling {
CommandHandling {
negative: true,
reply_type_id: ctx.asdu.type_id,
reply_information_objects: ctx.asdu.information_objects.clone(),
apply_updates: Vec::new(),
}
}
}
pub struct FnCommandHandler<F> {
f: F,
}
impl<F> FnCommandHandler<F> {
pub const fn new(f: F) -> Self {
Self { f }
}
}
#[async_trait::async_trait]
impl<F> RtuCommandHandler for FnCommandHandler<F>
where
F: Fn(CommandContext<'_>) -> CommandHandling + Send + Sync,
{
async fn handle_command(&self, ctx: CommandContext<'_>) -> CommandHandling {
(self.f)(ctx)
}
}
pub fn command_handler_from_fn(
f: impl Fn(CommandContext<'_>) -> CommandHandling + Send + Sync + 'static,
) -> Arc<dyn RtuCommandHandler> {
Arc::new(FnCommandHandler::new(f))
}