Skip to content

Commit

Permalink
Merge 02fd5d2 into 6a97257
Browse files Browse the repository at this point in the history
  • Loading branch information
uklotzde committed Apr 11, 2019
2 parents 6a97257 + 02fd5d2 commit 9466c7c
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 2 deletions.
8 changes: 6 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ Potential breaking change: Extending the `Request` enum with the new variant
within the client and will never be sent across the wire and can safely be
ignored by both clients and servers!

- Client: Added a `Disconnect` request as *poison pill* for stopping
the client service and to release the underlying transport.
- Client: Added a `Disconnect` request as *poison pill* for stopping the
client service and to release the underlying transport.
- Added utilities to share a Modbus context within a thread for communicating
with multiple devices.
- Added utility functions to disconnect and reconnect stale connections after
errors.

## v0.3.1 (2019-04-08)

Expand Down
2 changes: 2 additions & 0 deletions src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ pub mod sync;
#[cfg(feature = "tcp")]
pub mod tcp;

pub mod util;

use crate::frame::*;
use crate::slave::*;

Expand Down
102 changes: 102 additions & 0 deletions src/client/util.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use super::*;

use futures::{future, Future};

use std::{cell::RefCell, io::Error, rc::Rc};

/// Helper for sharing a context between multiple clients,
/// i.e. when addressing multiple slave devices in turn.
#[derive(Default)]
pub struct SharedContext {
context: Option<Rc<RefCell<Context>>>,
}

impl SharedContext {
/// Create an instance by wrapping an initial, optional context.
pub fn new(initial_context: Option<Context>) -> Self {
Self {
context: initial_context.map(RefCell::new).map(Rc::new),
}
}

/// Check if the instance is connected, i.e. if it wraps some
/// shared context reference.
pub fn is_connected(&self) -> bool {
self.context.is_some()
}

/// Disconnect and drop the wrapped context reference.
pub fn disconnect(&mut self) -> impl Future<Item = (), Error = Error> {
if let Some(context) = self.context.take() {
future::Either::A(context.borrow().disconnect())
} else {
future::Either::B(future::ok(()))
}
}

/// Reconnect by replacing the wrapped context reference.
pub fn reconnect(&mut self, context: Context) {
self.context = Some(Rc::new(RefCell::new(context)));
}

/// Obtain a shared reference of the wrapped context.
///
/// The result should only be used for subsequent requests and must
/// not be stored. If the `SharedContext` itself is shared it might
/// get disconnected at any time!
pub fn share(&self) -> Result<Rc<RefCell<Context>>, Error> {
if let Some(ref context) = self.context {
Ok(Rc::clone(context))
} else {
Err(Error::new(ErrorKind::NotConnected, "No context"))
}
}
}

/// Factory trait for creating a new context.
pub trait NewContext {
fn new_context(&self) -> Box<dyn Future<Item = Context, Error = Error>>;
}

/// Reconnectable environment with a shared context.
pub struct SharedEnvironment {
shared_context: SharedContext,
new_context: Box<dyn NewContext>,
}

impl SharedEnvironment {
pub fn new(inital_context: Option<Context>, new_context: Box<dyn NewContext>) -> Self {
Self {
shared_context: SharedContext::new(inital_context),
new_context,
}
}

pub fn shared_context(&self) -> Result<Rc<RefCell<Context>>, Error> {
self.shared_context.share()
}
}

pub fn reconnect_shared_context(
shared_env: &Rc<RefCell<SharedEnvironment>>,
) -> impl Future<Item = (), Error = Error> {
let disconnected_env = Rc::clone(shared_env);
shared_env
.borrow_mut()
.shared_context
.disconnect()
.and_then(move |()| {
debug_assert!(!disconnected_env.borrow().shared_context.is_connected());
let reconnected_env = Rc::clone(&disconnected_env);
disconnected_env
.borrow()
.new_context
.new_context()
.map(move |context| {
reconnected_env
.borrow_mut()
.shared_context
.reconnect(context)
})
})
}

0 comments on commit 9466c7c

Please sign in to comment.