diff --git a/dnp3/examples/master.rs b/dnp3/examples/master.rs index 62e2e297..7067f517 100644 --- a/dnp3/examples/master.rs +++ b/dnp3/examples/master.rs @@ -243,37 +243,7 @@ async fn main() -> Result<(), Box> { // ANCHOR_END: logging // spawn the master channel based on the command line argument - let mut channel = create_channel()?; - - let mut association = match channel.get_channel_type() { - MasterChannelType::Udp => { - // ANCHOR: association_create_udp - channel - .add_udp_association( - EndpointAddress::try_new(1024)?, - "127.0.0.1:20000".parse()?, - get_association_config(), - ExampleReadHandler::boxed(), - Box::new(ExampleAssociationHandler), - Box::new(ExampleAssociationInformation), - ) - .await? - // ANCHOR_END: association_create_udp - } - MasterChannelType::Stream => { - // ANCHOR: association_create - channel - .add_association( - EndpointAddress::try_new(1024)?, - get_association_config(), - ExampleReadHandler::boxed(), - Box::new(ExampleAssociationHandler), - Box::new(ExampleAssociationInformation), - ) - .await? - // ANCHOR_END: association_create - } - }; + let (mut channel, mut association) = create_channel_and_association().await?; // create an event poll // ANCHOR: add_poll @@ -497,7 +467,8 @@ impl CliHandler { } // create the specified channel based on the command line argument -fn create_channel() -> Result> { +async fn create_channel_and_association( +) -> Result<(MasterChannel, AssociationHandle), Box> { let args: Vec = std::env::args().collect(); let transport: &str = match args.as_slice() { [_, x] => x, @@ -508,14 +479,34 @@ fn create_channel() -> Result> { } }; match transport { - "tcp" => create_tcp_channel(), - "udp" => create_udp_channel(), + "tcp" => { + let mut channel = create_tcp_channel()?; + let assoc = add_association(&mut channel).await?; + Ok((channel, assoc)) + } + "udp" => { + let mut channel = create_udp_channel()?; + let assoc = add_udp_association(&mut channel).await?; + Ok((channel, assoc)) + } #[cfg(feature = "serial")] - "serial" => create_serial_channel(), + "serial" => { + let mut channel = create_serial_channel()?; + let assoc = add_association(&mut channel).await?; + Ok((channel, assoc)) + } #[cfg(feature = "tls")] - "tls-ca" => create_tls_channel(get_tls_authority_config()?), + "tls-ca" => { + let mut channel = create_tls_channel(get_tls_authority_config()?)?; + let assoc = add_association(&mut channel).await?; + Ok((channel, assoc)) + } #[cfg(feature = "tls")] - "tls-self-signed" => create_tls_channel(get_tls_self_signed_config()?), + "tls-self-signed" => { + let mut channel = create_tls_channel(get_tls_self_signed_config()?)?; + let assoc = add_association(&mut channel).await?; + Ok((channel, assoc)) + } _ => { eprintln!( "unknown transport '{}', options are (tcp, serial, tls-ca, tls-self-signed)", @@ -526,6 +517,41 @@ fn create_channel() -> Result> { } } +async fn add_association( + channel: &mut MasterChannel, +) -> Result> { + // ANCHOR: association_create + let association = channel + .add_association( + EndpointAddress::try_new(1024)?, + get_association_config(), + ExampleReadHandler::boxed(), + Box::new(ExampleAssociationHandler), + Box::new(ExampleAssociationInformation), + ) + .await?; + // ANCHOR_END: association_create + Ok(association) +} + +async fn add_udp_association( + channel: &mut MasterChannel, +) -> Result> { + // ANCHOR: association_create_udp + let association = channel + .add_udp_association( + EndpointAddress::try_new(1024)?, + "127.0.0.1:20000".parse()?, + get_association_config(), + ExampleReadHandler::boxed(), + Box::new(ExampleAssociationHandler), + Box::new(ExampleAssociationInformation), + ) + .await?; + // ANCHOR_END: association_create_udp + Ok(association) +} + // ANCHOR: master_channel_config fn get_master_channel_config() -> Result> { let mut config = MasterChannelConfig::new(EndpointAddress::try_new(1)?); diff --git a/dnp3/src/master/association.rs b/dnp3/src/master/association.rs index 0987a84f..5cebffdd 100644 --- a/dnp3/src/master/association.rs +++ b/dnp3/src/master/association.rs @@ -11,7 +11,7 @@ use crate::app::{Sequence, Timeout}; use crate::link::EndpointAddress; use crate::master::error::{AssociationError, TaskError, TimeSyncError}; use crate::master::extract::extract_measurements; -use crate::master::handler::{AssociationHandler, Promise}; +use crate::master::handler::AssociationHandler; use crate::master::messages::AssociationMsgType; use crate::master::poll::{PollHandle, PollMap, PollMsg}; use crate::master::request::{Classes, EventClasses, TimeSyncProcedure}; @@ -22,6 +22,7 @@ use crate::master::tasks::{AppTask, AssociationTask, ReadTask, Task}; use crate::master::{AssociationInformation, ReadHandler, ReadType, TaskType}; use crate::util::Smallest; +use crate::master::promise::Promise; use crate::transport::FragmentAddr; use crate::util::session::RunError; use tokio::time::Instant; diff --git a/dnp3/src/master/extract.rs b/dnp3/src/master/extract.rs index 4d6b8f57..22651094 100644 --- a/dnp3/src/master/extract.rs +++ b/dnp3/src/master/extract.rs @@ -3,7 +3,7 @@ use crate::app::measurement::*; use crate::app::parse::parser::{HeaderCollection, HeaderDetails, ObjectHeader}; use crate::app::variations::*; use crate::app::ResponseHeader; -use crate::master::handler::ReadHandler; +use crate::master::ReadHandler; use crate::master::ReadType; /// Extract measurements from a HeaderCollection, sinking them into @@ -91,7 +91,7 @@ mod test { use crate::app::control::CommandStatus; use crate::app::parse::parser::HeaderCollection; use crate::app::*; - use crate::master::handler::{HeaderInfo, ReadHandler}; + use crate::master::{HeaderInfo, ReadHandler}; use super::*; diff --git a/dnp3/src/master/handler.rs b/dnp3/src/master/handler.rs index 6cf00f40..94daf00a 100644 --- a/dnp3/src/master/handler.rs +++ b/dnp3/src/master/handler.rs @@ -1,8 +1,6 @@ use std::net::SocketAddr; use std::time::{Duration, SystemTime}; -use crate::app::attr::*; -use crate::app::measurement::*; use crate::app::*; use crate::decode::DecodeLevel; @@ -11,6 +9,7 @@ use crate::master::association::AssociationConfig; use crate::master::error::{AssociationError, CommandError, PollError, TaskError, TimeSyncError}; use crate::master::messages::{AssociationMsg, AssociationMsgType, MasterMsg, Message}; use crate::master::poll::{PollHandle, PollMsg}; +use crate::master::promise::Promise; use crate::master::request::{CommandHeaders, CommandMode, ReadRequest, TimeSyncProcedure}; use crate::master::tasks::command::CommandTask; use crate::master::tasks::deadbands::WriteDeadBandsTask; @@ -28,7 +27,7 @@ use crate::master::tasks::time::TimeSyncTask; use crate::master::tasks::Task; use crate::master::{ AuthKey, BlockNumber, DeadBandHeader, DirReadConfig, FileCredentials, FileError, FileHandle, - FileInfo, FileMode, FileReadConfig, FileReader, Headers, OpenFile, WriteError, + FileInfo, FileMode, FileReadConfig, FileReader, Headers, OpenFile, ReadHandler, WriteError, }; use crate::transport::FragmentAddr; use crate::util::channel::Sender; @@ -37,6 +36,7 @@ use crate::util::session::Enabled; /// Master channels may be Udp or of a "stream" type such as TCP #[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[non_exhaustive] pub enum MasterChannelType { /// UDP aka datagram based Udp, @@ -106,11 +106,6 @@ impl MasterChannel { } } - /// retrieve the channel type - pub fn get_channel_type(&self) -> MasterChannelType { - self.channel_type - } - /// enable communications pub async fn enable(&mut self) -> Result<(), Shutdown> { self.send_master_message(MasterMsg::EnableCommunication(Enabled::Yes)) @@ -532,32 +527,6 @@ impl AssociationHandle { } } -/// A generic callback type that must be invoked once and only once. -/// The user can select to implement it using FnOnce or a -/// one-shot reply channel -pub(crate) enum Promise { - /// nothing happens when the promise is completed - None, - /// one-shot reply channel is consumed when the promise is completed - OneShot(tokio::sync::oneshot::Sender), -} - -impl Promise { - pub(crate) fn one_shot() -> (Self, tokio::sync::oneshot::Receiver) { - let (tx, rx) = tokio::sync::oneshot::channel(); - (Self::OneShot(tx), rx) - } - - pub(crate) fn complete(self, value: T) { - match self { - Promise::None => {} - Promise::OneShot(s) => { - s.send(value).ok(); - } - } - } -} - /// Task types used in [`AssociationInformation`] #[cfg_attr(not(feature = "ffi"), non_exhaustive)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] @@ -621,196 +590,3 @@ pub trait AssociationInformation: Send + Sync { /// Called when an unsolicited response is received fn unsolicited_response(&mut self, _is_duplicate: bool, _seq: Sequence) {} } - -/// Information about the object header and specific variation -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct HeaderInfo { - /// underlying variation in the response - pub variation: Variation, - /// qualifier code used in the response - pub qualifier: QualifierCode, - /// true if the received variation is an event type, false otherwise - pub is_event: bool, - /// true if a flags byte is present on the underlying variation, false otherwise - pub has_flags: bool, -} - -impl HeaderInfo { - pub(crate) fn new( - variation: Variation, - qualifier: QualifierCode, - is_event: bool, - has_flags: bool, - ) -> Self { - Self { - variation, - qualifier, - is_event, - has_flags, - } - } -} - -/// Describes the source of a read event -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum ReadType { - /// Startup integrity poll - StartupIntegrity, - /// Unsolicited message - Unsolicited, - /// Single poll requested by the user - SinglePoll, - /// Periodic poll configured by the user - PeriodicPoll, -} - -/// Trait used to process measurement data received from an outstation -#[allow(unused_variables)] -pub trait ReadHandler: Send + Sync { - /// Called as the first action before any of the type-specific handle methods are invoked - /// - /// `read_type` provides information about what triggered the call, e.g. response vs unsolicited - /// `header` provides the full response header - /// - /// Note: The operation may or may not be async depending - fn begin_fragment(&mut self, read_type: ReadType, header: ResponseHeader) -> MaybeAsync<()> { - MaybeAsync::ready(()) - } - - /// Called as the last action after all of the type-specific handle methods have been invoked - /// - /// `read_type` provides information about what triggered the call, e.g. response vs unsolicited - /// `header` provides the full response header - /// - /// Note: The operation may or may not be async depending. A typical use case for using async - /// here would be to publish a message to an async MPSC. - fn end_fragment(&mut self, read_type: ReadType, header: ResponseHeader) -> MaybeAsync<()> { - MaybeAsync::ready(()) - } - - /// Process an object header of `BinaryInput` values - fn handle_binary_input( - &mut self, - info: HeaderInfo, - iter: &mut dyn Iterator, - ) { - } - - /// Process an object header of `DoubleBitBinaryInput` values - fn handle_double_bit_binary_input( - &mut self, - info: HeaderInfo, - iter: &mut dyn Iterator, - ) { - } - - /// Process an object header of `BinaryOutputStatus` values - fn handle_binary_output_status( - &mut self, - info: HeaderInfo, - iter: &mut dyn Iterator, - ) { - } - - /// Process an object header of `Counter` values - fn handle_counter(&mut self, info: HeaderInfo, iter: &mut dyn Iterator) { - } - - /// Process an object header of `FrozenCounter` values - fn handle_frozen_counter( - &mut self, - info: HeaderInfo, - iter: &mut dyn Iterator, - ) { - } - - /// Process an object header of `AnalogInput` values - fn handle_analog_input( - &mut self, - info: HeaderInfo, - iter: &mut dyn Iterator, - ) { - } - - /// Process an object header of `FrozenAnalogInput` values - fn handle_frozen_analog_input( - &mut self, - info: HeaderInfo, - iter: &mut dyn Iterator, - ) { - } - - /// Process an object header of `AnalogInputDeadBand` values - fn handle_analog_input_dead_band( - &mut self, - info: HeaderInfo, - iter: &mut dyn Iterator, - ) { - } - - /// Process an object header of `AnalogOutputStatus` values - fn handle_analog_output_status( - &mut self, - info: HeaderInfo, - iter: &mut dyn Iterator, - ) { - } - - /// Process an object header of `AnalogOutputCommandEvent` values - fn handle_analog_output_command_event( - &mut self, - info: HeaderInfo, - iter: &mut dyn Iterator, - ) { - } - - /// Process an object header of `BinaryOutputCommandEvent` values - fn handle_binary_output_command_event( - &mut self, - info: HeaderInfo, - iter: &mut dyn Iterator, - ) { - } - - /// Process an object header of `UnsignedInteger` values - fn handle_unsigned_integer( - &mut self, - info: HeaderInfo, - iter: &mut dyn Iterator, - ) { - } - - /// Process an object header of octet string values - fn handle_octet_string<'a>( - &mut self, - info: HeaderInfo, - iter: &'a mut dyn Iterator, - ) { - } - - /// Process a device attribute - fn handle_device_attribute(&mut self, info: HeaderInfo, attr: AnyAttribute) {} -} - -pub(crate) fn handle_attribute( - var: Variation, - qualifier: QualifierCode, - attr: &Option, - handler: &mut dyn ReadHandler, -) { - if let Some(attr) = attr { - match AnyAttribute::try_from(attr) { - Ok(attr) => { - handler - .handle_device_attribute(HeaderInfo::new(var, qualifier, false, false), attr); - } - Err(err) => { - tracing::warn!( - "Expected attribute type {:?} but received {:?}", - err.expected, - err.actual - ); - } - } - } -} diff --git a/dnp3/src/master/messages.rs b/dnp3/src/master/messages.rs index c989e9fd..b3d16fab 100644 --- a/dnp3/src/master/messages.rs +++ b/dnp3/src/master/messages.rs @@ -3,8 +3,8 @@ use crate::decode::DecodeLevel; use crate::link::EndpointAddress; use crate::master::error::PollError; use crate::master::error::{AssociationError, TaskError}; -use crate::master::handler::Promise; use crate::master::poll::PollMsg; +use crate::master::promise::Promise; use crate::master::tasks::Task; use crate::master::{AssociationConfig, AssociationHandler, AssociationInformation, ReadHandler}; use crate::transport::FragmentAddr; diff --git a/dnp3/src/master/mod.rs b/dnp3/src/master/mod.rs index bdefbc4e..e410bbf8 100644 --- a/dnp3/src/master/mod.rs +++ b/dnp3/src/master/mod.rs @@ -3,18 +3,21 @@ pub use error::*; pub use file::*; pub use handler::*; pub use poll::PollHandle; +pub use read_handler::*; pub use request::*; mod association; mod error; mod file; mod handler; +mod read_handler; mod request; pub(crate) mod convert; pub(crate) mod extract; pub(crate) mod messages; pub(crate) mod poll; +pub(crate) mod promise; pub(crate) mod task; pub(crate) mod tasks; diff --git a/dnp3/src/master/poll.rs b/dnp3/src/master/poll.rs index a017501e..194a6c32 100644 --- a/dnp3/src/master/poll.rs +++ b/dnp3/src/master/poll.rs @@ -5,10 +5,11 @@ use crate::app::format::write::HeaderWriter; use crate::app::Shutdown; use crate::master::association::Next; use crate::master::error::PollError; -use crate::master::handler::{AssociationHandle, Promise}; +use crate::master::handler::AssociationHandle; use crate::master::request::ReadRequest; use crate::util::Smallest; +use crate::master::promise::Promise; use tokio::time::Instant; /// Periodic poll representation diff --git a/dnp3/src/master/promise.rs b/dnp3/src/master/promise.rs new file mode 100644 index 00000000..e949c500 --- /dev/null +++ b/dnp3/src/master/promise.rs @@ -0,0 +1,25 @@ +/// A generic callback type that must be invoked once and only once. +/// The user can select to implement it using FnOnce or a +/// one-shot reply channel +pub(crate) enum Promise { + /// nothing happens when the promise is completed + None, + /// one-shot reply channel is consumed when the promise is completed + OneShot(tokio::sync::oneshot::Sender), +} + +impl Promise { + pub(crate) fn one_shot() -> (Self, tokio::sync::oneshot::Receiver) { + let (tx, rx) = tokio::sync::oneshot::channel(); + (Self::OneShot(tx), rx) + } + + pub(crate) fn complete(self, value: T) { + match self { + Promise::None => {} + Promise::OneShot(s) => { + s.send(value).ok(); + } + } + } +} diff --git a/dnp3/src/master/read_handler.rs b/dnp3/src/master/read_handler.rs new file mode 100644 index 00000000..e2f60e05 --- /dev/null +++ b/dnp3/src/master/read_handler.rs @@ -0,0 +1,196 @@ +use crate::app::attr::{AnyAttribute, Attribute}; +use crate::app::measurement::*; +use crate::app::{MaybeAsync, QualifierCode, ResponseHeader, Variation}; + +/// Trait used to process measurement data received from an outstation +#[allow(unused_variables)] +pub trait ReadHandler: Send + Sync { + /// Called as the first action before any of the type-specific handle methods are invoked + /// + /// `read_type` provides information about what triggered the call, e.g. response vs unsolicited + /// `header` provides the full response header + /// + /// Note: The operation may or may not be async depending + fn begin_fragment(&mut self, read_type: ReadType, header: ResponseHeader) -> MaybeAsync<()> { + MaybeAsync::ready(()) + } + + /// Called as the last action after all the type-specific handle methods have been invoked + /// + /// `read_type` provides information about what triggered the call, e.g. response vs unsolicited + /// `header` provides the full response header + /// + /// Note: The operation may or may not be async depending. A typical use case for using async + /// here would be to publish a message to an async MPSC. + fn end_fragment(&mut self, read_type: ReadType, header: ResponseHeader) -> MaybeAsync<()> { + MaybeAsync::ready(()) + } + + /// Process an object header of `BinaryInput` values + fn handle_binary_input( + &mut self, + info: HeaderInfo, + iter: &mut dyn Iterator, + ) { + } + + /// Process an object header of `DoubleBitBinaryInput` values + fn handle_double_bit_binary_input( + &mut self, + info: HeaderInfo, + iter: &mut dyn Iterator, + ) { + } + + /// Process an object header of `BinaryOutputStatus` values + fn handle_binary_output_status( + &mut self, + info: HeaderInfo, + iter: &mut dyn Iterator, + ) { + } + + /// Process an object header of `Counter` values + fn handle_counter(&mut self, info: HeaderInfo, iter: &mut dyn Iterator) { + } + + /// Process an object header of `FrozenCounter` values + fn handle_frozen_counter( + &mut self, + info: HeaderInfo, + iter: &mut dyn Iterator, + ) { + } + + /// Process an object header of `AnalogInput` values + fn handle_analog_input( + &mut self, + info: HeaderInfo, + iter: &mut dyn Iterator, + ) { + } + + /// Process an object header of `FrozenAnalogInput` values + fn handle_frozen_analog_input( + &mut self, + info: HeaderInfo, + iter: &mut dyn Iterator, + ) { + } + + /// Process an object header of `AnalogInputDeadBand` values + fn handle_analog_input_dead_band( + &mut self, + info: HeaderInfo, + iter: &mut dyn Iterator, + ) { + } + + /// Process an object header of `AnalogOutputStatus` values + fn handle_analog_output_status( + &mut self, + info: HeaderInfo, + iter: &mut dyn Iterator, + ) { + } + + /// Process an object header of `AnalogOutputCommandEvent` values + fn handle_analog_output_command_event( + &mut self, + info: HeaderInfo, + iter: &mut dyn Iterator, + ) { + } + + /// Process an object header of `BinaryOutputCommandEvent` values + fn handle_binary_output_command_event( + &mut self, + info: HeaderInfo, + iter: &mut dyn Iterator, + ) { + } + + /// Process an object header of `UnsignedInteger` values + fn handle_unsigned_integer( + &mut self, + info: HeaderInfo, + iter: &mut dyn Iterator, + ) { + } + + /// Process an object header of octet string values + fn handle_octet_string<'a>( + &mut self, + info: HeaderInfo, + iter: &'a mut dyn Iterator, + ) { + } + + /// Process a device attribute + fn handle_device_attribute(&mut self, info: HeaderInfo, attr: AnyAttribute) {} +} + +pub(crate) fn handle_attribute( + var: Variation, + qualifier: QualifierCode, + attr: &Option, + handler: &mut dyn ReadHandler, +) { + if let Some(attr) = attr { + match AnyAttribute::try_from(attr) { + Ok(attr) => { + handler + .handle_device_attribute(HeaderInfo::new(var, qualifier, false, false), attr); + } + Err(err) => { + tracing::warn!( + "Expected attribute type {:?} but received {:?}", + err.expected, + err.actual + ); + } + } + } +} + +/// Information about the object header and specific variation +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct HeaderInfo { + /// underlying variation in the response + pub variation: Variation, + /// qualifier code used in the response + pub qualifier: QualifierCode, + /// true if the received variation is an event type, false otherwise + pub is_event: bool, + /// true if a flags byte is present on the underlying variation, false otherwise + pub has_flags: bool, +} + +impl HeaderInfo { + pub(crate) fn new( + variation: Variation, + qualifier: QualifierCode, + is_event: bool, + has_flags: bool, + ) -> Self { + Self { + variation, + qualifier, + is_event, + has_flags, + } + } +} + +/// Describes the source of a read event +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum ReadType { + /// Startup integrity poll + StartupIntegrity, + /// Unsolicited message + Unsolicited, + /// Single poll requested by the user + SinglePoll, + /// Periodic poll configured by the user + PeriodicPoll, +} diff --git a/dnp3/src/master/tasks/command.rs b/dnp3/src/master/tasks/command.rs index aedb9e1c..1cfc9d9b 100644 --- a/dnp3/src/master/tasks/command.rs +++ b/dnp3/src/master/tasks/command.rs @@ -2,7 +2,7 @@ use crate::app::format::write::HeaderWriter; use crate::app::parse::parser::{HeaderCollection, Response}; use crate::app::FunctionCode; use crate::master::error::{CommandError, CommandResponseError, TaskError}; -use crate::master::handler::Promise; +use crate::master::promise::Promise; use crate::master::request::*; use crate::master::tasks::{AppTask, NonReadTask, Task}; diff --git a/dnp3/src/master/tasks/deadbands.rs b/dnp3/src/master/tasks/deadbands.rs index 3104876a..39d4868e 100644 --- a/dnp3/src/master/tasks/deadbands.rs +++ b/dnp3/src/master/tasks/deadbands.rs @@ -1,8 +1,9 @@ use crate::app::format::write::HeaderWriter; use crate::app::parse::parser::Response; use crate::app::FunctionCode; +use crate::master::promise::Promise; use crate::master::tasks::{AppTask, NonReadTask, Task}; -use crate::master::{DeadBandHeader, DeadBandHeaderVariants, Promise, TaskError, WriteError}; +use crate::master::{DeadBandHeader, DeadBandHeaderVariants, TaskError, WriteError}; pub(crate) struct WriteDeadBandsTask { headers: Vec, diff --git a/dnp3/src/master/tasks/empty_response.rs b/dnp3/src/master/tasks/empty_response.rs index f5c58585..bafc77ec 100644 --- a/dnp3/src/master/tasks/empty_response.rs +++ b/dnp3/src/master/tasks/empty_response.rs @@ -1,8 +1,9 @@ use crate::app::format::write::HeaderWriter; use crate::app::parse::parser::Response; use crate::app::FunctionCode; +use crate::master::promise::Promise; use crate::master::tasks::{AppTask, NonReadTask, Task}; -use crate::master::{Headers, Promise, TaskError, WriteError}; +use crate::master::{Headers, TaskError, WriteError}; pub(crate) struct EmptyResponseTask { function: FunctionCode, diff --git a/dnp3/src/master/tasks/file/authenticate.rs b/dnp3/src/master/tasks/file/authenticate.rs index 0b7bfcc9..97a009dc 100644 --- a/dnp3/src/master/tasks/file/authenticate.rs +++ b/dnp3/src/master/tasks/file/authenticate.rs @@ -3,8 +3,9 @@ use crate::app::format::WriteError; use crate::app::parse::free_format::FreeFormatVariation; use crate::app::parse::parser::{HeaderDetails, Response}; use crate::app::{FunctionCode, Group70Var2}; +use crate::master::promise::Promise; use crate::master::tasks::{AppTask, NonReadTask, Task}; -use crate::master::{AuthKey, FileCredentials, FileError, Promise, TaskError}; +use crate::master::{AuthKey, FileCredentials, FileError, TaskError}; pub(crate) struct AuthFileTask { pub(crate) credentials: FileCredentials, diff --git a/dnp3/src/master/tasks/file/close.rs b/dnp3/src/master/tasks/file/close.rs index 89d53157..76703f82 100644 --- a/dnp3/src/master/tasks/file/close.rs +++ b/dnp3/src/master/tasks/file/close.rs @@ -3,9 +3,10 @@ use crate::app::format::WriteError; use crate::app::parse::free_format::FreeFormatVariation; use crate::app::parse::parser::{HeaderDetails, Response}; use crate::app::{FileStatus, FunctionCode, Group70Var4}; +use crate::master::promise::Promise; use crate::master::tasks::file::REQUEST_ID; use crate::master::tasks::{AppTask, NonReadTask, Task}; -use crate::master::{FileError, FileHandle, Promise, TaskError}; +use crate::master::{FileError, FileHandle, TaskError}; pub(crate) struct CloseFileTask { pub(crate) handle: FileHandle, diff --git a/dnp3/src/master/tasks/file/directory.rs b/dnp3/src/master/tasks/file/directory.rs index 46104372..494e9270 100644 --- a/dnp3/src/master/tasks/file/directory.rs +++ b/dnp3/src/master/tasks/file/directory.rs @@ -1,5 +1,6 @@ use crate::app::{Group70Var7, MaybeAsync}; -use crate::master::{FileAction, FileError, FileInfo, FileReader, Promise}; +use crate::master::promise::Promise; +use crate::master::{FileAction, FileError, FileInfo, FileReader}; use scursor::ReadCursor; pub(crate) struct DirectoryReader { diff --git a/dnp3/src/master/tasks/file/get_info.rs b/dnp3/src/master/tasks/file/get_info.rs index 45654ba3..8c4692b9 100644 --- a/dnp3/src/master/tasks/file/get_info.rs +++ b/dnp3/src/master/tasks/file/get_info.rs @@ -4,8 +4,9 @@ use crate::app::format::WriteError; use crate::app::parse::free_format::FreeFormatVariation; use crate::app::parse::parser::{HeaderDetails, Response}; use crate::app::{FunctionCode, Timestamp}; +use crate::master::promise::Promise; use crate::master::tasks::{AppTask, NonReadTask, Task}; -use crate::master::{FileError, FileInfo, Promise, TaskError}; +use crate::master::{FileError, FileInfo, TaskError}; pub(crate) struct GetFileInfoTask { file_name: String, diff --git a/dnp3/src/master/tasks/file/open.rs b/dnp3/src/master/tasks/file/open.rs index f11a7f70..4d9d2d0c 100644 --- a/dnp3/src/master/tasks/file/open.rs +++ b/dnp3/src/master/tasks/file/open.rs @@ -3,9 +3,10 @@ use crate::app::format::WriteError; use crate::app::parse::free_format::FreeFormatVariation; use crate::app::parse::parser::{HeaderDetails, Response}; use crate::app::{FileStatus, FunctionCode, Group70Var3, Permissions, Timestamp}; +use crate::master::promise::Promise; use crate::master::tasks::file::REQUEST_ID; use crate::master::tasks::{AppTask, NonReadTask, Task}; -use crate::master::{AuthKey, FileError, FileHandle, FileMode, OpenFile, Promise, TaskError}; +use crate::master::{AuthKey, FileError, FileHandle, FileMode, OpenFile, TaskError}; pub(crate) struct OpenFileRequest { pub(crate) file_name: String, pub(crate) auth_key: AuthKey, diff --git a/dnp3/src/master/tasks/file/write_block.rs b/dnp3/src/master/tasks/file/write_block.rs index 77f34336..bd135046 100644 --- a/dnp3/src/master/tasks/file/write_block.rs +++ b/dnp3/src/master/tasks/file/write_block.rs @@ -3,8 +3,9 @@ use crate::app::format::WriteError; use crate::app::parse::free_format::FreeFormatVariation; use crate::app::parse::parser::{HeaderDetails, Response}; use crate::app::{FileStatus, FunctionCode, Group70Var5}; +use crate::master::promise::Promise; use crate::master::tasks::{AppTask, NonReadTask, Task}; -use crate::master::{BlockNumber, FileError, FileHandle, Promise, TaskError}; +use crate::master::{BlockNumber, FileError, FileHandle, TaskError}; pub(crate) struct WriteBlockRequest { pub(crate) handle: FileHandle, diff --git a/dnp3/src/master/tasks/mod.rs b/dnp3/src/master/tasks/mod.rs index 0b9ead7f..6e95593c 100644 --- a/dnp3/src/master/tasks/mod.rs +++ b/dnp3/src/master/tasks/mod.rs @@ -5,8 +5,8 @@ use crate::app::ResponseHeader; use crate::master::association::Association; use crate::master::error::TaskError; use crate::master::extract::extract_measurements; -use crate::master::handler::Promise; use crate::master::poll::Poll; +use crate::master::promise::Promise; use crate::master::request::{Classes, EventClasses}; use crate::master::tasks::auto::AutoTask; use crate::master::tasks::command::CommandTask; diff --git a/dnp3/src/master/tasks/read.rs b/dnp3/src/master/tasks/read.rs index 384c46b9..fb60ed9d 100644 --- a/dnp3/src/master/tasks/read.rs +++ b/dnp3/src/master/tasks/read.rs @@ -1,6 +1,6 @@ use crate::app::format::write::HeaderWriter; use crate::master::error::TaskError; -use crate::master::handler::Promise; +use crate::master::promise::Promise; use crate::master::request::ReadRequest; use crate::master::tasks::{AppTask, ReadTask, Task}; use crate::master::ReadHandler; diff --git a/dnp3/src/master/tasks/restart.rs b/dnp3/src/master/tasks/restart.rs index 65203236..1926f92d 100644 --- a/dnp3/src/master/tasks/restart.rs +++ b/dnp3/src/master/tasks/restart.rs @@ -4,7 +4,7 @@ use crate::app::gen::count::CountVariation; use crate::app::parse::parser::Response; use crate::app::FunctionCode; use crate::master::error::TaskError; -use crate::master::handler::Promise; +use crate::master::promise::Promise; use crate::master::tasks::{AppTask, NonReadTask, Task}; /// Type of restart to request diff --git a/dnp3/src/master/tasks/time.rs b/dnp3/src/master/tasks/time.rs index 98120bdf..f9f093b1 100644 --- a/dnp3/src/master/tasks/time.rs +++ b/dnp3/src/master/tasks/time.rs @@ -8,7 +8,7 @@ use crate::app::FunctionCode; use crate::app::Timestamp; use crate::master::association::Association; use crate::master::error::{TaskError, TimeSyncError}; -use crate::master::handler::Promise; +use crate::master::promise::Promise; use crate::master::request::TimeSyncProcedure; use crate::master::tasks::{AppTask, NonReadTask, Task}; diff --git a/dnp3/src/master/tests/harness/mod.rs b/dnp3/src/master/tests/harness/mod.rs index 6ed6c074..0f631402 100644 --- a/dnp3/src/master/tests/harness/mod.rs +++ b/dnp3/src/master/tests/harness/mod.rs @@ -8,8 +8,8 @@ use crate::link::header::{FrameInfo, FrameType}; use crate::link::reader::LinkModes; use crate::link::EndpointAddress; use crate::master::association::AssociationConfig; -use crate::master::handler::{AssociationHandle, MasterChannel, ReadHandler}; use crate::master::task::MasterTask; +use crate::master::{AssociationHandle, MasterChannel, ReadHandler}; use crate::master::{ AssociationHandler, AssociationInformation, HeaderInfo, MasterChannelConfig, MasterChannelType, }; @@ -22,7 +22,7 @@ struct DefaultAssociationHandler; impl AssociationHandler for DefaultAssociationHandler {} pub(crate) async fn create_association(mut config: AssociationConfig) -> TestHarness { - // use a 1 second timeout for all tests + // use a 1-second timeout for all tests config.response_timeout = Timeout::from_secs(1).unwrap(); let (io, io_handle) = sfio_tokio_mock_io::mock();