|
|
@@ -1,7 +1,6 @@
|
|
|
use async_std::sync::Mutex;
|
|
|
use futures::io::{ReadHalf, WriteHalf};
|
|
|
use futures::AsyncReadExt;
|
|
|
-use futures::FutureExt;
|
|
|
use log::*;
|
|
|
use smol::{Async, Executor};
|
|
|
|
|
|
@@ -17,7 +16,7 @@ use crate::net::message_subscriber::{
|
|
|
};
|
|
|
use crate::net::messages;
|
|
|
use crate::net::settings::SettingsPtr;
|
|
|
-use crate::system::{Subscriber, SubscriberPtr, Subscription};
|
|
|
+use crate::system::{StoppableTask, StoppableTaskPtr, Subscriber, SubscriberPtr, Subscription};
|
|
|
|
|
|
pub type ChannelPtr = Arc<Channel>;
|
|
|
|
|
|
@@ -27,6 +26,7 @@ pub struct Channel {
|
|
|
address: SocketAddr,
|
|
|
message_subscriber: MessageSubscriberPtr,
|
|
|
stop_subscriber: SubscriberPtr<NetError>,
|
|
|
+ receive_task: StoppableTaskPtr,
|
|
|
stopped: AtomicBool,
|
|
|
settings: SettingsPtr,
|
|
|
}
|
|
|
@@ -42,95 +42,148 @@ impl Channel {
|
|
|
address,
|
|
|
message_subscriber: MessageSubscriber::new(),
|
|
|
stop_subscriber: Subscriber::new(),
|
|
|
+ receive_task: StoppableTask::new(),
|
|
|
stopped: AtomicBool::new(false),
|
|
|
settings,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
pub fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) {
|
|
|
- executor.spawn(self.receive_loop()).detach();
|
|
|
+ debug!(target: "net", "Channel::start() [START, address={}]", self.address());
|
|
|
+ let self2 = self.clone();
|
|
|
+ self.receive_task.clone().start(
|
|
|
+ self.clone().receive_loop(),
|
|
|
+ // Ignore stop handler
|
|
|
+ |result| self2.handle_stop(result),
|
|
|
+ NetError::ServiceStopped,
|
|
|
+ executor,
|
|
|
+ );
|
|
|
+ debug!(target: "net", "Channel::start() [END, address={}]", self.address());
|
|
|
+ }
|
|
|
+
|
|
|
+ pub async fn stop(&self) {
|
|
|
+ debug!(target: "net", "Channel::stop() [START, address={}]", self.address());
|
|
|
+ assert_eq!(self.stopped.load(Ordering::Relaxed), false);
|
|
|
+ self.stopped.store(false, Ordering::Relaxed);
|
|
|
+ let stop_err = Arc::new(NetError::ChannelStopped);
|
|
|
+ self.stop_subscriber.notify(stop_err).await;
|
|
|
+ self.receive_task.stop().await;
|
|
|
+ debug!(target: "net", "Channel::stop() [END, address={}]", self.address());
|
|
|
+ }
|
|
|
+
|
|
|
+ pub async fn subscribe_stop(&self) -> Subscription<NetError> {
|
|
|
+ debug!(target: "net",
|
|
|
+ "Channel::subscribe_stop() [START, address={}]",
|
|
|
+ self.address()
|
|
|
+ );
|
|
|
+ // TODO: this should check the stopped status
|
|
|
+ // Call to receive should return ChannelStopped on newly created sub
|
|
|
+ let sub = self.stop_subscriber.clone().subscribe().await;
|
|
|
+ debug!(target: "net",
|
|
|
+ "Channel::subscribe_stop() [END, address={}]",
|
|
|
+ self.address()
|
|
|
+ );
|
|
|
+ sub
|
|
|
}
|
|
|
|
|
|
pub async fn send(self: Arc<Self>, message: messages::Message) -> NetResult<()> {
|
|
|
+ let packet_type = message.packet_type();
|
|
|
+ debug!(target: "net",
|
|
|
+ "Channel::send() [START, pkt_type={:?}, address={}]",
|
|
|
+ packet_type,
|
|
|
+ self.address()
|
|
|
+ );
|
|
|
if self.stopped.load(Ordering::Relaxed) {
|
|
|
return Err(NetError::ChannelStopped);
|
|
|
}
|
|
|
|
|
|
// Catch failure and stop channel, return a net error
|
|
|
- match messages::send_message(&mut *self.writer.lock().await, message).await {
|
|
|
+ let result = match messages::send_message(&mut *self.writer.lock().await, message).await {
|
|
|
Ok(()) => Ok(()),
|
|
|
Err(err) => {
|
|
|
- error!("Channel error {}, closing {}", err, self.address());
|
|
|
+ error!("Channel send error for [{}]: {}", self.address(), err);
|
|
|
self.stop().await;
|
|
|
Err(NetError::ChannelStopped)
|
|
|
}
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- pub fn address(&self) -> SocketAddr {
|
|
|
- self.address
|
|
|
+ };
|
|
|
+ debug!(target: "net",
|
|
|
+ "Channel::send() [END, pkt_type={:?}, address={}]",
|
|
|
+ packet_type,
|
|
|
+ self.address()
|
|
|
+ );
|
|
|
+ result
|
|
|
}
|
|
|
|
|
|
pub async fn subscribe_msg(
|
|
|
self: Arc<Self>,
|
|
|
packet_type: messages::PacketType,
|
|
|
) -> MessageSubscription {
|
|
|
- self.message_subscriber.clone().subscribe(packet_type).await
|
|
|
+ debug!(target: "net",
|
|
|
+ "Channel::subscribe_msg() [START, pkt_type={:?}, address={}]",
|
|
|
+ packet_type,
|
|
|
+ self.address()
|
|
|
+ );
|
|
|
+ let sub = self.message_subscriber.clone().subscribe(packet_type).await;
|
|
|
+ debug!(target: "net",
|
|
|
+ "Channel::subscribe_msg() [END, pkt_type={:?}, address={}]",
|
|
|
+ packet_type,
|
|
|
+ self.address()
|
|
|
+ );
|
|
|
+ sub
|
|
|
}
|
|
|
|
|
|
- pub async fn subscribe_stop(self: Arc<Self>) -> Subscription<NetError> {
|
|
|
- self.stop_subscriber.clone().subscribe().await
|
|
|
- }
|
|
|
-
|
|
|
- pub async fn stop(&self) {
|
|
|
- self.stopped.store(false, Ordering::Relaxed);
|
|
|
- let stop_err = Arc::new(NetError::ChannelStopped);
|
|
|
- self.stop_subscriber.notify(stop_err).await;
|
|
|
+ pub fn address(&self) -> SocketAddr {
|
|
|
+ self.address
|
|
|
}
|
|
|
|
|
|
fn is_eof_error(err: &error::Error) -> bool {
|
|
|
match err {
|
|
|
error::Error::Io(io_err) => io_err.kind() == std::io::ErrorKind::UnexpectedEof,
|
|
|
- _ => false
|
|
|
+ _ => false,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
async fn receive_loop(self: Arc<Self>) -> NetResult<()> {
|
|
|
- let stop_sub = self.clone().subscribe_stop().await;
|
|
|
+ debug!(target: "net",
|
|
|
+ "Channel::receive_loop() [START, address={}]",
|
|
|
+ self.address()
|
|
|
+ );
|
|
|
let reader = &mut *self.reader.lock().await;
|
|
|
|
|
|
loop {
|
|
|
- let message_result = futures::select! {
|
|
|
- message_result = messages::receive_message(reader).fuse() => {
|
|
|
- match message_result {
|
|
|
- Ok(message) => Ok(Arc::new(message)),
|
|
|
- Err(err) => {
|
|
|
- if Self::is_eof_error(&err) {
|
|
|
- info!("Closing channel {} disconnected", self.address());
|
|
|
- } else {
|
|
|
- error!("Read error on channel: {}", err);
|
|
|
- }
|
|
|
- self.stop().await;
|
|
|
- Err(NetError::ChannelStopped)
|
|
|
- }
|
|
|
+ let message_result = messages::receive_message(reader).await;
|
|
|
+ let message = match message_result {
|
|
|
+ Ok(message) => Arc::new(message),
|
|
|
+ Err(err) => {
|
|
|
+ if Self::is_eof_error(&err) {
|
|
|
+ info!("Channel {} disconnected", self.address());
|
|
|
+ } else {
|
|
|
+ error!("Read error on channel: {}", err);
|
|
|
}
|
|
|
- }
|
|
|
- stop_err = stop_sub.receive().fuse() => {
|
|
|
- Err(*stop_err)
|
|
|
+ debug!(target: "net",
|
|
|
+ "Channel::receive_loop() stopping channel {}",
|
|
|
+ self.address()
|
|
|
+ );
|
|
|
+ self.stop().await;
|
|
|
+ return Err(NetError::ChannelStopped);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
- // Save status before using the message
|
|
|
- let stopped = message_result.is_err();
|
|
|
-
|
|
|
// Send result to our subscribers
|
|
|
- self.message_subscriber.notify(message_result).await;
|
|
|
+ self.message_subscriber.notify(Ok(message)).await;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // If channel is stopped, timed out or any other error then terminate loop.
|
|
|
- if stopped {
|
|
|
- break;
|
|
|
+ async fn handle_stop(self: Arc<Self>, result: NetResult<()>) {
|
|
|
+ debug!(target: "net", "Channel::handle_stop() [START, address={}]", self.address());
|
|
|
+ match result {
|
|
|
+ Ok(()) => panic!("Channel task should never complete without error status"),
|
|
|
+ Err(err) => {
|
|
|
+ // Send this error to all channel subscribers
|
|
|
+ let result = Err(err);
|
|
|
+ self.message_subscriber.notify(result).await;
|
|
|
}
|
|
|
}
|
|
|
- Ok(())
|
|
|
+ debug!(target: "net", "Channel::handle_stop() [END, address={}]", self.address());
|
|
|
}
|
|
|
}
|