dnp3 1.6.0

Rust implementation of DNP3 (IEEE 1815) with idiomatic bindings for C, C++, .NET, and Java
Documentation
use crate::app::{Shutdown, Timeout};
use crate::udp::layer::UdpFactory;
use crate::util::session::{RunError, Session, StopReason};

pub(crate) struct UdpTask {
    pub(crate) session: Session,
    pub(crate) factory: UdpFactory,
    pub(crate) retry_delay: Timeout,
}

enum Delay {
    Yes,
    No,
}

impl UdpTask {
    pub(crate) async fn run(mut self) -> Result<(), Shutdown> {
        loop {
            self.session.wait_for_enabled().await?;
            if let Delay::Yes = self.run_one().await? {
                if let Err(reason) = self.session.wait_for_retry(self.retry_delay.into()).await {
                    Self::handle_stop(reason)?;
                }
            }
        }
    }

    fn handle_stop(reason: StopReason) -> Result<Delay, Shutdown> {
        match reason {
            StopReason::Disable => Ok(Delay::No),
            StopReason::Shutdown => Err(Shutdown),
        }
    }

    async fn run_one(&mut self) -> Result<Delay, Shutdown> {
        match self.factory.open().await {
            Ok(mut phys) => match self.session.run(&mut phys).await {
                RunError::Stop(r) => Self::handle_stop(r),
                RunError::Link(err) => {
                    tracing::warn!("{err}");
                    Ok(Delay::Yes)
                }
            },
            Err(err) => {
                tracing::error!("{err}");
                Ok(Delay::Yes)
            }
        }
    }
}