Mostly cosmetic changes in dealer (#762)

* Add missing timeout on reconnect

* Cosmetic changes
This commit is contained in:
Johannesd3 2021-05-27 15:33:29 +02:00 committed by GitHub
parent 1ade02b7ad
commit 7ed35396f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 47 additions and 43 deletions

View file

@ -1,5 +1,5 @@
mod maps; mod maps;
mod protocol; pub mod protocol;
use std::iter; use std::iter;
use std::pin::Pin; use std::pin::Pin;
@ -11,6 +11,7 @@ use std::time::Duration;
use futures_core::{Future, Stream}; use futures_core::{Future, Stream};
use futures_util::future::join_all; use futures_util::future::join_all;
use futures_util::{SinkExt, StreamExt}; use futures_util::{SinkExt, StreamExt};
use thiserror::Error;
use tokio::select; use tokio::select;
use tokio::sync::mpsc::{self, UnboundedReceiver}; use tokio::sync::mpsc::{self, UnboundedReceiver};
use tokio::sync::Semaphore; use tokio::sync::Semaphore;
@ -21,7 +22,6 @@ use url::Url;
use self::maps::*; use self::maps::*;
use self::protocol::*; use self::protocol::*;
pub use self::protocol::{Message, Request};
use crate::socket; use crate::socket;
use crate::util::{keep_flushing, CancelOnDrop, TimeoutOnDrop}; use crate::util::{keep_flushing, CancelOnDrop, TimeoutOnDrop};
@ -29,6 +29,13 @@ type WsMessage = tungstenite::Message;
type WsError = tungstenite::Error; type WsError = tungstenite::Error;
type WsResult<T> = Result<T, tungstenite::Error>; type WsResult<T> = Result<T, tungstenite::Error>;
const WEBSOCKET_CLOSE_TIMEOUT: Duration = Duration::from_secs(3);
const PING_INTERVAL: Duration = Duration::from_secs(30);
const PING_TIMEOUT: Duration = Duration::from_secs(3);
const RECONNECT_INTERVAL: Duration = Duration::from_secs(10);
pub struct Response { pub struct Response {
pub success: bool, pub success: bool,
} }
@ -64,8 +71,8 @@ impl Responder {
} }
} }
pub fn send(mut self, success: Response) { pub fn send(mut self, response: Response) {
self.send_internal(success); self.send_internal(response);
self.sent = true; self.sent = true;
} }
@ -105,26 +112,26 @@ where
impl<F, R> RequestHandler for F impl<F, R> RequestHandler for F
where where
F: (Fn(Request<Payload>) -> R) + Send + Sync + 'static, F: (Fn(Request) -> R) + Send + 'static,
R: IntoResponse, R: IntoResponse,
{ {
fn handle_request(&self, request: Request<Payload>, responder: Responder) { fn handle_request(&self, request: Request, responder: Responder) {
self(request).respond(responder); self(request).respond(responder);
} }
} }
pub trait RequestHandler: Send + Sync + 'static { pub trait RequestHandler: Send + 'static {
fn handle_request(&self, request: Request<Payload>, responder: Responder); fn handle_request(&self, request: Request, responder: Responder);
} }
type MessageHandler = mpsc::UnboundedSender<Message<JsonValue>>; type MessageHandler = mpsc::UnboundedSender<Message>;
// TODO: Maybe it's possible to unregister subscription directly when they // TODO: Maybe it's possible to unregister subscription directly when they
// are dropped instead of on next failed attempt. // are dropped instead of on next failed attempt.
pub struct Subscription(UnboundedReceiver<Message<JsonValue>>); pub struct Subscription(UnboundedReceiver<Message>);
impl Stream for Subscription { impl Stream for Subscription {
type Item = Message<JsonValue>; type Item = Message;
fn poll_next( fn poll_next(
mut self: Pin<&mut Self>, mut self: Pin<&mut Self>,
@ -153,25 +160,25 @@ fn split_uri(s: &str) -> Option<impl Iterator<Item = &'_ str>> {
Some(iter::once(scheme).chain(split)) Some(iter::once(scheme).chain(split))
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone, Error)]
pub enum AddHandlerError { pub enum AddHandlerError {
#[error("There is already a handler for the given uri")]
AlreadyHandled, AlreadyHandled,
#[error("The specified uri is invalid")]
InvalidUri, InvalidUri,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone, Error)]
pub enum SubscriptionError { pub enum SubscriptionError {
#[error("The specified uri is invalid")]
InvalidUri, InvalidUri,
} }
fn add_handler<H>( fn add_handler(
map: &mut HandlerMap<Box<dyn RequestHandler>>, map: &mut HandlerMap<Box<dyn RequestHandler>>,
uri: &str, uri: &str,
handler: H, handler: impl RequestHandler,
) -> Result<(), AddHandlerError> ) -> Result<(), AddHandlerError> {
where
H: RequestHandler,
{
let split = split_uri(uri).ok_or(AddHandlerError::InvalidUri)?; let split = split_uri(uri).ok_or(AddHandlerError::InvalidUri)?;
map.insert(split, Box::new(handler)) map.insert(split, Box::new(handler))
.map_err(|_| AddHandlerError::AlreadyHandled) .map_err(|_| AddHandlerError::AlreadyHandled)
@ -218,7 +225,7 @@ macro_rules! create_dealer {
Dealer { Dealer {
shared, shared,
handle: TimeoutOnDrop::new(handle, Duration::from_secs(3)), handle: TimeoutOnDrop::new(handle, WEBSOCKET_CLOSE_TIMEOUT),
} }
} }
} }
@ -278,7 +285,7 @@ struct DealerShared {
} }
impl DealerShared { impl DealerShared {
fn dispatch_message(&self, msg: Message<JsonValue>) { fn dispatch_message(&self, msg: Message) {
if let Some(split) = split_uri(&msg.uri) { if let Some(split) = split_uri(&msg.uri) {
self.message_handlers self.message_handlers
.lock() .lock()
@ -287,11 +294,7 @@ impl DealerShared {
} }
} }
fn dispatch_request( fn dispatch_request(&self, request: Request, send_tx: &mpsc::UnboundedSender<WsMessage>) {
&self,
request: Request<Payload>,
send_tx: &mpsc::UnboundedSender<WsMessage>,
) {
// ResponseSender will automatically send "success: false" if it is dropped without an answer. // ResponseSender will automatically send "success: false" if it is dropped without an answer.
let responder = Responder::new(request.key.clone(), send_tx.clone()); let responder = Responder::new(request.key.clone(), send_tx.clone());
@ -490,7 +493,7 @@ async fn connect(
let ping_task = async { let ping_task = async {
use tokio::time::{interval, sleep}; use tokio::time::{interval, sleep};
let mut timer = interval(Duration::from_secs(30)); let mut timer = interval(PING_INTERVAL);
loop { loop {
timer.tick().await; timer.tick().await;
@ -503,7 +506,7 @@ async fn connect(
debug!("Sent ping"); debug!("Sent ping");
sleep(Duration::from_secs(3)).await; sleep(PING_TIMEOUT).await;
if !pong_received.load(atomic::Ordering::SeqCst) { if !pong_received.load(atomic::Ordering::SeqCst) {
// No response // No response
@ -539,7 +542,7 @@ async fn run<F, Fut>(
Fut: Future<Output = Url> + Send + 'static, Fut: Future<Output = Url> + Send + 'static,
F: (FnMut() -> Fut) + Send + 'static, F: (FnMut() -> Fut) + Send + 'static,
{ {
let init_task = |t| Some(TimeoutOnDrop::new(t, Duration::from_secs(3))); let init_task = |t| Some(TimeoutOnDrop::new(t, WEBSOCKET_CLOSE_TIMEOUT));
let mut tasks = if let Some((s, r)) = initial_tasks { let mut tasks = if let Some((s, r)) = initial_tasks {
(init_task(s), init_task(r)) (init_task(s), init_task(r))
@ -574,6 +577,7 @@ async fn run<F, Fut>(
Ok((s, r)) => tasks = (init_task(s), init_task(r)), Ok((s, r)) => tasks = (init_task(s), init_task(r)),
Err(e) => { Err(e) => {
warn!("Error while connecting: {}", e); warn!("Error while connecting: {}", e);
tokio::time::sleep(RECONNECT_INTERVAL).await;
} }
} }
} }

View file

@ -5,15 +5,6 @@ use serde::Deserialize;
pub type JsonValue = serde_json::Value; pub type JsonValue = serde_json::Value;
pub type JsonObject = serde_json::Map<String, JsonValue>; pub type JsonObject = serde_json::Map<String, JsonValue>;
#[derive(Clone, Debug, Deserialize)]
pub struct Request<P> {
#[serde(default)]
pub headers: HashMap<String, String>,
pub message_ident: String,
pub key: String,
pub payload: P,
}
#[derive(Clone, Debug, Deserialize)] #[derive(Clone, Debug, Deserialize)]
pub struct Payload { pub struct Payload {
pub message_id: i32, pub message_id: i32,
@ -22,18 +13,27 @@ pub struct Payload {
} }
#[derive(Clone, Debug, Deserialize)] #[derive(Clone, Debug, Deserialize)]
pub struct Message<P> { pub struct Request {
#[serde(default)]
pub headers: HashMap<String, String>,
pub message_ident: String,
pub key: String,
pub payload: Payload,
}
#[derive(Clone, Debug, Deserialize)]
pub struct Message {
#[serde(default)] #[serde(default)]
pub headers: HashMap<String, String>, pub headers: HashMap<String, String>,
pub method: Option<String>, pub method: Option<String>,
#[serde(default)] #[serde(default)]
pub payloads: Vec<P>, pub payloads: Vec<JsonValue>,
pub uri: String, pub uri: String,
} }
#[derive(Clone, Debug, Deserialize)] #[derive(Clone, Debug, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")] #[serde(tag = "type", rename_all = "snake_case")]
pub enum MessageOrRequest { pub(super) enum MessageOrRequest {
Message(Message<JsonValue>), Message(Message),
Request(Request<Payload>), Request(Request),
} }