Compare commits
56 Commits
local-hand
...
master
Author | SHA1 | Date | |
---|---|---|---|
1d898b8257 | |||
73aeefb46f | |||
b06eac6504 | |||
c9f03f5b49 | |||
c927dad70e | |||
18bd3c63f4 | |||
bc862cfac6 | |||
1bff5cc70a | |||
7034e8b87b | |||
535c39c9dc | |||
73763f8a9d | |||
3a0a1019b6 | |||
16690db44c | |||
bed35670c6 | |||
5ba6f1139d | |||
79a4441bfd | |||
6ef65cbfd1 | |||
22d1d4a569 | |||
9d014d38a1 | |||
ce64f7f4bc | |||
5c03068c79 | |||
a0544f01e4 | |||
c9ea551e0d | |||
ac12bb08ab | |||
81e5376fe2 | |||
da6dc04f71 | |||
21e28ffa12 | |||
e81a70a197 | |||
c2e67bfcbd | |||
73cf59afb8 | |||
7332c04e53 | |||
6d8dd039b3 | |||
ba67c8251d | |||
c47657177c | |||
db34774acd | |||
9a887d4821 | |||
3bb2fe7492 | |||
993ff4a46d | |||
640a8ceee1 | |||
13d1d48a70 | |||
76cc57e7ae | |||
308939801b | |||
908059d8c9 | |||
48756264b8 | |||
655fdf8462 | |||
f51433557e | |||
3e0f21153d | |||
2f4a267d09 | |||
d051922a29 | |||
dc4bb94ec5 | |||
500e1ce178 | |||
db1d22df7f | |||
cf0a50a445 | |||
dc56bd8a8d | |||
6b24f39c50 | |||
|
b86509178e |
14
.drone.yml
Normal file
14
.drone.yml
Normal file
@ -0,0 +1,14 @@
|
||||
kind: pipeline
|
||||
name: default
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: rust
|
||||
commands:
|
||||
- cargo build --verbose --all
|
||||
|
||||
- name: fmt-check
|
||||
image: rust
|
||||
commands:
|
||||
- rustup component add rustfmt
|
||||
- cargo fmt --all -- --check
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
/target
|
||||
/crates/*/target
|
||||
Cargo.lock
|
||||
|
58
CHANGELOG.md
Normal file
58
CHANGELOG.md
Normal file
@ -0,0 +1,58 @@
|
||||
## MewssageBus pending changes:
|
||||
|
||||
### 0.8.0
|
||||
#### new features:
|
||||
* Generator Handlers
|
||||
* Message Masking
|
||||
|
||||
### 0.7.0
|
||||
#### new features:
|
||||
* Bus scopes (`enter` and `leave` methods) instead clone
|
||||
* Bus relays. Connect other message bus by IP address
|
||||
|
||||
#### breaking changes:
|
||||
* Batched handlers now require `InBatch` and `OutBatch` types
|
||||
|
||||
## MewssageBus changelog:
|
||||
|
||||
### 0.6.5
|
||||
#### new features:
|
||||
* the `Message` trait no more required to be `Clone`
|
||||
* added methods `send_one`, `send_one_blocked`, `try_send_one` which does not require `Message: Clone`
|
||||
|
||||
### 0.6.4
|
||||
#### new features:
|
||||
* added struct `Module` and `BusBuilder::add_module`
|
||||
|
||||
### 0.6.3
|
||||
#### fixes:
|
||||
* Update Error Handling
|
||||
|
||||
#### breaking changes:
|
||||
* all methods now return `messagenus::Error`
|
||||
|
||||
### 0.6.2
|
||||
#### new features:
|
||||
* add `request_we` for requests when we know the handler's error type
|
||||
|
||||
#### fixes:
|
||||
* Update Error Handling
|
||||
|
||||
#### breaking changes:
|
||||
* send methods now return `messagenus::SendError`
|
||||
|
||||
#### notes:
|
||||
* Got rid of `anyhow::Error`
|
||||
|
||||
### 0.6.0
|
||||
#### new features:
|
||||
* Request/Response API (request method)
|
||||
|
||||
#### fixes:
|
||||
* Fix some unwaked receivers
|
||||
|
||||
#### breaking changes:
|
||||
* Add `type Response` and `type Error` into all handlers
|
||||
|
||||
#### notes:
|
||||
* Refactorin Receivers API
|
37
Cargo.toml
37
Cargo.toml
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "messagebus"
|
||||
version = "0.4.6"
|
||||
version = "0.9.13"
|
||||
authors = ["Andrey Tkachenko <andrey@aidev.ru>"]
|
||||
repository = "https://github.com/andreytkachenko/messagebus.git"
|
||||
keywords = ["futures", "async", "tokio", "message", "bus"]
|
||||
@ -10,13 +10,34 @@ license = "MIT OR Apache-2.0"
|
||||
exclude = [".gitignore", ".cargo/config", ".github/**", "codecov.yml"]
|
||||
edition = "2018"
|
||||
|
||||
[workspace]
|
||||
members = ["crates/remote", "crates/derive"]
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "0.2", features = ["parking_lot", "rt-threaded", "sync", "stream", "blocking"] }
|
||||
parking_lot = "0.11.1"
|
||||
async-trait = "0.1.42"
|
||||
futures = "0.3.8"
|
||||
anyhow = "1.0.34"
|
||||
crossbeam = "0.8.0"
|
||||
messagebus_derive = "0.2.5"
|
||||
|
||||
tokio = { version = "1", features = ["parking_lot", "rt-multi-thread", "sync", "time"] }
|
||||
parking_lot = "0.11"
|
||||
async-trait = "0.1"
|
||||
futures = "0.3"
|
||||
smallvec = "1.6"
|
||||
log = "0.4"
|
||||
sharded-slab = "0.1"
|
||||
thiserror = "1"
|
||||
erased-serde = "0.3"
|
||||
serde = "1"
|
||||
serde_derive = "1"
|
||||
dashmap = "4.0"
|
||||
ctor = "0.1.21"
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "0.2", features = ["parking_lot", "rt-threaded", "sync", "stream", "macros"] }
|
||||
anyhow = "1.0"
|
||||
env_logger = "0.9"
|
||||
serde_json = "1.0"
|
||||
tokio = { version = "1", features = [
|
||||
"macros",
|
||||
"parking_lot",
|
||||
"rt-multi-thread",
|
||||
"io-util",
|
||||
"sync",
|
||||
] }
|
||||
|
154
README.md
154
README.md
@ -11,67 +11,118 @@ Inspired by Actix
|
||||
### Basics
|
||||
1. Can deliver messages between actors using receivers (usually a queue implementations)
|
||||
2. Messages distincts and delivers by TypeId
|
||||
3. Messages delivers in a broadcast fashion to many receivers (Cloned)
|
||||
3. Messages delivers ether in a broadcast fashion to many receivers (Cloned) or addressed by recevier id, balanced (depends on queue load) or random
|
||||
4. There are different kind of receivers implemented:
|
||||
- BufferUnordered Receiver (in sync and async version depending by handler)
|
||||
- Synchronized (also sync and async) if receiving part needs syncronization
|
||||
- SynchronizeBuffered (also sync and async)
|
||||
here are the implmented handlers definitions:
|
||||
```rust
|
||||
- BufferUnordered Receiver (sync and async)
|
||||
- Synchronized (sync and async)
|
||||
- BatchedBufferUnordered Receiver (sync and async)
|
||||
- BatchedSynchronized (sync and async)
|
||||
5. Request/response api. There is an example is [demo_req_resp.rs](./examples/demo_req_resp.rs)
|
||||
|
||||
// Handler is Sync and we can spawn many of concurrent tasks
|
||||
Here are the list of implmented handler kinds:
|
||||
```rust
|
||||
pub trait Handler<M: Message>: Send + Sync {
|
||||
fn handle(&self, msg: M, bus: &Bus) -> anyhow::Result<()>;
|
||||
fn sync(&self, _bus: &Bus) -> anyhow::Result<()> {Ok(())}
|
||||
type Error: StdSyncSendError;
|
||||
type Response: Message;
|
||||
|
||||
fn handle(&self, msg: M, bus: &Bus) -> Result<Self::Response, Self::Error>;
|
||||
fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait AsyncHandler<M: Message>: Send + Sync {
|
||||
async fn handle(&self, msg: M, bus: &Bus) -> anyhow::Result<()>;
|
||||
async fn sync(&self, _bus: &Bus) -> anyhow::Result<()> {Ok(())}
|
||||
type Error: StdSyncSendError;
|
||||
type Response: Message;
|
||||
|
||||
async fn handle(&self, msg: M, bus: &Bus) -> Result<Self::Response, Self::Error>;
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// Handler is not Sync and we cannot spawn many of concurrent tasks same time (uses synchronization primitives such as Mutex or RwLock)
|
||||
pub trait SynchronizedHandler<M: Message>: Send {
|
||||
fn handle(&mut self, msg: M, bus: &Bus) -> anyhow::Result<()>;
|
||||
fn sync(&mut self, _bus: &Bus) -> anyhow::Result<()> {Ok(())}
|
||||
type Error: StdSyncSendError;
|
||||
type Response: Message;
|
||||
|
||||
fn handle(&mut self, msg: M, bus: &Bus) -> Result<Self::Response, Self::Error>;
|
||||
fn sync(&mut self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait AsyncSynchronizedHandler<M: Message>: Send {
|
||||
async fn handle(&mut self, msg: M, bus: &Bus) -> anyhow::Result<()>;
|
||||
async fn sync(&mut self, _bus: &Bus) -> anyhow::Result<()> {Ok(())}
|
||||
type Error: StdSyncSendError;
|
||||
type Response: Message;
|
||||
|
||||
async fn handle(&mut self, msg: M, bus: &Bus) -> Result<Self::Response, Self::Error>;
|
||||
async fn sync(&mut self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait BatchHandler<M: Message>: Send + Sync {
|
||||
type Error: StdSyncSendError + Clone;
|
||||
type Response: Message;
|
||||
type InBatch: FromIterator<M> + Send;
|
||||
type OutBatch: IntoIterator<Item = Self::Response> + Send;
|
||||
|
||||
fn handle(&self, msg: Self::InBatch, bus: &Bus) -> Result<Self::OutBatch, Self::Error>;
|
||||
fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait AsyncBatchHandler<M: Message>: Send + Sync {
|
||||
type Error: StdSyncSendError + Clone;
|
||||
type Response: Message;
|
||||
type InBatch: FromIterator<M> + Send;
|
||||
type OutBatch: IntoIterator<Item = Self::Response> + Send;
|
||||
|
||||
async fn handle(&self, msg: Self::InBatch, bus: &Bus) -> Result<Self::OutBatch, Self::Error>;
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// Handler is not Sync and handler will process items in batched mode
|
||||
pub trait BatchSynchronizedHandler<M: Message>: Send {
|
||||
fn handle(&mut self, msg: Vec<M>, bus: &Bus) -> anyhow::Result<()>;
|
||||
fn sync(&mut self, _bus: &Bus) -> anyhow::Result<()> {Ok(())}
|
||||
type Error: StdSyncSendError + Clone;
|
||||
type Response: Message;
|
||||
type InBatch: FromIterator<M> + Send;
|
||||
type OutBatch: IntoIterator<Item = Self::Response> + Send;
|
||||
|
||||
fn handle(&mut self, msg: Self::InBatch, bus: &Bus) -> Result<Self::OutBatch, Self::Error>;
|
||||
fn sync(&mut self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait AsyncBatchSynchronizedHandler<M: Message>: Send {
|
||||
async fn handle(&mut self, msg: Vec<M>, bus: &Bus) -> anyhow::Result<()>;
|
||||
async fn sync(&mut self, _bus: &Bus) -> anyhow::Result<()> {Ok(())}
|
||||
type Error: StdSyncSendError + Clone;
|
||||
type Response: Message;
|
||||
type InBatch: FromIterator<M> + Send;
|
||||
type OutBatch: IntoIterator<Item = Self::Response> + Send;
|
||||
|
||||
async fn handle(&mut self, msg: Self::InBatch, bus: &Bus) -> Result<Self::OutBatch, Self::Error>;
|
||||
async fn sync(&mut self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
4. Handler Kinds:
|
||||
1. No Synchronization needed (Handler is `Send` + `Sync`)
|
||||
* Not batched operations **(implemented)**
|
||||
6. Implemented handler kinds:
|
||||
1. No Synchronization needed (Handler implements `Send` and `Sync`)
|
||||
* Not batched operations
|
||||
- sync (spawn_blocking)
|
||||
- async (spawn)
|
||||
* Batched
|
||||
- sync (spawn_blocking)
|
||||
- async (spawn)
|
||||
2. Synchronization needed (Handler is `Sync` + `!Send`)
|
||||
* Not batched operations **(implemented)**
|
||||
- sync (spawn_blocking)
|
||||
- async (spawn)
|
||||
* Batched **(implemented)**
|
||||
- sync (spawn_blocking)
|
||||
- async (spawn)
|
||||
3. Synchronization needed and thread dedicated (Handler is `!Sync` + `!Send`)
|
||||
2. Synchronization needed (Handler implements only `Send` but not implements `Sync`)
|
||||
* Not batched operations
|
||||
- sync (spawn_blocking)
|
||||
- async (spawn)
|
||||
@ -79,16 +130,28 @@ pub trait AsyncBatchSynchronizedHandler<M: Message>: Send {
|
||||
- sync (spawn_blocking)
|
||||
- async (spawn)
|
||||
|
||||
5. Example:
|
||||
7. Not yet implemented handler kinds:
|
||||
1. Synchronization needed and thread dedicated (Handler is `!Sync` and `!Send`)
|
||||
* Not batched operations
|
||||
- sync (spawn_blocking)
|
||||
- async (spawn)
|
||||
* Batched
|
||||
- sync (spawn_blocking)
|
||||
- async (spawn)
|
||||
|
||||
8. Example:
|
||||
```rust
|
||||
use messagebus::{Bus, AsyncHandler, Result as MbusResult, receivers};
|
||||
use messagebus::{error::Error, receivers, AsyncHandler, Bus};
|
||||
use async_trait::async_trait;
|
||||
|
||||
struct TmpReceiver;
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<i32> for TmpReceiver {
|
||||
async fn handle(&self, msg: i32, bus: &Bus) -> MbusResult {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, msg: i32, bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
println!("---> i32 {}", msg);
|
||||
|
||||
bus.send(2i64).await?;
|
||||
@ -99,7 +162,10 @@ impl AsyncHandler<i32> for TmpReceiver {
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<i64> for TmpReceiver {
|
||||
async fn handle(&self, msg: i64, _bus: &Bus) -> MbusResult {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, msg: i64, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
println!("---> i64 {}", msg);
|
||||
|
||||
Ok(())
|
||||
@ -110,12 +176,22 @@ impl AsyncHandler<i64> for TmpReceiver {
|
||||
async fn main() {
|
||||
let (b, poller) = Bus::build()
|
||||
.register(TmpReceiver)
|
||||
.subscribe::<i32, receivers::BufferUnorderedAsync<_>>(Default::default())
|
||||
.subscribe::<i64, receivers::BufferUnorderedAsync<_>>(Default::default())
|
||||
.subscribe::<i32, receivers::BufferUnorderedAsync<_>, _, _>(8, Default::default())
|
||||
.subscribe::<i64, receivers::BufferUnorderedAsync<_>, _, _>(8, Default::default())
|
||||
.done()
|
||||
.build();
|
||||
|
||||
b.send(1i32).await.unwrap();
|
||||
poller.await
|
||||
|
||||
println!("flush");
|
||||
b.flush().await;
|
||||
|
||||
println!("close");
|
||||
b.close().await;
|
||||
|
||||
println!("closed");
|
||||
|
||||
poller.await;
|
||||
println!("[done]");
|
||||
}
|
||||
```
|
19
crates/derive/Cargo.toml
Normal file
19
crates/derive/Cargo.toml
Normal file
@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "messagebus_derive"
|
||||
version = "0.2.5"
|
||||
authors = ["Andrey Tkachenko <andrey@aidev.ru>"]
|
||||
repository = "https://github.com/andreytkachenko/messagebus.git"
|
||||
keywords = ["futures", "async", "tokio", "message", "bus"]
|
||||
categories = ["network-programming", "asynchronous"]
|
||||
description = "MessageBus allows intercommunicate with messages between modules"
|
||||
license = "MIT OR Apache-2.0"
|
||||
exclude = [".gitignore", ".cargo/config", ".github/**", "codecov.yml"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "1"
|
||||
quote = "1"
|
||||
syn = {version = "1", features = ["full"]}
|
350
crates/derive/src/lib.rs
Normal file
350
crates/derive/src/lib.rs
Normal file
@ -0,0 +1,350 @@
|
||||
#![recursion_limit = "128"]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
// use proc_macro::{TokenStream};
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::{quote, ToTokens};
|
||||
use std::collections::hash_map;
|
||||
use std::fmt::Write;
|
||||
use std::hash::Hasher;
|
||||
use syn::parse::{Parse, ParseStream};
|
||||
use syn::{parenthesized, Result};
|
||||
use syn::{punctuated::Punctuated, token::Comma, DeriveInput};
|
||||
|
||||
fn shared_part(_ast: &syn::DeriveInput, has_shared: bool) -> proc_macro2::TokenStream {
|
||||
if has_shared {
|
||||
quote! {
|
||||
fn as_shared_ref(&self) -> std::option::Option<&dyn messagebus::SharedMessage> {Some(self)}
|
||||
fn as_shared_mut(&mut self) -> std::option::Option<&mut dyn messagebus::SharedMessage>{Some(self)}
|
||||
fn as_shared_boxed(self: Box<Self>) -> Result<Box<dyn messagebus::SharedMessage>, Box<dyn messagebus::Message>> {Ok(self)}
|
||||
fn as_shared_arc(self: std::sync::Arc<Self>) -> Option<std::sync::Arc<dyn messagebus::SharedMessage>>{Some(self)}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
fn as_shared_ref(&self) -> std::option::Option<&dyn messagebus::SharedMessage> {None}
|
||||
fn as_shared_mut(&mut self) -> std::option::Option<&mut dyn messagebus::SharedMessage> {None}
|
||||
fn as_shared_boxed(self: Box<Self>) -> Result<Box<dyn messagebus::SharedMessage>, Box<dyn messagebus::Message>> {Err(self)}
|
||||
fn as_shared_arc(self: std::sync::Arc<Self>) -> Option<std::sync::Arc<dyn messagebus::SharedMessage>> {None}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn clone_part(ast: &syn::DeriveInput, has_clone: bool) -> proc_macro2::TokenStream {
|
||||
let name = &ast.ident;
|
||||
let (_, ty_generics, _) = ast.generics.split_for_impl();
|
||||
|
||||
if has_clone {
|
||||
quote! {
|
||||
fn try_clone_into(&self, into: &mut dyn core::any::Any) -> bool {
|
||||
let into = if let Some(inner) = into.downcast_mut::<Option<#name #ty_generics>>() {
|
||||
inner
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
|
||||
into.replace(core::clone::Clone::clone(self));
|
||||
true
|
||||
}
|
||||
fn try_clone_boxed(&self) -> std::option::Option<std::boxed::Box<dyn messagebus::Message>>{
|
||||
Some(Box::new(core::clone::Clone::clone(self)))
|
||||
}
|
||||
fn try_clone(&self) -> Option<Self> {
|
||||
Some(core::clone::Clone::clone(self))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
fn try_clone_into(&self, into: &mut dyn core::any::Any) -> bool {false}
|
||||
fn try_clone_boxed(&self) -> std::option::Option<std::boxed::Box<dyn messagebus::Message>>{ None }
|
||||
fn try_clone(&self) -> Option<Self> { None }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn type_tag_part(
|
||||
ast: &syn::DeriveInput,
|
||||
type_tag: Option<String>,
|
||||
namespace: Option<String>,
|
||||
) -> proc_macro2::TokenStream {
|
||||
let class_name = &ast.ident;
|
||||
let name = if let Some(tt) = type_tag {
|
||||
tt
|
||||
} else if let Some(ns) = namespace {
|
||||
format!("{}::{}", ns, class_name)
|
||||
} else {
|
||||
class_name.to_string()
|
||||
};
|
||||
|
||||
let (_, ty_generics, where_clause) = ast.generics.split_for_impl();
|
||||
let mut impl_generics = ast.generics.clone();
|
||||
|
||||
let mut type_name = String::new();
|
||||
let mut type_values = String::from("(");
|
||||
let mut need_close = false;
|
||||
|
||||
write!(&mut type_name, "{}", name).unwrap();
|
||||
for mut param in impl_generics.params.pairs_mut() {
|
||||
match &mut param.value_mut() {
|
||||
syn::GenericParam::Lifetime(_) => continue,
|
||||
syn::GenericParam::Type(param) => {
|
||||
if !need_close {
|
||||
type_name.push('<');
|
||||
need_close = true;
|
||||
} else {
|
||||
type_name.push(',');
|
||||
type_values.push(',');
|
||||
}
|
||||
|
||||
type_name.push_str("{}");
|
||||
|
||||
write!(
|
||||
&mut type_values,
|
||||
"<{} as messagebus::TypeTagged>::type_tag_()",
|
||||
param.ident
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let bound: syn::TypeParamBound = syn::parse_str("messagebus::TypeTagged").unwrap();
|
||||
param.bounds.push(bound);
|
||||
}
|
||||
syn::GenericParam::Const(_param) => {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if need_close {
|
||||
type_name.push('>');
|
||||
}
|
||||
|
||||
if type_values.len() > 1 {
|
||||
type_values.push_str(",)");
|
||||
|
||||
let type_values: syn::ExprTuple = syn::parse_str(&type_values).unwrap();
|
||||
let type_values = type_values.elems;
|
||||
|
||||
quote! {
|
||||
impl #impl_generics messagebus::TypeTagged for #class_name #ty_generics #where_clause {
|
||||
fn type_tag_() -> messagebus::TypeTag { format!(#type_name, #type_values).into() }
|
||||
fn type_tag(&self) -> messagebus::TypeTag { Self::type_tag_() }
|
||||
fn type_name(&self) -> std::borrow::Cow<str> { Self::type_tag_() }
|
||||
fn type_layout(&self) -> std::alloc::Layout { std::alloc::Layout::for_value(self) }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
impl #impl_generics messagebus::TypeTagged for #class_name #ty_generics #where_clause {
|
||||
fn type_tag_() -> messagebus::TypeTag { #type_name.into() }
|
||||
fn type_tag(&self) -> messagebus::TypeTag { Self::type_tag_() }
|
||||
fn type_name(&self) -> std::borrow::Cow<str> { Self::type_tag_() }
|
||||
fn type_layout(&self) -> std::alloc::Layout { std::alloc::Layout::for_value(self) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TypeTag {
|
||||
pub inner: syn::LitStr,
|
||||
}
|
||||
|
||||
impl Parse for TypeTag {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let content;
|
||||
parenthesized!(content in input);
|
||||
let punctuated = Punctuated::<syn::LitStr, Comma>::parse_terminated(&content)?;
|
||||
|
||||
let inner = punctuated.pairs().map(|x| x.into_value()).next();
|
||||
|
||||
Ok(TypeTag {
|
||||
inner: inner.unwrap().to_owned(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct Tags {
|
||||
has_clone: bool,
|
||||
has_shared: bool,
|
||||
}
|
||||
|
||||
impl Tags {
|
||||
pub fn add(&mut self, other: Tags) {
|
||||
self.has_clone = self.has_clone || other.has_clone;
|
||||
self.has_shared = self.has_shared || other.has_shared;
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for Tags {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let mut has_shared = false;
|
||||
let mut has_clone = false;
|
||||
|
||||
let content;
|
||||
parenthesized!(content in input);
|
||||
let punctuated = Punctuated::<syn::Ident, Comma>::parse_terminated(&content)?;
|
||||
|
||||
for pair in punctuated.pairs() {
|
||||
let val = pair.into_value().to_string();
|
||||
match val.as_str() {
|
||||
"shared" => has_shared = true,
|
||||
"clone" => has_clone = true,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Tags {
|
||||
has_clone,
|
||||
has_shared,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro_derive(Message, attributes(type_tag, message, namespace))]
|
||||
pub fn derive_message(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let mut tags = Tags::default();
|
||||
let mut type_tag = None;
|
||||
let mut namespace = None;
|
||||
|
||||
let ast: DeriveInput = syn::parse(input).unwrap();
|
||||
let name = &ast.ident;
|
||||
let (_, ty_generics, where_clause) = ast.generics.split_for_impl();
|
||||
for attr in &ast.attrs {
|
||||
if let Some(i) = attr.path.get_ident() {
|
||||
match i.to_string().as_str() {
|
||||
"message" => {
|
||||
let tt: Tags = syn::parse2(attr.tokens.clone()).unwrap();
|
||||
tags.add(tt);
|
||||
}
|
||||
|
||||
"type_tag" => {
|
||||
let tt: TypeTag = syn::parse2(attr.tokens.clone()).unwrap();
|
||||
type_tag = Some(tt.inner.value());
|
||||
}
|
||||
|
||||
"namespace" => {
|
||||
let tt: TypeTag = syn::parse2(attr.tokens.clone()).unwrap();
|
||||
namespace = Some(tt.inner.value());
|
||||
}
|
||||
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut impl_generics = ast.generics.clone();
|
||||
for mut param in impl_generics.params.pairs_mut() {
|
||||
match &mut param.value_mut() {
|
||||
syn::GenericParam::Lifetime(_) => {}
|
||||
syn::GenericParam::Type(params) => {
|
||||
let bound: syn::TypeParamBound =
|
||||
syn::parse_str("messagebus::MessageBounds").unwrap();
|
||||
|
||||
params.bounds.push(bound);
|
||||
|
||||
if tags.has_shared {
|
||||
let bound: syn::TypeParamBound =
|
||||
syn::parse_str("messagebus::__reexport::serde::Serialize").unwrap();
|
||||
|
||||
params.bounds.push(bound);
|
||||
|
||||
let bound: syn::TypeParamBound =
|
||||
syn::parse_str("messagebus::__reexport::serde::Deserialize<'de>").unwrap();
|
||||
|
||||
params.bounds.push(bound);
|
||||
}
|
||||
|
||||
if tags.has_clone {
|
||||
let bound: syn::TypeParamBound = syn::parse_str("core::clone::Clone").unwrap();
|
||||
|
||||
params.bounds.push(bound);
|
||||
}
|
||||
}
|
||||
syn::GenericParam::Const(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
let type_tag_part = type_tag_part(&ast, type_tag, namespace);
|
||||
let shared_part = shared_part(&ast, tags.has_shared);
|
||||
let clone_part = clone_part(&ast, tags.has_clone);
|
||||
|
||||
let init = Ident::new(
|
||||
&format!("__init_{}", hash(ast.clone().into_token_stream())),
|
||||
Span::call_site(),
|
||||
);
|
||||
let init_impl = if tags.has_shared && impl_generics.params.is_empty() {
|
||||
quote! {
|
||||
#[allow(non_upper_case_globals)]
|
||||
#[messagebus::ctor::ctor]
|
||||
fn #init() {
|
||||
messagebus::register_shared_message::<#name>();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {}
|
||||
};
|
||||
|
||||
if !impl_generics.params.is_empty() && tags.has_shared {
|
||||
impl_generics
|
||||
.params
|
||||
.push(syn::GenericParam::Lifetime(syn::LifetimeDef::new(
|
||||
syn::Lifetime::new("'de", Span::call_site()),
|
||||
)))
|
||||
}
|
||||
|
||||
let tokens = quote! {
|
||||
#type_tag_part
|
||||
|
||||
impl #impl_generics messagebus::Message for #name #ty_generics #where_clause {
|
||||
fn as_any_ref(&self) -> &dyn core::any::Any {self}
|
||||
fn as_any_mut(&mut self) -> &mut dyn core::any::Any {self}
|
||||
fn as_any_boxed(self: std::boxed::Box<Self>) -> std::boxed::Box<dyn core::any::Any> {self}
|
||||
fn as_any_arc(self: std::sync::Arc<Self>) -> std::sync::Arc<dyn core::any::Any> {self}
|
||||
|
||||
#shared_part
|
||||
#clone_part
|
||||
}
|
||||
|
||||
#init_impl
|
||||
};
|
||||
|
||||
tokens.into()
|
||||
}
|
||||
|
||||
#[proc_macro_derive(Error, attributes(type_tag, namespace))]
|
||||
pub fn derive_error(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let mut type_tag = None;
|
||||
let mut namespace = None;
|
||||
|
||||
let ast: DeriveInput = syn::parse(input).unwrap();
|
||||
for attr in &ast.attrs {
|
||||
if let Some(i) = attr.path.get_ident() {
|
||||
match i.to_string().as_str() {
|
||||
"type_tag" => {
|
||||
let tt: TypeTag = syn::parse2(attr.tokens.clone()).unwrap();
|
||||
type_tag = Some(tt.inner.value());
|
||||
}
|
||||
|
||||
"namespace" => {
|
||||
let tt: TypeTag = syn::parse2(attr.tokens.clone()).unwrap();
|
||||
namespace = Some(tt.inner.value());
|
||||
}
|
||||
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let type_tag_part = type_tag_part(&ast, type_tag, namespace);
|
||||
let tokens = quote! {
|
||||
#type_tag_part
|
||||
};
|
||||
|
||||
tokens.into()
|
||||
}
|
||||
|
||||
fn hash(input: TokenStream) -> u64 {
|
||||
let mut hasher = hash_map::DefaultHasher::new();
|
||||
hasher.write(input.to_string().as_bytes());
|
||||
hasher.finish()
|
||||
}
|
44
crates/remote/Cargo.toml
Normal file
44
crates/remote/Cargo.toml
Normal file
@ -0,0 +1,44 @@
|
||||
[package]
|
||||
name = "messagebus_remote"
|
||||
version = "0.1.0"
|
||||
authors = ["Andrey Tkachenko <andrey@aidev.ru>"]
|
||||
repository = "https://github.com/andreytkachenko/messagebus.git"
|
||||
keywords = ["futures", "async", "tokio", "message", "bus", "quic", "remote", "rpc", "parallel", "computing"]
|
||||
categories = ["network-programming", "asynchronous"]
|
||||
description = "MessageBus remote allows intercommunicate by messages between instances"
|
||||
license = "MIT OR Apache-2.0"
|
||||
exclude = [".gitignore", ".cargo/config", ".github/**", "codecov.yml"]
|
||||
edition = "2018"
|
||||
|
||||
# [features]
|
||||
# quic = ["quinn"]
|
||||
|
||||
[dependencies]
|
||||
thiserror = "1.0"
|
||||
messagebus = { path = "../../" }
|
||||
tokio = { version = "1", features = ["parking_lot", "rt-multi-thread", "sync", "time", "io-util"] }
|
||||
parking_lot = "0.11"
|
||||
quinn = "0.7"
|
||||
rmp = "0.8.10"
|
||||
rmp-serde = "0.15.5"
|
||||
erased-serde = "0.3.16"
|
||||
serde_derive = "1.0.130"
|
||||
serde = "1.0.130"
|
||||
futures = "0.3.17"
|
||||
cbor = "0.4.1"
|
||||
serde_cbor = "0.11.2"
|
||||
bytes = "1.1.0"
|
||||
quinn-proto = "0.7.3"
|
||||
rustls = "0.19.1"
|
||||
redis = {version = "0.21.2", features = ["aio", "tokio-comp"]}
|
||||
bitflags = "1.2.1"
|
||||
serde_json = "1.0.68"
|
||||
log = "0.4.14"
|
||||
|
||||
[dev-dependencies]
|
||||
anyhow = "1.0.44"
|
||||
async-trait = "0.1.51"
|
||||
thiserror = "1.0.29"
|
||||
tokio = { version = "1.11.0", features = ["full"] }
|
||||
# quinn = { version = "0.7", optional = true }
|
||||
|
BIN
crates/remote/examples/cert.der
Normal file
BIN
crates/remote/examples/cert.der
Normal file
Binary file not shown.
BIN
crates/remote/examples/cert.key
Normal file
BIN
crates/remote/examples/cert.key
Normal file
Binary file not shown.
60
crates/remote/examples/quic_client.rs
Normal file
60
crates/remote/examples/quic_client.rs
Normal file
@ -0,0 +1,60 @@
|
||||
use messagebus::derive::Message;
|
||||
use messagebus::error::GenericError;
|
||||
use messagebus::{Bus, TypeTagged};
|
||||
use messagebus_remote::relays::QuicClientRelay;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Message)]
|
||||
#[namespace("example")]
|
||||
#[message(shared, clone)]
|
||||
pub struct Req {
|
||||
data: i32,
|
||||
text: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Message)]
|
||||
#[namespace("example")]
|
||||
#[message(shared, clone)]
|
||||
pub struct Resp {
|
||||
data: i32,
|
||||
text: String,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let relay = QuicClientRelay::new(
|
||||
"./examples/cert.der",
|
||||
"127.0.0.1:8083".parse().unwrap(),
|
||||
"localhost".into(),
|
||||
(
|
||||
vec![(
|
||||
Req::type_tag_(),
|
||||
Some((Resp::type_tag_(), GenericError::type_tag_())),
|
||||
)],
|
||||
vec![],
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (b, poller) = Bus::build().register_relay(relay).build();
|
||||
|
||||
b.ready().await;
|
||||
println!("ready");
|
||||
|
||||
let resp: Resp = b
|
||||
.request(
|
||||
Req {
|
||||
data: 12,
|
||||
text: String::from("test"),
|
||||
},
|
||||
Default::default(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
println!("resp {:?}", resp);
|
||||
|
||||
b.flush_all().await;
|
||||
b.close().await;
|
||||
poller.await;
|
||||
}
|
88
crates/remote/examples/quic_server.rs
Normal file
88
crates/remote/examples/quic_server.rs
Normal file
@ -0,0 +1,88 @@
|
||||
use async_trait::async_trait;
|
||||
use messagebus::{
|
||||
derive::{Error as MbError, Message},
|
||||
error::{self, GenericError},
|
||||
AsyncHandler, Bus, Message, TypeTagged,
|
||||
};
|
||||
use messagebus_remote::relays::QuicServerRelay;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error, MbError)]
|
||||
enum Error {
|
||||
#[error("Error({0})")]
|
||||
Error(anyhow::Error),
|
||||
}
|
||||
|
||||
impl<M: Message> From<error::Error<M>> for Error {
|
||||
fn from(err: error::Error<M>) -> Self {
|
||||
Self::Error(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Message)]
|
||||
#[namespace("example")]
|
||||
#[message(shared, clone)]
|
||||
pub struct Req {
|
||||
data: i32,
|
||||
text: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Message)]
|
||||
#[namespace("example")]
|
||||
#[message(shared, clone)]
|
||||
pub struct Resp {
|
||||
data: i32,
|
||||
text: String,
|
||||
}
|
||||
|
||||
struct TmpReceiver;
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<Req> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = Resp;
|
||||
|
||||
async fn handle(&self, msg: Req, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
println!("TmpReceiver::handle {:?}", msg);
|
||||
Ok(Resp {
|
||||
data: msg.data + 12,
|
||||
text: format!("<< {} >>", msg.text),
|
||||
})
|
||||
}
|
||||
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
println!("TmpReceiver::sync");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let relay = QuicServerRelay::new(
|
||||
"./examples/cert.key",
|
||||
"./examples/cert.der",
|
||||
"0.0.0.0:8083".parse().unwrap(),
|
||||
(
|
||||
vec![],
|
||||
vec![(
|
||||
Req::type_tag_(),
|
||||
Some((Resp::type_tag_(), GenericError::type_tag_())),
|
||||
)],
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (b, poller) = Bus::build()
|
||||
.register_relay(relay)
|
||||
.register(TmpReceiver)
|
||||
.subscribe_async::<Req>(8, Default::default())
|
||||
.done()
|
||||
.build();
|
||||
|
||||
b.ready().await;
|
||||
|
||||
println!("ready");
|
||||
|
||||
poller.await;
|
||||
}
|
58
crates/remote/examples/tcp_client.rs
Normal file
58
crates/remote/examples/tcp_client.rs
Normal file
@ -0,0 +1,58 @@
|
||||
use messagebus::derive::Message;
|
||||
use messagebus::error::GenericError;
|
||||
use messagebus::{Bus, TypeTagged};
|
||||
use messagebus_remote::relays::TcpRelay;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Message)]
|
||||
#[namespace("example")]
|
||||
#[message(shared, clone)]
|
||||
pub struct Req {
|
||||
data: i32,
|
||||
text: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Message)]
|
||||
#[namespace("example")]
|
||||
#[message(shared, clone)]
|
||||
pub struct Resp {
|
||||
data: i32,
|
||||
text: String,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let relay = TcpRelay::new(
|
||||
false,
|
||||
"0.0.0.0:8083".parse().unwrap(),
|
||||
(
|
||||
vec![(
|
||||
Req::type_tag_(),
|
||||
Some((Resp::type_tag_(), GenericError::type_tag_())),
|
||||
)],
|
||||
vec![],
|
||||
),
|
||||
);
|
||||
|
||||
let (b, poller) = Bus::build().register_relay(relay).build();
|
||||
|
||||
b.ready().await;
|
||||
println!("ready");
|
||||
|
||||
let resp: Resp = b
|
||||
.request(
|
||||
Req {
|
||||
data: 12,
|
||||
text: String::from("test"),
|
||||
},
|
||||
Default::default(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
println!("resp {:?}", resp);
|
||||
|
||||
b.flush_all().await;
|
||||
b.close().await;
|
||||
poller.await;
|
||||
}
|
86
crates/remote/examples/tcp_server.rs
Normal file
86
crates/remote/examples/tcp_server.rs
Normal file
@ -0,0 +1,86 @@
|
||||
use async_trait::async_trait;
|
||||
use messagebus::{
|
||||
derive::{Error as MbError, Message},
|
||||
error::{self, GenericError},
|
||||
AsyncHandler, Bus, Message, TypeTagged,
|
||||
};
|
||||
use messagebus_remote::relays::TcpRelay;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error, MbError)]
|
||||
enum Error {
|
||||
#[error("Error({0})")]
|
||||
Error(anyhow::Error),
|
||||
}
|
||||
|
||||
impl<M: Message> From<error::Error<M>> for Error {
|
||||
fn from(err: error::Error<M>) -> Self {
|
||||
Self::Error(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Message)]
|
||||
#[namespace("example")]
|
||||
#[message(shared, clone)]
|
||||
pub struct Req {
|
||||
data: i32,
|
||||
text: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Message)]
|
||||
#[namespace("example")]
|
||||
#[message(shared, clone)]
|
||||
pub struct Resp {
|
||||
data: i32,
|
||||
text: String,
|
||||
}
|
||||
|
||||
struct TmpReceiver;
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<Req> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = Resp;
|
||||
|
||||
async fn handle(&self, msg: Req, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
println!("TmpReceiver::handle {:?}", msg);
|
||||
Ok(Resp {
|
||||
data: msg.data + 12,
|
||||
text: format!("<< {} >>", msg.text),
|
||||
})
|
||||
}
|
||||
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
println!("TmpReceiver::sync");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let relay = TcpRelay::new(
|
||||
true,
|
||||
"0.0.0.0:8083".parse().unwrap(),
|
||||
(
|
||||
vec![],
|
||||
vec![(
|
||||
Req::type_tag_(),
|
||||
Some((Resp::type_tag_(), GenericError::type_tag_())),
|
||||
)],
|
||||
),
|
||||
);
|
||||
|
||||
let (b, poller) = Bus::build()
|
||||
.register_relay(relay)
|
||||
.register(TmpReceiver)
|
||||
.subscribe_async::<Req>(8, Default::default())
|
||||
.done()
|
||||
.build();
|
||||
|
||||
b.ready().await;
|
||||
|
||||
println!("ready");
|
||||
|
||||
poller.await;
|
||||
}
|
45
crates/remote/src/error.rs
Normal file
45
crates/remote/src/error.rs
Normal file
@ -0,0 +1,45 @@
|
||||
use quinn::{ConnectError, ConnectionError, EndpointError, ParseError, ReadToEndError, WriteError};
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
#[error("IO Error: {0}")]
|
||||
Io(#[from] std::io::Error),
|
||||
|
||||
// #[error("ReadToEnd: {0}")]
|
||||
// ReadToEnd(#[from] ReadToEndError),
|
||||
#[error("ConnectionError: {0}")]
|
||||
ConnectionError(#[from] ConnectionError),
|
||||
|
||||
#[error("ConnectError: {0}")]
|
||||
ConnectError(#[from] ConnectError),
|
||||
|
||||
#[error("EndpointError: {0}")]
|
||||
EndpointError(#[from] EndpointError),
|
||||
|
||||
#[error("WriteError: {0}")]
|
||||
WriteError(#[from] WriteError),
|
||||
|
||||
#[error("ReadToEndError: {0}")]
|
||||
ReadToEndError(#[from] ReadToEndError),
|
||||
|
||||
#[error("QuinnConnectError: {0}")]
|
||||
QuinnParseError(#[from] ParseError),
|
||||
|
||||
#[error("ConfigError: {0}")]
|
||||
ConfigError(#[from] quinn_proto::ConfigError),
|
||||
|
||||
#[error("TLSError: {0}")]
|
||||
TLSError(#[from] rustls::TLSError),
|
||||
|
||||
#[error("Redis: {0}")]
|
||||
Redis(#[from] redis::RedisError),
|
||||
|
||||
#[error("ProtocolParseError {0}")]
|
||||
ProtocolParseError(String),
|
||||
|
||||
#[error("UnknownCodec")]
|
||||
UnknownCodec,
|
||||
|
||||
#[error("SerdeErased {0}")]
|
||||
SerdeErased(#[from] erased_serde::Error),
|
||||
}
|
3
crates/remote/src/lib.rs
Normal file
3
crates/remote/src/lib.rs
Normal file
@ -0,0 +1,3 @@
|
||||
pub mod error;
|
||||
pub mod proto;
|
||||
pub mod relays;
|
530
crates/remote/src/proto.rs
Normal file
530
crates/remote/src/proto.rs
Normal file
@ -0,0 +1,530 @@
|
||||
use messagebus::{Action, Bus, Event, SharedMessage, TypeTag};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::borrow::Cow;
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[repr(u16)]
|
||||
pub enum ProtocolHeaderActionKind {
|
||||
Nop,
|
||||
Error,
|
||||
|
||||
Send,
|
||||
Response,
|
||||
BatchComplete,
|
||||
|
||||
Flush,
|
||||
Flushed,
|
||||
|
||||
Synchronize,
|
||||
Synchronized,
|
||||
|
||||
Close,
|
||||
Exited,
|
||||
|
||||
Initialize,
|
||||
Ready,
|
||||
|
||||
Pause,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Deserialize, Serialize)]
|
||||
#[non_exhaustive]
|
||||
#[repr(u32)]
|
||||
pub enum BodyType {
|
||||
None,
|
||||
Utf8,
|
||||
Cbor,
|
||||
MessagePack,
|
||||
Json,
|
||||
Bson,
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct ProtocolHeaderFlags: u32 {
|
||||
const TYPE_TAG = 0b00000001;
|
||||
const BODY = 0b00000010;
|
||||
const ERROR = 0b00000100;
|
||||
const ARGUMENT = 0b00001000;
|
||||
const TT_AND_ERROR = Self::TYPE_TAG.bits | Self::ERROR.bits;
|
||||
const TT_AND_BODY = Self::TYPE_TAG.bits | Self::BODY.bits;
|
||||
const TT_ERROR_AND_ARGUMENT = Self::TYPE_TAG.bits | Self::ERROR.bits | Self::ARGUMENT.bits;
|
||||
const TT_BODY_AND_ARGUMENT = Self::TYPE_TAG.bits | Self::BODY.bits | Self::ARGUMENT.bits;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct ProtocolHeader<'a> {
|
||||
pub kind: ProtocolHeaderActionKind,
|
||||
pub type_tag: Option<Cow<'a, [u8]>>,
|
||||
pub flags: ProtocolHeaderFlags,
|
||||
pub body_type: BodyType,
|
||||
pub argument: u64,
|
||||
}
|
||||
|
||||
impl<'a> ProtocolHeader<'a> {
|
||||
pub fn send(mid: u64, tt: &'a TypeTag, body_type: BodyType) -> ProtocolHeader<'a> {
|
||||
ProtocolHeader {
|
||||
kind: ProtocolHeaderActionKind::Send,
|
||||
type_tag: Some(tt.as_bytes().into()),
|
||||
flags: ProtocolHeaderFlags::TT_BODY_AND_ARGUMENT,
|
||||
body_type,
|
||||
argument: mid,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flush() -> Self {
|
||||
ProtocolHeader {
|
||||
kind: ProtocolHeaderActionKind::Flush,
|
||||
type_tag: None,
|
||||
flags: ProtocolHeaderFlags::empty(),
|
||||
body_type: BodyType::None,
|
||||
argument: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn close() -> Self {
|
||||
ProtocolHeader {
|
||||
kind: ProtocolHeaderActionKind::Close,
|
||||
type_tag: None,
|
||||
flags: ProtocolHeaderFlags::empty(),
|
||||
body_type: BodyType::None,
|
||||
argument: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sync() -> Self {
|
||||
ProtocolHeader {
|
||||
kind: ProtocolHeaderActionKind::Synchronize,
|
||||
type_tag: None,
|
||||
flags: ProtocolHeaderFlags::empty(),
|
||||
body_type: BodyType::None,
|
||||
argument: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// pub fn init() -> Self {
|
||||
// ProtocolHeader {
|
||||
// kind: ProtocolHeaderActionKind::Initialize,
|
||||
// type_tag: None,
|
||||
// failed: false,
|
||||
// body_encoding: 0,
|
||||
// argument: 0,
|
||||
// }
|
||||
// }
|
||||
|
||||
// pub fn pause() -> Self {
|
||||
// ProtocolHeader {
|
||||
// kind: ProtocolHeaderActionKind::Pause,
|
||||
// type_tag: None,
|
||||
// failed: false,
|
||||
// body_encoding: 0,
|
||||
// argument: 0,
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ProtocolItem {
|
||||
Nop,
|
||||
Event(Event<Box<dyn SharedMessage>, messagebus::error::GenericError>),
|
||||
Action(Action),
|
||||
Send(u64, Box<dyn SharedMessage>, bool),
|
||||
}
|
||||
|
||||
impl From<Action> for ProtocolItem {
|
||||
fn from(action: Action) -> Self {
|
||||
ProtocolItem::Action(action)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Event<Box<dyn SharedMessage>, messagebus::error::GenericError>> for ProtocolItem {
|
||||
fn from(ev: Event<Box<dyn SharedMessage>, messagebus::error::GenericError>) -> Self {
|
||||
ProtocolItem::Event(ev)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(u64, Box<dyn SharedMessage>, bool)> for ProtocolItem {
|
||||
fn from(msg: (u64, Box<dyn SharedMessage>, bool)) -> Self {
|
||||
ProtocolItem::Send(msg.0, msg.1, msg.2)
|
||||
}
|
||||
}
|
||||
|
||||
impl ProtocolItem {
|
||||
pub fn unwrap_send(self) -> Result<(u64, Box<dyn SharedMessage>, bool), ProtocolItem> {
|
||||
match self {
|
||||
ProtocolItem::Send(a, b, c) => Ok((a, b, c)),
|
||||
other => Err(other),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serialize<'a>(
|
||||
&self,
|
||||
mut body_type: BodyType,
|
||||
body_buff: &'a mut Vec<u8>,
|
||||
) -> Result<ProtocolPacket<'a>, crate::error::Error> {
|
||||
let mut argument = 0;
|
||||
let mut type_tag = None;
|
||||
let mut body = None;
|
||||
let mut flags = ProtocolHeaderFlags::empty();
|
||||
|
||||
let kind = match self {
|
||||
ProtocolItem::Nop => ProtocolHeaderActionKind::Nop,
|
||||
ProtocolItem::Action(action) => match action {
|
||||
Action::Close => ProtocolHeaderActionKind::Close,
|
||||
Action::Flush => ProtocolHeaderActionKind::Flush,
|
||||
Action::Init(..) => ProtocolHeaderActionKind::Initialize,
|
||||
Action::Sync => ProtocolHeaderActionKind::Synchronize,
|
||||
_ => unimplemented!(),
|
||||
},
|
||||
ProtocolItem::Send(mid, msg, req) => {
|
||||
let msg = msg
|
||||
.as_shared_ref()
|
||||
.ok_or(crate::error::Error::UnknownCodec)?;
|
||||
|
||||
argument = *mid;
|
||||
flags.set(ProtocolHeaderFlags::ARGUMENT, *req);
|
||||
flags.set(ProtocolHeaderFlags::BODY, true);
|
||||
flags.set(ProtocolHeaderFlags::TYPE_TAG, true);
|
||||
type_tag = Some(msg.type_tag());
|
||||
body = Some(generic_serialize(body_type, &*msg, body_buff)?);
|
||||
|
||||
ProtocolHeaderActionKind::Send
|
||||
}
|
||||
ProtocolItem::Event(ev) => match ev {
|
||||
Event::Response(mid, res) => {
|
||||
argument = *mid;
|
||||
flags.set(ProtocolHeaderFlags::ARGUMENT, true);
|
||||
flags.set(ProtocolHeaderFlags::BODY, true);
|
||||
flags.set(ProtocolHeaderFlags::TYPE_TAG, true);
|
||||
|
||||
match res {
|
||||
Ok(msg) => {
|
||||
let msg = msg
|
||||
.as_shared_ref()
|
||||
.ok_or(crate::error::Error::UnknownCodec)?;
|
||||
|
||||
type_tag = Some(msg.type_tag());
|
||||
body = Some(generic_serialize(body_type, &*msg, body_buff)?);
|
||||
}
|
||||
|
||||
Err(err) => {
|
||||
flags.set(ProtocolHeaderFlags::ERROR, true);
|
||||
|
||||
type_tag = Some("GenericError".into());
|
||||
body_type = BodyType::Utf8;
|
||||
body = Some(format!("{}", err).into_bytes().into());
|
||||
}
|
||||
}
|
||||
|
||||
ProtocolHeaderActionKind::Response
|
||||
}
|
||||
Event::Error(err) => {
|
||||
flags.set(ProtocolHeaderFlags::ERROR, true);
|
||||
flags.set(ProtocolHeaderFlags::BODY, true);
|
||||
flags.set(ProtocolHeaderFlags::TYPE_TAG, true);
|
||||
|
||||
type_tag = Some("GenericError".into());
|
||||
body_type = BodyType::Utf8;
|
||||
body = Some(format!("{}", err).into_bytes().into());
|
||||
|
||||
ProtocolHeaderActionKind::Error
|
||||
}
|
||||
Event::BatchComplete(tt, n) => {
|
||||
argument = *n;
|
||||
type_tag = Some(tt.clone());
|
||||
flags.set(ProtocolHeaderFlags::TYPE_TAG, true);
|
||||
flags.set(ProtocolHeaderFlags::ARGUMENT, true);
|
||||
ProtocolHeaderActionKind::BatchComplete
|
||||
}
|
||||
Event::Synchronized(res) => {
|
||||
match res {
|
||||
Ok(_) => {}
|
||||
Err(err) => {
|
||||
flags.set(ProtocolHeaderFlags::BODY, true);
|
||||
flags.set(ProtocolHeaderFlags::ERROR, true);
|
||||
flags.set(ProtocolHeaderFlags::TYPE_TAG, true);
|
||||
|
||||
type_tag = Some("GenericError".into());
|
||||
body_type = BodyType::Utf8;
|
||||
body = Some(format!("{}", err).into_bytes().into());
|
||||
}
|
||||
}
|
||||
ProtocolHeaderActionKind::Synchronized
|
||||
}
|
||||
Event::InitFailed(err) => {
|
||||
flags.set(ProtocolHeaderFlags::BODY, true);
|
||||
flags.set(ProtocolHeaderFlags::ERROR, true);
|
||||
flags.set(ProtocolHeaderFlags::TYPE_TAG, true);
|
||||
|
||||
type_tag = Some("GenericError".into());
|
||||
body_type = BodyType::Utf8;
|
||||
body = Some(format!("{}", err).into_bytes().into());
|
||||
|
||||
ProtocolHeaderActionKind::Ready
|
||||
}
|
||||
Event::Ready => ProtocolHeaderActionKind::Ready,
|
||||
Event::Pause => ProtocolHeaderActionKind::Pause,
|
||||
Event::Exited => ProtocolHeaderActionKind::Exited,
|
||||
Event::Flushed => ProtocolHeaderActionKind::Flushed,
|
||||
_ => unimplemented!(),
|
||||
},
|
||||
};
|
||||
|
||||
Ok(ProtocolPacket {
|
||||
header: ProtocolHeader {
|
||||
kind,
|
||||
type_tag: type_tag.map(|x| x.to_string().into_bytes().into()),
|
||||
flags,
|
||||
body_type,
|
||||
argument,
|
||||
},
|
||||
body,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct ProtocolPacket<'a> {
|
||||
pub header: ProtocolHeader<'a>,
|
||||
pub body: Option<Cow<'a, [u8]>>,
|
||||
}
|
||||
|
||||
impl<'a> ProtocolPacket<'a> {
|
||||
pub fn deserialize(self, _bus: &Bus) -> Result<ProtocolItem, crate::error::Error> {
|
||||
let type_tag: Option<TypeTag> = if self.header.flags.contains(ProtocolHeaderFlags::TYPE_TAG)
|
||||
{
|
||||
self.header
|
||||
.type_tag
|
||||
.map(|x| String::from_utf8_lossy(x.as_ref()).to_string().into())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let (body, error) = if self.header.flags.contains(ProtocolHeaderFlags::ERROR) {
|
||||
let error = messagebus::error::GenericError {
|
||||
type_tag: type_tag.clone().unwrap(),
|
||||
description: self
|
||||
.body
|
||||
.map(|x| String::from_utf8_lossy(x.as_ref()).to_string())
|
||||
.unwrap_or_default(),
|
||||
};
|
||||
|
||||
(None, Some(messagebus::error::Error::Other(error)))
|
||||
} else if self.header.flags.contains(ProtocolHeaderFlags::TT_AND_BODY) {
|
||||
let body = self
|
||||
.body
|
||||
.ok_or_else(|| crate::error::Error::ProtocolParseError("No body".to_string()))?;
|
||||
let res = generic_deserialize(self.header.body_type, body.as_ref(), |de| {
|
||||
messagebus::deserialize_shared_message(type_tag.clone().unwrap(), de)
|
||||
.map_err(|x| x.map_msg(|_| ()))
|
||||
})?;
|
||||
|
||||
match res {
|
||||
Ok(body) => (Some(body), None),
|
||||
Err(err) => (None, Some(err)),
|
||||
}
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
|
||||
let argument = if self.header.flags.contains(ProtocolHeaderFlags::ARGUMENT) {
|
||||
Some(self.header.argument)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(ProtocolItem::Event(match self.header.kind {
|
||||
ProtocolHeaderActionKind::Response => Event::Response(
|
||||
argument.ok_or_else(|| {
|
||||
crate::error::Error::ProtocolParseError(
|
||||
"Event::Response expected argument".into(),
|
||||
)
|
||||
})?,
|
||||
error.map(Err).or_else(|| body.map(Ok)).ok_or_else(|| {
|
||||
crate::error::Error::ProtocolParseError("Event::Response expected body".into())
|
||||
})?,
|
||||
),
|
||||
ProtocolHeaderActionKind::Synchronized => {
|
||||
Event::Synchronized(error.map(Err).unwrap_or(Ok(())))
|
||||
}
|
||||
ProtocolHeaderActionKind::Error => Event::Error(error.ok_or_else(|| {
|
||||
crate::error::Error::ProtocolParseError("Event::Error expected body".into())
|
||||
})?),
|
||||
ProtocolHeaderActionKind::BatchComplete => {
|
||||
Event::BatchComplete(type_tag.unwrap(), self.header.argument)
|
||||
}
|
||||
ProtocolHeaderActionKind::Flushed => Event::Flushed,
|
||||
ProtocolHeaderActionKind::Exited => Event::Exited,
|
||||
ProtocolHeaderActionKind::Ready => Event::Ready,
|
||||
ProtocolHeaderActionKind::Pause => Event::Pause,
|
||||
|
||||
other => {
|
||||
return Ok(ProtocolItem::Action(match other {
|
||||
ProtocolHeaderActionKind::Initialize => Action::Init(self.header.argument),
|
||||
ProtocolHeaderActionKind::Close => Action::Close,
|
||||
ProtocolHeaderActionKind::Flush => Action::Flush,
|
||||
ProtocolHeaderActionKind::Synchronize => Action::Sync,
|
||||
ProtocolHeaderActionKind::Send => {
|
||||
let req = argument.is_some();
|
||||
let mid = self.header.argument;
|
||||
let body = body.ok_or_else(|| {
|
||||
crate::error::Error::ProtocolParseError(format!(
|
||||
"Action::Send[{:?}] expected body",
|
||||
type_tag
|
||||
))
|
||||
})?;
|
||||
|
||||
return Ok(ProtocolItem::Send(mid, body, req));
|
||||
}
|
||||
ProtocolHeaderActionKind::Nop => return Ok(ProtocolItem::Nop),
|
||||
|
||||
_ => unreachable!(),
|
||||
}))
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
fn generic_deserialize<F, T>(k: BodyType, data: &[u8], f: F) -> Result<T, crate::error::Error>
|
||||
where
|
||||
F: FnOnce(&mut dyn erased_serde::Deserializer<'_>) -> T,
|
||||
{
|
||||
match k {
|
||||
BodyType::Cbor => {
|
||||
let mut cbor_de = serde_cbor::Deserializer::from_slice(data);
|
||||
let mut de = <dyn erased_serde::Deserializer>::erase(&mut cbor_de);
|
||||
|
||||
Ok(f(&mut de))
|
||||
}
|
||||
|
||||
BodyType::Json => {
|
||||
let mut json_de = serde_json::Deserializer::from_slice(data);
|
||||
let mut de = <dyn erased_serde::Deserializer>::erase(&mut json_de);
|
||||
|
||||
Ok(f(&mut de))
|
||||
}
|
||||
|
||||
_ => Err(crate::error::Error::UnknownCodec),
|
||||
}
|
||||
}
|
||||
|
||||
fn generic_serialize<'a>(
|
||||
kind: BodyType,
|
||||
msg: &dyn SharedMessage,
|
||||
buffer: &'a mut Vec<u8>,
|
||||
) -> Result<Cow<'a, [u8]>, crate::error::Error> {
|
||||
match kind {
|
||||
BodyType::Cbor => {
|
||||
let mut cbor_se = serde_cbor::Serializer::new(&mut *buffer);
|
||||
let mut se = <dyn erased_serde::Serializer>::erase(&mut cbor_se);
|
||||
msg.erased_serialize(&mut se)?;
|
||||
}
|
||||
|
||||
BodyType::Json => {
|
||||
let mut json_se = serde_json::Serializer::new(&mut *buffer);
|
||||
let mut se = <dyn erased_serde::Serializer>::erase(&mut json_se);
|
||||
msg.erased_serialize(&mut se)?;
|
||||
}
|
||||
|
||||
_ => return Err(crate::error::Error::UnknownCodec),
|
||||
}
|
||||
|
||||
Ok(buffer.as_slice().into())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::proto::ProtocolItem;
|
||||
|
||||
use super::{
|
||||
BodyType, ProtocolHeader, ProtocolHeaderActionKind, ProtocolHeaderFlags, ProtocolPacket,
|
||||
};
|
||||
use messagebus::Event;
|
||||
use messagebus::{derive::Message, Bus, TypeTagged};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::borrow::Cow;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Message)]
|
||||
#[namespace("test")]
|
||||
#[message(shared, clone)]
|
||||
struct TestSharedMessage {
|
||||
test: String,
|
||||
value: i32,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_proto_pack_event() {
|
||||
let (bus, _) = Bus::build().build();
|
||||
|
||||
let pkt = ProtocolPacket {
|
||||
header: ProtocolHeader {
|
||||
kind: ProtocolHeaderActionKind::Response,
|
||||
type_tag: Some(TestSharedMessage::type_tag_().as_bytes().to_vec().into()),
|
||||
flags: ProtocolHeaderFlags::TT_BODY_AND_ARGUMENT,
|
||||
body_type: BodyType::Json,
|
||||
argument: 222,
|
||||
},
|
||||
body: Some(Cow::Borrowed(br#"{"test":"my test","value":12}"#)),
|
||||
};
|
||||
|
||||
let event = match pkt.deserialize(&bus).unwrap() {
|
||||
ProtocolItem::Event(ev) => ev,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
assert!(matches!(event, Event::Response(..)));
|
||||
|
||||
match event {
|
||||
Event::Response(mid, msg) => {
|
||||
assert_eq!(mid, 222);
|
||||
// assert!(msg.is_ok());
|
||||
let msg = msg.unwrap();
|
||||
|
||||
assert_eq!(msg.type_tag(), TestSharedMessage::type_tag_());
|
||||
let m: Box<TestSharedMessage> = msg.as_any_boxed().downcast().unwrap();
|
||||
|
||||
assert_eq!(m.value, 12);
|
||||
assert_eq!(&m.test, "my test");
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_proto_pack_event_error() {
|
||||
let (bus, _) = Bus::build().build();
|
||||
|
||||
let pkt = ProtocolPacket {
|
||||
header: ProtocolHeader {
|
||||
kind: ProtocolHeaderActionKind::Response,
|
||||
type_tag: Some(TestSharedMessage::type_tag_().as_bytes().to_vec().into()),
|
||||
flags: ProtocolHeaderFlags::TT_ERROR_AND_ARGUMENT,
|
||||
body_type: BodyType::Utf8,
|
||||
argument: 222,
|
||||
},
|
||||
body: Some(Cow::Borrowed(br#"error description"#)),
|
||||
};
|
||||
|
||||
let event = match pkt.deserialize(&bus).unwrap() {
|
||||
ProtocolItem::Event(ev) => ev,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
assert!(matches!(event, Event::Response(..)));
|
||||
|
||||
#[allow(clippy::unit_cmp)]
|
||||
match event {
|
||||
Event::Response(mid, msg) => {
|
||||
assert_eq!(mid, 222);
|
||||
let msg = msg.unwrap_err();
|
||||
|
||||
assert!(matches!(msg, messagebus::error::Error::Other(val) if (
|
||||
assert_eq!(val.type_tag, TestSharedMessage::type_tag_()) == () &&
|
||||
assert_eq!(val.description, "error description") == ()
|
||||
)));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
89
crates/remote/src/relays/mod.rs
Normal file
89
crates/remote/src/relays/mod.rs
Normal file
@ -0,0 +1,89 @@
|
||||
// #[cfg(feature = "quic")]
|
||||
mod quic;
|
||||
// mod redis;
|
||||
mod tcp;
|
||||
|
||||
use futures::Stream;
|
||||
use messagebus::{error::GenericError, Event, Message, TypeTag};
|
||||
use std::{collections::HashMap, pin::Pin};
|
||||
|
||||
// #[cfg(feature = "quic")]
|
||||
pub use quic::*;
|
||||
pub use tcp::*;
|
||||
|
||||
pub(crate) type GenericEventStream =
|
||||
Pin<Box<dyn Stream<Item = Event<Box<dyn Message>, GenericError>> + Send>>;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct MessageTable {
|
||||
table: HashMap<TypeTag, Vec<Option<(TypeTag, TypeTag)>>>,
|
||||
}
|
||||
|
||||
impl MessageTable {
|
||||
#[inline]
|
||||
pub fn add_any(&mut self, req: TypeTag, resp_err: Option<(TypeTag, TypeTag)>) {
|
||||
self.table
|
||||
.entry(req)
|
||||
.or_insert_with(Vec::new)
|
||||
.push(resp_err);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn add_request(&mut self, req: TypeTag, resp: TypeTag, err: TypeTag) {
|
||||
self.add_any(req, Some((resp, err)));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn add_message(&mut self, msg: TypeTag) {
|
||||
self.add_any(msg, None);
|
||||
}
|
||||
|
||||
pub fn iter_keys(&self) -> impl Iterator<Item = &str> + '_ {
|
||||
self.table.keys().map(|k| k.as_ref())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn accept_any(&self, msg: &TypeTag) -> bool {
|
||||
self.table.contains_key(msg)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn accept_message(&self, msg: &TypeTag) -> bool {
|
||||
self.table
|
||||
.get(msg)
|
||||
.map_or(false, |v| v.iter().any(Option::is_none))
|
||||
}
|
||||
|
||||
pub fn accept_request(
|
||||
&self,
|
||||
msg: &TypeTag,
|
||||
resp: Option<&TypeTag>,
|
||||
err: Option<&TypeTag>,
|
||||
) -> bool {
|
||||
self.table.get(msg).map_or(false, |v| {
|
||||
v.iter().filter_map(Option::as_ref).any(|(r, e)| {
|
||||
resp.map_or(true, |resp| resp.as_ref() == r.as_ref())
|
||||
&& err.map_or(true, |err| err.as_ref() == e.as_ref())
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn iter_types(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (&'_ TypeTag, Option<&'_ (TypeTag, TypeTag)>)> + '_ {
|
||||
self.table
|
||||
.iter()
|
||||
.map(|(k, v)| v.iter().map(move |resp| (k, resp.as_ref())))
|
||||
.flatten()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<(TypeTag, Option<(TypeTag, TypeTag)>)>> for MessageTable {
|
||||
fn from(table: Vec<(TypeTag, Option<(TypeTag, TypeTag)>)>) -> Self {
|
||||
let mut outgoing_table = MessageTable::default();
|
||||
for (key, val) in table {
|
||||
outgoing_table.add_any(key, val);
|
||||
}
|
||||
outgoing_table
|
||||
}
|
||||
}
|
56
crates/remote/src/relays/quic/client.rs
Normal file
56
crates/remote/src/relays/quic/client.rs
Normal file
@ -0,0 +1,56 @@
|
||||
use crate::error::Error;
|
||||
use futures::{Future, Stream};
|
||||
use quinn::Connecting;
|
||||
use std::{
|
||||
net::SocketAddr,
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
use super::WaitIdle;
|
||||
|
||||
pub struct QuicClientEndpoint {
|
||||
addr: SocketAddr,
|
||||
host: String,
|
||||
endpoint: quinn::Endpoint,
|
||||
}
|
||||
|
||||
impl QuicClientEndpoint {
|
||||
pub fn new(cert: &str, addr: SocketAddr, host: String) -> Result<Self, Error> {
|
||||
let mut client_config = quinn::ClientConfigBuilder::default();
|
||||
client_config.protocols(super::ALPN_QUIC_HTTP);
|
||||
client_config.enable_keylog();
|
||||
|
||||
let cert_der = std::fs::read(cert)?;
|
||||
let cert = quinn::Certificate::from_der(&cert_der)?;
|
||||
|
||||
client_config.add_certificate_authority(cert).unwrap();
|
||||
|
||||
let mut endpoint = quinn::Endpoint::builder();
|
||||
endpoint.default_client_config(client_config.build());
|
||||
|
||||
let (endpoint, _) = endpoint.bind(&"0.0.0.0:0".parse().unwrap())?;
|
||||
|
||||
Ok(Self {
|
||||
addr,
|
||||
host,
|
||||
endpoint,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Stream for QuicClientEndpoint {
|
||||
type Item = Connecting;
|
||||
|
||||
fn poll_next(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
let this = self.get_mut();
|
||||
Poll::Ready(this.endpoint.connect(&this.addr, &this.host).ok())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> WaitIdle<'a> for QuicClientEndpoint {
|
||||
type Fut = Pin<Box<dyn Future<Output = ()> + Send + 'a>>;
|
||||
fn wait_idle(&'a self) -> Self::Fut {
|
||||
Box::pin(self.endpoint.wait_idle())
|
||||
}
|
||||
}
|
489
crates/remote/src/relays/quic/mod.rs
Normal file
489
crates/remote/src/relays/quic/mod.rs
Normal file
@ -0,0 +1,489 @@
|
||||
mod client;
|
||||
mod server;
|
||||
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
use bytes::{Buf, BufMut};
|
||||
pub use client::QuicClientEndpoint;
|
||||
use futures::{pin_mut, Future, Stream, StreamExt};
|
||||
use messagebus::error::GenericError;
|
||||
use messagebus::{
|
||||
Action, Bus, Event, EventBoxed, Message, ReciveUntypedReceiver, SendOptions,
|
||||
SendUntypedReceiver, TypeTag, TypeTagAccept, TypeTagAcceptItem,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use quinn::{Connecting, IncomingBiStreams};
|
||||
pub use server::QuicServerEndpoint;
|
||||
use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender};
|
||||
|
||||
pub const ALPN_QUIC_HTTP: &[&[u8]] = &[b"hq-29"];
|
||||
|
||||
use crate::proto::{BodyType, ProtocolItem, ProtocolPacket};
|
||||
|
||||
pub type QuicClientRelay = QuicRelay<QuicClientEndpoint>;
|
||||
pub type QuicServerRelay = QuicRelay<QuicServerEndpoint>;
|
||||
|
||||
use super::{GenericEventStream, MessageTable};
|
||||
pub type MessageList = Vec<(TypeTag, Option<(TypeTag, TypeTag)>)>;
|
||||
|
||||
pub trait WaitIdle<'a>: Sync {
|
||||
type Fut: Future + Send + 'a;
|
||||
fn wait_idle(&'a self) -> Self::Fut;
|
||||
}
|
||||
|
||||
pub struct QuicRelay<B> {
|
||||
base: Mutex<Option<B>>,
|
||||
self_id: Arc<AtomicU64>,
|
||||
in_table: MessageTable,
|
||||
_out_table: MessageTable,
|
||||
|
||||
item_sender: UnboundedSender<Option<ProtocolItem>>,
|
||||
item_receiver: Mutex<Option<UnboundedReceiver<Option<ProtocolItem>>>>,
|
||||
|
||||
event_sender: UnboundedSender<EventBoxed<GenericError>>,
|
||||
event_receiver: Mutex<Option<UnboundedReceiver<EventBoxed<GenericError>>>>,
|
||||
|
||||
stream_sender: UnboundedSender<IncomingBiStreams>,
|
||||
stream_receiver: Mutex<Option<UnboundedReceiver<IncomingBiStreams>>>,
|
||||
}
|
||||
|
||||
impl QuicRelay<QuicClientEndpoint> {
|
||||
pub fn new(
|
||||
cert: &str,
|
||||
addr: SocketAddr,
|
||||
host: String,
|
||||
table: (MessageList, MessageList),
|
||||
) -> Result<Self, crate::error::Error> {
|
||||
let (item_sender, item_receiver) = mpsc::unbounded_channel();
|
||||
let (event_sender, event_receiver) = mpsc::unbounded_channel();
|
||||
let (stream_sender, stream_receiver) = mpsc::unbounded_channel();
|
||||
|
||||
Ok(QuicRelay {
|
||||
base: Mutex::new(Some(QuicClientEndpoint::new(cert, addr, host)?)),
|
||||
self_id: Arc::new(AtomicU64::new(0)),
|
||||
in_table: MessageTable::from(table.0),
|
||||
_out_table: MessageTable::from(table.1),
|
||||
item_sender,
|
||||
item_receiver: Mutex::new(Some(item_receiver)),
|
||||
event_sender,
|
||||
event_receiver: Mutex::new(Some(event_receiver)),
|
||||
stream_sender,
|
||||
stream_receiver: Mutex::new(Some(stream_receiver)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl QuicRelay<QuicServerEndpoint> {
|
||||
pub fn new(
|
||||
key_path: &str,
|
||||
cert_path: &str,
|
||||
addr: SocketAddr,
|
||||
table: (MessageList, MessageList),
|
||||
) -> Result<Self, crate::error::Error> {
|
||||
let (item_sender, item_receiver) = mpsc::unbounded_channel();
|
||||
let (event_sender, event_receiver) = mpsc::unbounded_channel();
|
||||
let (stream_sender, stream_receiver) = mpsc::unbounded_channel();
|
||||
|
||||
Ok(QuicRelay {
|
||||
base: Mutex::new(Some(QuicServerEndpoint::new(key_path, cert_path, &addr)?)),
|
||||
self_id: Arc::new(AtomicU64::new(0)),
|
||||
in_table: MessageTable::from(table.0),
|
||||
_out_table: MessageTable::from(table.1),
|
||||
item_sender,
|
||||
item_receiver: Mutex::new(Some(item_receiver)),
|
||||
event_sender,
|
||||
event_receiver: Mutex::new(Some(event_receiver)),
|
||||
stream_sender,
|
||||
stream_receiver: Mutex::new(Some(stream_receiver)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<B> TypeTagAccept for QuicRelay<B>
|
||||
where
|
||||
B: Stream<Item = Connecting> + Send + 'static,
|
||||
{
|
||||
fn iter_types(&self) -> Box<dyn Iterator<Item = TypeTagAcceptItem> + '_> {
|
||||
let iter = self.in_table.iter_types();
|
||||
Box::new(iter.map(|(x, y)| (x.clone(), y.cloned())))
|
||||
}
|
||||
|
||||
fn accept_msg(&self, msg: &TypeTag) -> bool {
|
||||
self.in_table.accept_message(msg)
|
||||
}
|
||||
|
||||
fn accept_req(&self, req: &TypeTag, resp: Option<&TypeTag>, err: Option<&TypeTag>) -> bool {
|
||||
self.in_table.accept_request(req, resp, err)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B> SendUntypedReceiver for QuicRelay<B>
|
||||
where
|
||||
B: for<'a> WaitIdle<'a> + Stream<Item = Connecting> + Send + 'static,
|
||||
{
|
||||
fn send(&self, msg: Action, _bus: &Bus) -> Result<(), messagebus::error::Error<Action>> {
|
||||
match msg {
|
||||
Action::Init(self_id) => {
|
||||
let mut rx = match self.item_receiver.lock().take() {
|
||||
Some(x) => x,
|
||||
None => return Ok(()),
|
||||
};
|
||||
|
||||
let stream_sender = self.stream_sender.clone();
|
||||
let event_sender = self.event_sender.clone();
|
||||
|
||||
let incoming = self.base.lock().take().unwrap();
|
||||
self.self_id.store(self_id, Ordering::SeqCst);
|
||||
|
||||
tokio::spawn(async move {
|
||||
pin_mut!(incoming);
|
||||
|
||||
let mut body_buff = Vec::new();
|
||||
let mut header_buff = Vec::new();
|
||||
let mut item = None;
|
||||
|
||||
loop {
|
||||
println!("begin");
|
||||
|
||||
let conn = match incoming.next().await {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
println!("No more connections. Message {:?} has been lost!", item);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
let conn = match conn.await {
|
||||
Ok(conn) => conn,
|
||||
Err(err) => {
|
||||
println!(
|
||||
"connection dropped with err {}. waiting next connection",
|
||||
err
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
stream_sender.send(conn.bi_streams).unwrap();
|
||||
event_sender.send(Event::Ready).unwrap();
|
||||
|
||||
loop {
|
||||
let r = if let Some(r) = item.take() {
|
||||
r
|
||||
} else {
|
||||
match rx.recv().await {
|
||||
Some(Some(r)) => r,
|
||||
None | Some(None) => {
|
||||
println!("closing");
|
||||
conn.connection.close(0u32.into(), b"done");
|
||||
incoming.wait_idle().await;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// match tokio::time::timeout(Duration::from_secs(5), rx.recv()).await {
|
||||
// Ok(Some(Some(r))) => r,
|
||||
// Ok(None) | Ok(Some(None)) => {
|
||||
// conn.connection.close(0u32.into(), b"done");
|
||||
// incoming.wait_idle().await;
|
||||
// break;
|
||||
// },
|
||||
// Err(_) => {
|
||||
// // println!("{:?}", err);
|
||||
// // let (mut send, _) = match conn.connection.open_bi().await {
|
||||
// // Ok(x) => x,
|
||||
// // Err(err) => {
|
||||
// // println!("err {}", err);
|
||||
// // break;
|
||||
// // }
|
||||
// // };
|
||||
// // println!("<< PING");
|
||||
// // let _ = send.write_all(b"PING").await.unwrap();
|
||||
// // let _ = send.finish().await;
|
||||
// continue;
|
||||
// }
|
||||
// }
|
||||
};
|
||||
|
||||
let (mut send, _) = match conn.connection.open_bi().await {
|
||||
Ok(x) => x,
|
||||
Err(err) => {
|
||||
println!("err {}", err);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
body_buff.clear();
|
||||
let pkt = r.serialize(BodyType::Cbor, &mut body_buff).unwrap();
|
||||
|
||||
header_buff.resize(16, 0);
|
||||
serde_cbor::to_writer(&mut header_buff, &pkt).unwrap();
|
||||
let body_size = header_buff.len() - 16;
|
||||
|
||||
let mut head = &mut header_buff[0..16];
|
||||
|
||||
head.put(&b"MBUS"[..]);
|
||||
head.put_u16(1);
|
||||
head.put_u16(0);
|
||||
head.put_u64(body_size as _);
|
||||
|
||||
if let Err(err) = send.write_all(&header_buff).await {
|
||||
item = Some(r);
|
||||
println!(
|
||||
"write broken connection err {}. try with next connection",
|
||||
err
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
if let Err(err) = send.finish().await {
|
||||
item = Some(r);
|
||||
println!(
|
||||
"finish broken connection err {}. try with next connection",
|
||||
err
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
event_sender.send(Event::Pause).unwrap();
|
||||
}
|
||||
|
||||
println!("exit main loop");
|
||||
});
|
||||
}
|
||||
|
||||
Action::Close => {
|
||||
self.item_sender.send(None).unwrap();
|
||||
self.event_sender.send(Event::Exited).unwrap();
|
||||
}
|
||||
|
||||
other => self.item_sender.send(Some(other.into())).unwrap(),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn send_msg(
|
||||
&self,
|
||||
mid: u64,
|
||||
msg: Box<dyn Message>,
|
||||
req: bool,
|
||||
_bus: &Bus,
|
||||
) -> Result<(), messagebus::error::Error<Box<dyn Message>>> {
|
||||
match msg.as_shared_boxed() {
|
||||
Ok(msg) => {
|
||||
if let Err(err) = self.item_sender.send(Some((mid, msg, req).into())) {
|
||||
Err(messagebus::error::Error::TryAgain(
|
||||
err.0.unwrap().unwrap_send().unwrap().1.upcast_box(),
|
||||
))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Err(msg) => Err(messagebus::error::Error::TryAgain(msg)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B> ReciveUntypedReceiver for QuicRelay<B>
|
||||
where
|
||||
B: Send,
|
||||
{
|
||||
type Stream = GenericEventStream;
|
||||
|
||||
fn event_stream(&self, bus: Bus) -> Self::Stream {
|
||||
let self_id = self.self_id.clone();
|
||||
|
||||
let mut recv_stream = self.stream_receiver.lock().take().unwrap();
|
||||
let mut recv_events = self.event_receiver.lock().take().unwrap();
|
||||
let sender = self.item_sender.clone();
|
||||
|
||||
let stream1 = futures::stream::poll_fn(move |cx| recv_stream.poll_recv(cx))
|
||||
.map(move |incoming| {
|
||||
let buff: Vec<u8> = Vec::with_capacity(1024);
|
||||
let bus = bus.clone();
|
||||
let self_id = self_id.clone();
|
||||
let sender = sender.clone();
|
||||
|
||||
futures::stream::unfold(
|
||||
(incoming, bus, sender, self_id, buff),
|
||||
|(mut incoming, bus, sender, self_id, mut buff)| async move {
|
||||
loop {
|
||||
let (_, mut recv) = match incoming.next().await? {
|
||||
Ok(recv) => recv,
|
||||
Err(err) => {
|
||||
println!("error: {}", err);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
buff.resize(4, 0);
|
||||
if let Err(err) = recv.read_exact(&mut buff[..]).await {
|
||||
println!("recv err: {}", err);
|
||||
continue;
|
||||
}
|
||||
|
||||
let verb = match std::str::from_utf8(&buff[0..4]) {
|
||||
Ok(m) => m,
|
||||
Err(err) => {
|
||||
println!("recv err parse: {}", err);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
if verb == "PING" {
|
||||
println!(">> PING");
|
||||
continue;
|
||||
}
|
||||
|
||||
if verb != "MBUS" {
|
||||
println!("Not MBUS packet!");
|
||||
continue;
|
||||
}
|
||||
|
||||
buff.resize(12, 0);
|
||||
if let Err(err) = recv.read_exact(&mut buff[..]).await {
|
||||
println!("recv err: {}", err);
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut reader = &buff[..];
|
||||
let _version = reader.get_u16();
|
||||
let content_type = reader.get_u16();
|
||||
let body_size = reader.get_u64();
|
||||
|
||||
buff.resize(body_size as _, 0);
|
||||
if let Err(err) = recv.read_exact(&mut buff[..]).await {
|
||||
println!("recv err: {}", err);
|
||||
continue;
|
||||
}
|
||||
|
||||
drop(recv);
|
||||
|
||||
// println!("inbound packet MBUS v: {}; ct: {}; bs: {}",
|
||||
// version, content_type, body_size);
|
||||
|
||||
let event = match content_type {
|
||||
0 => {
|
||||
// CBOR
|
||||
let proto: ProtocolPacket =
|
||||
match serde_cbor::from_slice(&buff[..]) {
|
||||
Ok(val) => val,
|
||||
Err(err) => {
|
||||
println!("pkt parse err: {}", err);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let item: ProtocolItem = match proto.deserialize(&bus) {
|
||||
Ok(val) => val,
|
||||
Err(err) => {
|
||||
println!("item parse err: {}", err);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
match item {
|
||||
ProtocolItem::Event(ev) => {
|
||||
ev.map_msg(|msg| msg.upcast_box())
|
||||
}
|
||||
ProtocolItem::Action(action) => {
|
||||
match action {
|
||||
Action::Close => {
|
||||
println!("warning: Close recevied - ignoring!");
|
||||
sender
|
||||
.send(Some(ProtocolItem::Event(
|
||||
Event::Exited,
|
||||
)))
|
||||
.unwrap();
|
||||
}
|
||||
Action::Flush => {
|
||||
println!("flush");
|
||||
bus.flush_all().await;
|
||||
sender
|
||||
.send(Some(ProtocolItem::Event(
|
||||
Event::Flushed,
|
||||
)))
|
||||
.unwrap();
|
||||
}
|
||||
Action::Sync => {
|
||||
println!("flush");
|
||||
bus.sync_all().await;
|
||||
sender
|
||||
.send(Some(ProtocolItem::Event(
|
||||
Event::Synchronized(Ok(())),
|
||||
)))
|
||||
.unwrap();
|
||||
}
|
||||
Action::Init(..) => (),
|
||||
Action::Stats => (),
|
||||
_ => (),
|
||||
}
|
||||
continue;
|
||||
}
|
||||
ProtocolItem::Send(mid, msg, req) => {
|
||||
let self_id = self_id.clone();
|
||||
let sender = sender.clone();
|
||||
let bus = bus.clone();
|
||||
|
||||
let _ = tokio::spawn(async move {
|
||||
if req {
|
||||
let res = bus
|
||||
.request_boxed(
|
||||
msg.upcast_box(),
|
||||
SendOptions::Except(
|
||||
self_id.load(Ordering::SeqCst),
|
||||
),
|
||||
)
|
||||
.await
|
||||
.map(|x| x.as_shared_boxed().unwrap())
|
||||
.map_err(|x| x.map_msg(|_| ()));
|
||||
|
||||
sender
|
||||
.send(Some(ProtocolItem::Event(
|
||||
Event::Response(mid, res),
|
||||
)))
|
||||
.unwrap();
|
||||
} else {
|
||||
let tt = msg.type_tag();
|
||||
let _ = bus
|
||||
.send_boxed(
|
||||
msg.upcast_box(),
|
||||
Default::default(),
|
||||
)
|
||||
.await;
|
||||
|
||||
sender
|
||||
.send(Some(ProtocolItem::Event(
|
||||
Event::BatchComplete(tt, 1),
|
||||
)))
|
||||
.unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
continue;
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
return Some((event, (incoming, bus, sender, self_id, buff)));
|
||||
}
|
||||
},
|
||||
)
|
||||
})
|
||||
.flatten();
|
||||
|
||||
let stream2 = futures::stream::poll_fn(move |cx| recv_events.poll_recv(cx));
|
||||
Box::pin(
|
||||
futures::stream::select(stream1, stream2)
|
||||
.take_while(|x| futures::future::ready(!matches!(x, Event::Exited))),
|
||||
)
|
||||
}
|
||||
}
|
64
crates/remote/src/relays/quic/server.rs
Normal file
64
crates/remote/src/relays/quic/server.rs
Normal file
@ -0,0 +1,64 @@
|
||||
use crate::error::Error;
|
||||
use futures::{Future, Stream};
|
||||
use quinn::Connecting;
|
||||
use std::{
|
||||
net::SocketAddr,
|
||||
pin::Pin,
|
||||
sync::Arc,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
use super::WaitIdle;
|
||||
|
||||
pub struct QuicServerEndpoint {
|
||||
endpoint: quinn::Endpoint,
|
||||
incoming: quinn::Incoming,
|
||||
}
|
||||
|
||||
impl QuicServerEndpoint {
|
||||
pub fn new(key_path: &str, cert_path: &str, addr: &SocketAddr) -> Result<Self, Error> {
|
||||
let mut transport_config = quinn::TransportConfig::default();
|
||||
transport_config.max_concurrent_uni_streams(0)?;
|
||||
|
||||
let mut server_config = quinn::ServerConfig::default();
|
||||
server_config.transport = Arc::new(transport_config);
|
||||
|
||||
let mut server_config = quinn::ServerConfigBuilder::new(server_config);
|
||||
|
||||
server_config.protocols(super::ALPN_QUIC_HTTP);
|
||||
server_config.enable_keylog();
|
||||
|
||||
let key = std::fs::read(key_path)?;
|
||||
let cert_der = std::fs::read(cert_path)?;
|
||||
|
||||
let key = quinn::PrivateKey::from_der(&key)?;
|
||||
let cert_chain = quinn::Certificate::from_der(&cert_der)?;
|
||||
|
||||
let cert = quinn::CertificateChain::from_certs([cert_chain]);
|
||||
|
||||
server_config.certificate(cert, key)?;
|
||||
|
||||
let mut endpoint = quinn::Endpoint::builder();
|
||||
endpoint.listen(server_config.build());
|
||||
|
||||
let (endpoint, incoming) = endpoint.bind(addr)?;
|
||||
|
||||
Ok(Self { endpoint, incoming })
|
||||
}
|
||||
}
|
||||
|
||||
impl Stream for QuicServerEndpoint {
|
||||
type Item = Connecting;
|
||||
|
||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
let this = self.get_mut();
|
||||
unsafe { Pin::new_unchecked(&mut this.incoming) }.poll_next(cx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> WaitIdle<'a> for QuicServerEndpoint {
|
||||
type Fut = Pin<Box<dyn Future<Output = ()> + Send + 'a>>;
|
||||
fn wait_idle(&'a self) -> Self::Fut {
|
||||
Box::pin(self.endpoint.wait_idle())
|
||||
}
|
||||
}
|
252
crates/remote/src/relays/redis/mod.rs
Normal file
252
crates/remote/src/relays/redis/mod.rs
Normal file
@ -0,0 +1,252 @@
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
use futures::StreamExt;
|
||||
use messagebus::{
|
||||
Action, Bus, Event, Message, ReciveUntypedReceiver, SendUntypedReceiver, TypeTag, TypeTagAccept,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender};
|
||||
|
||||
use super::{GenericEventStream, MessageTable};
|
||||
use crate::proto::{BodyType, ProtocolItem};
|
||||
use redis::AsyncCommands;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum RecvDo {
|
||||
Ready,
|
||||
}
|
||||
|
||||
pub struct RedisRelay {
|
||||
client: Arc<redis::Client>,
|
||||
self_id: Arc<AtomicU64>,
|
||||
table: MessageTable,
|
||||
item_sender: UnboundedSender<Option<ProtocolItem>>,
|
||||
item_receiver: Mutex<Option<UnboundedReceiver<Option<ProtocolItem>>>>,
|
||||
event_sender: UnboundedSender<RecvDo>,
|
||||
event_receiver: Mutex<Option<UnboundedReceiver<RecvDo>>>,
|
||||
}
|
||||
|
||||
impl RedisRelay {
|
||||
pub fn new(
|
||||
path: &str,
|
||||
table: Vec<(TypeTag, Option<(TypeTag, TypeTag)>)>,
|
||||
) -> Result<Self, crate::error::Error> {
|
||||
let client = redis::Client::open(path)?;
|
||||
|
||||
let (item_sender, item_receiver) = mpsc::unbounded_channel();
|
||||
let (event_sender, event_receiver) = mpsc::unbounded_channel();
|
||||
|
||||
Ok(RedisRelay {
|
||||
client: Arc::new(client),
|
||||
self_id: Arc::new(AtomicU64::new(0)),
|
||||
table: MessageTable::from(table),
|
||||
item_sender,
|
||||
item_receiver: Mutex::new(Some(item_receiver)),
|
||||
event_sender,
|
||||
event_receiver: Mutex::new(Some(event_receiver)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeTagAccept for RedisRelay {
|
||||
fn accept_msg(&self, msg: &TypeTag) -> bool {
|
||||
self.table.accept_message(msg)
|
||||
}
|
||||
|
||||
fn accept_req(&self, msg: &TypeTag, resp: Option<&TypeTag>, err: Option<&TypeTag>) -> bool {
|
||||
self.table.accept_request(msg, resp, err)
|
||||
}
|
||||
|
||||
fn iter_types(&self) -> Box<dyn Iterator<Item = (TypeTag, Option<(TypeTag, TypeTag)>)> + '_> {
|
||||
let iter = self.table.iter_types();
|
||||
Box::new(iter.map(|(x, y)| (x.clone(), y.cloned())))
|
||||
}
|
||||
}
|
||||
|
||||
impl SendUntypedReceiver for RedisRelay {
|
||||
fn send(&self, msg: Action, _bus: &Bus) -> Result<(), messagebus::error::Error<Action>> {
|
||||
match msg {
|
||||
Action::Init(self_id) => {
|
||||
let event_sender = self.event_sender.clone();
|
||||
let mut rx = self.item_receiver.lock().take().unwrap();
|
||||
|
||||
let client = self.client.clone();
|
||||
self.self_id.store(self_id, Ordering::SeqCst);
|
||||
|
||||
tokio::spawn(async move {
|
||||
let mut connection = client.get_tokio_connection().await.unwrap();
|
||||
let mut body_buff = Vec::new();
|
||||
let mut header_buff = Vec::new();
|
||||
// let mut item = None;
|
||||
|
||||
event_sender.send(RecvDo::Ready).unwrap();
|
||||
|
||||
while let Some(Some(item)) = rx.recv().await {
|
||||
header_buff.clear();
|
||||
body_buff.clear();
|
||||
|
||||
let pkt = item.serialize(BodyType::Cbor, &mut body_buff).unwrap();
|
||||
|
||||
serde_cbor::to_writer(&mut header_buff, &pkt).unwrap();
|
||||
|
||||
let channel = match &item {
|
||||
ProtocolItem::Action(_) => "mbus_action".into(),
|
||||
ProtocolItem::Send(_, msg, _) => {
|
||||
format!("mbus_request::{}", msg.type_tag())
|
||||
}
|
||||
ProtocolItem::Event(_ev) => "mbus_response::".into(),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let () = connection.publish(channel, &header_buff).await.unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Action::Close => {
|
||||
self.item_sender.send(None).unwrap();
|
||||
// self.event_sender.send(RecvDo::Closed).unwrap();
|
||||
}
|
||||
|
||||
other => self.item_sender.send(Some(other.into())).unwrap(),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn send_msg(
|
||||
&self,
|
||||
mid: u64,
|
||||
msg: Box<dyn Message>,
|
||||
req: bool,
|
||||
_bus: &Bus,
|
||||
) -> Result<(), messagebus::error::Error<Box<dyn Message>>> {
|
||||
match msg.as_shared_boxed() {
|
||||
Ok(msg) => {
|
||||
if let Err(err) = self.item_sender.send(Some((mid, msg, req).into())) {
|
||||
Err(messagebus::error::Error::TryAgain(
|
||||
err.0.unwrap().unwrap_send().unwrap().1.upcast_box(),
|
||||
))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Err(msg) => Err(messagebus::error::Error::TryAgain(msg)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ReciveUntypedReceiver for RedisRelay {
|
||||
type Stream = GenericEventStream;
|
||||
|
||||
fn event_stream(&self, bus: Bus) -> Self::Stream {
|
||||
let self_id = self.self_id.clone();
|
||||
let sender = self.item_sender.clone();
|
||||
let mut recv = self.event_receiver.lock().take().unwrap();
|
||||
|
||||
Box::pin(
|
||||
futures::stream::poll_fn(move |cx| recv.poll_recv(cx))
|
||||
.map(move |recv_do| {
|
||||
let self_id = self_id.clone();
|
||||
let bus = bus.clone();
|
||||
let sender = sender.clone();
|
||||
|
||||
match recv_do {
|
||||
// RecvDo::Incoming(incoming) => {
|
||||
// futures::stream::unfold((incoming, bus, sender, self_id), |(mut incoming, bus, sender, self_id)| async move {
|
||||
// loop {
|
||||
// let (_, recv) = match incoming.next().await? {
|
||||
// Ok(recv) => recv,
|
||||
// Err(err) => {
|
||||
// println!("error: {}", err);
|
||||
// return None;
|
||||
// }
|
||||
// };
|
||||
|
||||
// let buff = recv
|
||||
// .read_to_end(usize::max_value())
|
||||
// .await
|
||||
// .unwrap();
|
||||
|
||||
// // assert_eq!(&buff[0..4], b"MBUS");
|
||||
|
||||
// if buff.is_empty() {
|
||||
// println!("PONG");
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// let mut reader = &buff[4..];
|
||||
|
||||
// let version = reader.get_u16();
|
||||
// let content_type = reader.get_u16();
|
||||
// let body_size = reader.get_u64();
|
||||
|
||||
// println!("inbound packet {}: v: {}; ct: {}; bs: {}", String::from_utf8_lossy(&buff[0..4]), version, content_type, body_size);
|
||||
|
||||
// let event = match content_type {
|
||||
// 0 => { // CBOR
|
||||
// let proto: ProtocolPacket = serde_cbor::from_slice(&buff[16..]).unwrap();
|
||||
// match proto.deserialize(&bus).unwrap() {
|
||||
// ProtocolItem::Event(ev) => ev.map_msg(|msg|msg.upcast_box()),
|
||||
// ProtocolItem::Action(action) => {
|
||||
// match action {
|
||||
// Action::Close => {
|
||||
// println!("warning: Close recevied - ignoring!");
|
||||
// sender.send(Some(ProtocolItem::Event(Event::Exited))).unwrap();
|
||||
// },
|
||||
// Action::Flush => {
|
||||
// bus.flush().await;
|
||||
// sender.send(Some(ProtocolItem::Event(Event::Flushed))).unwrap();
|
||||
// },
|
||||
// Action::Sync => {
|
||||
// bus.sync().await;
|
||||
// sender.send(Some(ProtocolItem::Event(Event::Synchronized(Ok(()))))).unwrap();
|
||||
// },
|
||||
// Action::Init(..) => (),
|
||||
// Action::Stats => (),
|
||||
// _ => (),
|
||||
// }
|
||||
// continue;
|
||||
// }
|
||||
// ProtocolItem::Send(mid, msg, req) => {
|
||||
// if req {
|
||||
// let res = bus.request_boxed(
|
||||
// msg.upcast_box(),
|
||||
// SendOptions::Except(self_id.load(Ordering::SeqCst))
|
||||
// )
|
||||
// .await
|
||||
// .map(|x|x.as_shared_boxed().unwrap())
|
||||
// .map_err(|x|x.map_msg(|_|()));
|
||||
|
||||
// sender.send(Some(ProtocolItem::Event(Event::Response(mid, res)))).unwrap();
|
||||
// } else {
|
||||
// let _ = bus.send_boxed(msg.upcast_box(), Default::default())
|
||||
// .await;
|
||||
// }
|
||||
|
||||
// continue;
|
||||
// }
|
||||
// _ => unimplemented!()
|
||||
// }
|
||||
// },
|
||||
// _ => unimplemented!()
|
||||
// };
|
||||
|
||||
// return Some((event, (incoming, bus, sender, self_id)));
|
||||
// }
|
||||
// }).right_stream()
|
||||
// }
|
||||
other => futures::stream::once(async move {
|
||||
match other {
|
||||
RecvDo::Ready => Event::Ready,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}), // .left_stream()
|
||||
}
|
||||
})
|
||||
.flatten(),
|
||||
)
|
||||
}
|
||||
}
|
429
crates/remote/src/relays/tcp/mod.rs
Normal file
429
crates/remote/src/relays/tcp/mod.rs
Normal file
@ -0,0 +1,429 @@
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
use bytes::{Buf, BufMut};
|
||||
use futures::stream::unfold;
|
||||
use futures::{pin_mut, Stream, StreamExt};
|
||||
use messagebus::error::GenericError;
|
||||
use messagebus::{
|
||||
Action, Bus, Event, EventBoxed, Message, ReciveUntypedReceiver, SendOptions,
|
||||
SendUntypedReceiver, TypeTag, TypeTagAccept, TypeTagAcceptItem,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf};
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender};
|
||||
|
||||
use crate::proto::{BodyType, ProtocolItem, ProtocolPacket};
|
||||
|
||||
use super::{GenericEventStream, MessageList, MessageTable};
|
||||
|
||||
pub struct TcpRelay {
|
||||
server_mode: bool,
|
||||
addr: SocketAddr,
|
||||
|
||||
self_id: Arc<AtomicU64>,
|
||||
in_table: MessageTable,
|
||||
// _out_table: MessageTable,
|
||||
item_sender: UnboundedSender<Option<ProtocolItem>>,
|
||||
item_receiver: Mutex<Option<UnboundedReceiver<Option<ProtocolItem>>>>,
|
||||
|
||||
event_sender: UnboundedSender<EventBoxed<GenericError>>,
|
||||
event_receiver: Mutex<Option<UnboundedReceiver<EventBoxed<GenericError>>>>,
|
||||
|
||||
stream_sender: UnboundedSender<OwnedReadHalf>,
|
||||
stream_receiver: Mutex<Option<UnboundedReceiver<OwnedReadHalf>>>,
|
||||
}
|
||||
|
||||
impl TcpRelay {
|
||||
pub fn new(server_mode: bool, addr: SocketAddr, table: (MessageList, MessageList)) -> Self {
|
||||
let (item_sender, item_receiver) = mpsc::unbounded_channel();
|
||||
let (event_sender, event_receiver) = mpsc::unbounded_channel();
|
||||
let (stream_sender, stream_receiver) = mpsc::unbounded_channel();
|
||||
|
||||
Self {
|
||||
self_id: Arc::new(AtomicU64::new(0)),
|
||||
server_mode,
|
||||
addr,
|
||||
item_sender,
|
||||
in_table: MessageTable::from(table.0),
|
||||
item_receiver: Mutex::new(Some(item_receiver)),
|
||||
event_sender,
|
||||
event_receiver: Mutex::new(Some(event_receiver)),
|
||||
stream_sender,
|
||||
stream_receiver: Mutex::new(Some(stream_receiver)),
|
||||
}
|
||||
}
|
||||
|
||||
fn connections(&self) -> impl Stream<Item = TcpRelayConnection> {
|
||||
unfold(
|
||||
(self.server_mode, self.addr),
|
||||
move |(sm, addr)| async move {
|
||||
let stream = if sm {
|
||||
let bind_res = TcpListener::bind(addr).await;
|
||||
let listener = match bind_res {
|
||||
Err(err) => {
|
||||
println!("bind error: {}", err);
|
||||
return None;
|
||||
}
|
||||
|
||||
Ok(listener) => listener,
|
||||
};
|
||||
|
||||
unfold((listener,), move |(listener,)| async move {
|
||||
let (stream, _addr) = match listener.accept().await {
|
||||
Err(err) => {
|
||||
println!("accept error: {}", err);
|
||||
return None;
|
||||
}
|
||||
|
||||
Ok(listener) => listener,
|
||||
};
|
||||
|
||||
Some((TcpRelayConnection::from(stream), (listener,)))
|
||||
})
|
||||
.left_stream()
|
||||
} else {
|
||||
unfold((addr,), move |(addr,)| async move {
|
||||
let stream = match TcpStream::connect(addr).await {
|
||||
Err(err) => {
|
||||
println!("connect error: {}", err);
|
||||
return None;
|
||||
}
|
||||
|
||||
Ok(listener) => listener,
|
||||
};
|
||||
|
||||
Some((TcpRelayConnection::from(stream), (addr,)))
|
||||
})
|
||||
.right_stream()
|
||||
};
|
||||
|
||||
Some((stream, (sm, addr)))
|
||||
},
|
||||
)
|
||||
.flatten()
|
||||
}
|
||||
}
|
||||
|
||||
struct TcpRelayConnection {
|
||||
recv: OwnedReadHalf,
|
||||
send: OwnedWriteHalf,
|
||||
}
|
||||
|
||||
impl From<TcpStream> for TcpRelayConnection {
|
||||
fn from(stream: TcpStream) -> Self {
|
||||
let (recv, send) = stream.into_split();
|
||||
TcpRelayConnection { recv, send }
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeTagAccept for TcpRelay {
|
||||
fn iter_types(&self) -> Box<dyn Iterator<Item = TypeTagAcceptItem> + '_> {
|
||||
let iter = self.in_table.iter_types();
|
||||
Box::new(iter.map(|(x, y)| (x.clone(), y.cloned())))
|
||||
}
|
||||
|
||||
fn accept_msg(&self, msg: &TypeTag) -> bool {
|
||||
self.in_table.accept_message(msg)
|
||||
}
|
||||
|
||||
fn accept_req(&self, req: &TypeTag, resp: Option<&TypeTag>, err: Option<&TypeTag>) -> bool {
|
||||
self.in_table.accept_request(req, resp, err)
|
||||
}
|
||||
}
|
||||
|
||||
impl SendUntypedReceiver for TcpRelay {
|
||||
fn send(&self, msg: Action, _bus: &Bus) -> Result<(), messagebus::error::Error<Action>> {
|
||||
match msg {
|
||||
Action::Init(self_id) => {
|
||||
let mut rx = match self.item_receiver.lock().take() {
|
||||
Some(x) => x,
|
||||
None => return Ok(()),
|
||||
};
|
||||
|
||||
let stream_sender = self.stream_sender.clone();
|
||||
let event_sender = self.event_sender.clone();
|
||||
|
||||
let incoming = self.connections();
|
||||
self.self_id.store(self_id, Ordering::SeqCst);
|
||||
|
||||
tokio::spawn(async move {
|
||||
pin_mut!(incoming);
|
||||
|
||||
let mut body_buff = Vec::new();
|
||||
let mut header_buff = Vec::new();
|
||||
let mut item = None;
|
||||
|
||||
loop {
|
||||
println!("begin");
|
||||
|
||||
let mut conn = match incoming.next().await {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
println!("No more connections. Message {:?} has been lost!", item);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
stream_sender.send(conn.recv).unwrap();
|
||||
event_sender.send(Event::Ready).unwrap();
|
||||
|
||||
loop {
|
||||
let r = if let Some(r) = item.take() {
|
||||
r
|
||||
} else {
|
||||
match rx.recv().await {
|
||||
Some(Some(r)) => r,
|
||||
None | Some(None) => {
|
||||
println!("closing");
|
||||
drop(conn.send);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
body_buff.clear();
|
||||
let pkt = r.serialize(BodyType::Cbor, &mut body_buff).unwrap();
|
||||
|
||||
header_buff.resize(16, 0);
|
||||
serde_cbor::to_writer(&mut header_buff, &pkt).unwrap();
|
||||
let body_size = header_buff.len() - 16;
|
||||
|
||||
let mut head = &mut header_buff[0..16];
|
||||
|
||||
head.put(&b"MBUS"[..]);
|
||||
head.put_u16(1);
|
||||
head.put_u16(0);
|
||||
head.put_u64(body_size as _);
|
||||
|
||||
if let Err(err) = conn.send.write_all(&header_buff).await {
|
||||
item = Some(r);
|
||||
println!(
|
||||
"write broken connection err {}. try with next connection",
|
||||
err
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
event_sender.send(Event::Pause).unwrap();
|
||||
}
|
||||
|
||||
println!("exit main loop");
|
||||
});
|
||||
}
|
||||
|
||||
Action::Close => {
|
||||
self.item_sender.send(None).unwrap();
|
||||
self.event_sender.send(Event::Exited).unwrap();
|
||||
}
|
||||
|
||||
other => self.item_sender.send(Some(other.into())).unwrap(),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn send_msg(
|
||||
&self,
|
||||
mid: u64,
|
||||
msg: Box<dyn Message>,
|
||||
req: bool,
|
||||
_bus: &Bus,
|
||||
) -> Result<(), messagebus::error::Error<Box<dyn Message>>> {
|
||||
match msg.as_shared_boxed() {
|
||||
Ok(msg) => {
|
||||
if let Err(err) = self.item_sender.send(Some((mid, msg, req).into())) {
|
||||
Err(messagebus::error::Error::TryAgain(
|
||||
err.0.unwrap().unwrap_send().unwrap().1.upcast_box(),
|
||||
))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Err(msg) => Err(messagebus::error::Error::TryAgain(msg)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ReciveUntypedReceiver for TcpRelay {
|
||||
type Stream = GenericEventStream;
|
||||
|
||||
fn event_stream(&self, bus: Bus) -> Self::Stream {
|
||||
let self_id = self.self_id.clone();
|
||||
|
||||
let mut recv_stream = self.stream_receiver.lock().take().unwrap();
|
||||
let mut recv_events = self.event_receiver.lock().take().unwrap();
|
||||
let sender = self.item_sender.clone();
|
||||
|
||||
let stream1 = futures::stream::poll_fn(move |cx| recv_stream.poll_recv(cx))
|
||||
.map(move |incoming| {
|
||||
let buff: Vec<u8> = Vec::with_capacity(1024);
|
||||
let bus = bus.clone();
|
||||
let self_id = self_id.clone();
|
||||
let sender = sender.clone();
|
||||
|
||||
futures::stream::unfold(
|
||||
(incoming, bus, sender, self_id, buff),
|
||||
|(mut recv, bus, sender, self_id, mut buff)| async move {
|
||||
loop {
|
||||
buff.resize(4, 0);
|
||||
if let Err(err) = recv.read_exact(&mut buff[..]).await {
|
||||
println!("recv err: {}", err);
|
||||
break None;
|
||||
}
|
||||
|
||||
if &buff == b"PING" {
|
||||
println!(">> PING");
|
||||
continue;
|
||||
}
|
||||
|
||||
if &buff != b"MBUS" {
|
||||
println!("Not MBUS packet!");
|
||||
continue;
|
||||
}
|
||||
|
||||
buff.resize(12, 0);
|
||||
if let Err(err) = recv.read_exact(&mut buff[..]).await {
|
||||
println!("recv err: {}", err);
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut reader = &buff[..];
|
||||
let _version = reader.get_u16();
|
||||
let content_type = reader.get_u16();
|
||||
let body_size = reader.get_u64();
|
||||
|
||||
buff.resize(body_size as _, 0);
|
||||
if let Err(err) = recv.read_exact(&mut buff[..]).await {
|
||||
println!("recv err: {}", err);
|
||||
continue;
|
||||
}
|
||||
|
||||
// println!("inbound packet MBUS v: {}; ct: {}; bs: {}",
|
||||
// version, content_type, body_size);
|
||||
|
||||
let event = match content_type {
|
||||
0 => {
|
||||
// CBOR
|
||||
let proto: ProtocolPacket =
|
||||
match serde_cbor::from_slice(&buff[..]) {
|
||||
Ok(val) => val,
|
||||
Err(err) => {
|
||||
println!("pkt parse err: {}", err);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let item: ProtocolItem = match proto.deserialize(&bus) {
|
||||
Ok(val) => val,
|
||||
Err(err) => {
|
||||
println!("item parse err: {}", err);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
match item {
|
||||
ProtocolItem::Event(ev) => {
|
||||
ev.map_msg(|msg| msg.upcast_box())
|
||||
}
|
||||
ProtocolItem::Action(action) => {
|
||||
match action {
|
||||
Action::Close => {
|
||||
println!("warning: Close recevied - ignoring!");
|
||||
sender
|
||||
.send(Some(ProtocolItem::Event(
|
||||
Event::Exited,
|
||||
)))
|
||||
.unwrap();
|
||||
}
|
||||
Action::Flush => {
|
||||
println!("flush");
|
||||
bus.flush_all().await;
|
||||
sender
|
||||
.send(Some(ProtocolItem::Event(
|
||||
Event::Flushed,
|
||||
)))
|
||||
.unwrap();
|
||||
}
|
||||
Action::Sync => {
|
||||
println!("sync");
|
||||
bus.sync_all().await;
|
||||
sender
|
||||
.send(Some(ProtocolItem::Event(
|
||||
Event::Synchronized(Ok(())),
|
||||
)))
|
||||
.unwrap();
|
||||
}
|
||||
Action::Init(..) => (),
|
||||
Action::Stats => (),
|
||||
_ => (),
|
||||
}
|
||||
continue;
|
||||
}
|
||||
ProtocolItem::Send(mid, msg, req) => {
|
||||
let self_id = self_id.clone();
|
||||
let sender = sender.clone();
|
||||
let bus = bus.clone();
|
||||
|
||||
let _ = tokio::spawn(async move {
|
||||
if req {
|
||||
let res = bus
|
||||
.request_boxed(
|
||||
msg.upcast_box(),
|
||||
SendOptions::Except(
|
||||
self_id.load(Ordering::SeqCst),
|
||||
),
|
||||
)
|
||||
.await
|
||||
.map(|x| x.as_shared_boxed().unwrap())
|
||||
.map_err(|x| x.map_msg(|_| ()));
|
||||
|
||||
sender
|
||||
.send(Some(ProtocolItem::Event(
|
||||
Event::Response(mid, res),
|
||||
)))
|
||||
.unwrap();
|
||||
} else {
|
||||
let tt = msg.type_tag();
|
||||
let _ = bus
|
||||
.send_boxed(
|
||||
msg.upcast_box(),
|
||||
Default::default(),
|
||||
)
|
||||
.await;
|
||||
|
||||
sender
|
||||
.send(Some(ProtocolItem::Event(
|
||||
Event::BatchComplete(tt, 1),
|
||||
)))
|
||||
.unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
continue;
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
return Some((event, (recv, bus, sender, self_id, buff)));
|
||||
}
|
||||
},
|
||||
)
|
||||
})
|
||||
.flatten();
|
||||
|
||||
let stream2 = futures::stream::poll_fn(move |cx| recv_events.poll_recv(cx));
|
||||
Box::pin(
|
||||
futures::stream::select(stream1, stream2)
|
||||
.take_while(|x| futures::future::ready(!matches!(x, Event::Exited))),
|
||||
)
|
||||
}
|
||||
}
|
168
examples/benchmark.rs
Normal file
168
examples/benchmark.rs
Normal file
@ -0,0 +1,168 @@
|
||||
use std::time::Instant;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use messagebus::{
|
||||
derive::Message, error, receivers::BufferUnorderedConfig, AsyncHandler, Bus, Message,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error, messagebus::derive::Error)]
|
||||
enum Error {
|
||||
#[error("Error({0})")]
|
||||
Error(anyhow::Error),
|
||||
}
|
||||
|
||||
impl<M: Message> From<error::Error<M>> for Error {
|
||||
fn from(err: error::Error<M>) -> Self {
|
||||
Self::Error(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
struct TmpReceiver;
|
||||
struct TmpReceiver2;
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[message(clone)]
|
||||
struct MsgF32(f32);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[message(clone)]
|
||||
struct MsgU16(u16);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[message(clone)]
|
||||
struct MsgU32(u32);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[message(clone)]
|
||||
struct MsgI32(i32);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[message(clone)]
|
||||
struct MsgI16(i16);
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<MsgF32> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, _msg: MsgF32, bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
tokio::time::sleep(std::time::Duration::from_millis(1)).await;
|
||||
bus.send(MsgU16(1)).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<MsgU16> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, _msg: MsgU16, bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
tokio::time::sleep(std::time::Duration::from_millis(1)).await;
|
||||
bus.send(MsgU32(2)).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<MsgU32> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, _msg: MsgU32, bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
tokio::time::sleep(std::time::Duration::from_millis(1)).await;
|
||||
bus.send(MsgI32(3)).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<MsgI32> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, _msg: MsgI32, bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
tokio::time::sleep(std::time::Duration::from_millis(1)).await;
|
||||
bus.send(MsgI16(4)).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<MsgI16> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, _msg: MsgI16, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<MsgI32> for TmpReceiver2 {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, _msg: MsgI32, bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
tokio::time::sleep(std::time::Duration::from_millis(1)).await;
|
||||
bus.send(MsgI16(5)).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
async fn iter(bus: &Bus) {
|
||||
for _ in 0..10_000 {
|
||||
bus.send(MsgF32(0.)).await.unwrap();
|
||||
}
|
||||
|
||||
bus.flush_all().await;
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let cfg = BufferUnorderedConfig {
|
||||
buffer_size: 8,
|
||||
max_parallel: 8,
|
||||
};
|
||||
|
||||
let (b, poller) = Bus::build()
|
||||
.register(TmpReceiver)
|
||||
.subscribe_async::<MsgF32>(cfg.buffer_size as _, cfg)
|
||||
.subscribe_async::<MsgU16>(cfg.buffer_size as _, cfg)
|
||||
.subscribe_async::<MsgU32>(cfg.buffer_size as _, cfg)
|
||||
.subscribe_async::<MsgI32>(cfg.buffer_size as _, cfg)
|
||||
.subscribe_async::<MsgI16>(cfg.buffer_size as _, cfg)
|
||||
.done()
|
||||
.register(TmpReceiver2)
|
||||
.subscribe_async::<MsgI32>(cfg.buffer_size as _, cfg)
|
||||
.done()
|
||||
.build();
|
||||
|
||||
iter(&b).await;
|
||||
|
||||
let count = 5;
|
||||
|
||||
let mut time_sum = 0;
|
||||
for _ in 0..count {
|
||||
let inst = Instant::now();
|
||||
iter(&b).await;
|
||||
let diff = inst.elapsed();
|
||||
|
||||
time_sum += diff.as_micros();
|
||||
}
|
||||
|
||||
println!("Avg time: {:.4}", time_sum as f64 / (count as f64 * 1000.0));
|
||||
|
||||
println!("flush");
|
||||
b.flush_all().await;
|
||||
|
||||
println!("close");
|
||||
b.close().await;
|
||||
|
||||
println!("closed");
|
||||
|
||||
poller.await;
|
||||
println!("[done]");
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
use messagebus::{receivers, Bus, Handler, Result as MbusResult};
|
||||
|
||||
struct TmpReceiver;
|
||||
struct TmpReceiver2;
|
||||
|
||||
impl Handler<f32> for TmpReceiver {
|
||||
fn handle(&self, msg: f32, bus: &Bus) -> MbusResult {
|
||||
bus.try_send(1u16).unwrap();
|
||||
|
||||
println!("---> f32 {}", msg);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler<u16> for TmpReceiver {
|
||||
fn handle(&self, msg: u16, bus: &Bus) -> MbusResult {
|
||||
bus.try_send(1u32).unwrap();
|
||||
println!("---> u16 {}", msg);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler<u32> for TmpReceiver {
|
||||
fn handle(&self, msg: u32, bus: &Bus) -> MbusResult {
|
||||
bus.try_send(2i32).unwrap();
|
||||
println!("---> u32 {}", msg);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler<i32> for TmpReceiver {
|
||||
fn handle(&self, msg: i32, bus: &Bus) -> MbusResult {
|
||||
bus.try_send(3i16).unwrap();
|
||||
println!("---> i32 {}", msg);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler<i16> for TmpReceiver {
|
||||
fn handle(&self, msg: i16, _bus: &Bus) -> MbusResult {
|
||||
println!("---> i16 {}", msg);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler<i32> for TmpReceiver2 {
|
||||
fn handle(&self, msg: i32, bus: &Bus) -> MbusResult {
|
||||
bus.try_send(3i16).unwrap();
|
||||
println!("---> 2 i32 {}", msg);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler<i16> for TmpReceiver2 {
|
||||
fn handle(&self, msg: i16, _bus: &Bus) -> MbusResult {
|
||||
println!("---> 2 i16 {}", msg);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let (b, poller) = Bus::build()
|
||||
.register(TmpReceiver)
|
||||
.subscribe::<f32, receivers::BufferUnorderedSync<_>>(Default::default())
|
||||
.subscribe::<u16, receivers::BufferUnorderedSync<_>>(Default::default())
|
||||
.subscribe::<u32, receivers::BufferUnorderedSync<_>>(Default::default())
|
||||
.subscribe::<i32, receivers::BufferUnorderedSync<_>>(Default::default())
|
||||
.subscribe::<i16, receivers::BufferUnorderedSync<_>>(Default::default())
|
||||
.done()
|
||||
.register(TmpReceiver2)
|
||||
.subscribe::<i32, receivers::BufferUnorderedSync<_>>(Default::default())
|
||||
.subscribe::<i16, receivers::BufferUnorderedSync<_>>(Default::default())
|
||||
.done()
|
||||
.build();
|
||||
|
||||
b.send(32f32).await.unwrap();
|
||||
poller.await
|
||||
}
|
@ -1,72 +1,166 @@
|
||||
use async_trait::async_trait;
|
||||
use messagebus::{receivers, AsyncHandler, Bus, Handler, Result as MbusResult};
|
||||
use messagebus::{derive::Message, error, AsyncHandler, Bus, Handler, Message, TypeTagged};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error, messagebus::derive::Error)]
|
||||
enum Error {
|
||||
#[error("Error({0})")]
|
||||
Error(anyhow::Error),
|
||||
}
|
||||
|
||||
impl<M: Message> From<error::Error<M>> for Error {
|
||||
fn from(err: error::Error<M>) -> Self {
|
||||
Self::Error(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
struct TmpReceiver;
|
||||
struct TmpReceiver2;
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<f32> for TmpReceiver {
|
||||
async fn handle(&self, msg: f32, bus: &Bus) -> MbusResult {
|
||||
bus.send(1u16).await?;
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[message(clone)]
|
||||
struct MsgF32(f32);
|
||||
|
||||
println!("---> f32 {}", msg);
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[message(clone)]
|
||||
struct MsgU16(u16);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[message(clone)]
|
||||
struct MsgU32(u32);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[message(clone)]
|
||||
struct MsgI32(i32);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[message(clone)]
|
||||
struct MsgI16(i16);
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<MsgF32> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, msg: MsgF32, bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
bus.send(MsgU16(1)).await?;
|
||||
|
||||
println!("TmpReceiver ---> {:?} {}", msg, msg.type_tag());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
println!("TmpReceiver f32: sync");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<u16> for TmpReceiver {
|
||||
async fn handle(&self, msg: u16, bus: &Bus) -> MbusResult {
|
||||
bus.send(2u32).await?;
|
||||
println!("---> u16 {}", msg);
|
||||
impl AsyncHandler<MsgU16> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, msg: MsgU16, bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
bus.send(MsgU32(2)).await?;
|
||||
println!("TmpReceiver ---> {:?}", msg);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
println!("TmpReceiver u16: sync");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<u32> for TmpReceiver {
|
||||
async fn handle(&self, msg: u32, bus: &Bus) -> MbusResult {
|
||||
bus.send(3i32).await?;
|
||||
println!("---> u32 {}", msg);
|
||||
impl AsyncHandler<MsgU32> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, msg: MsgU32, bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
bus.send(MsgI32(3)).await?;
|
||||
println!("TmpReceiver ---> {:?}", msg);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
println!("TmpReceiver u32: sync");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<i32> for TmpReceiver {
|
||||
async fn handle(&self, msg: i32, bus: &Bus) -> MbusResult {
|
||||
bus.send(4i16).await?;
|
||||
println!("---> i32 {}", msg);
|
||||
impl AsyncHandler<MsgI32> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, msg: MsgI32, bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
bus.send(MsgI16(4)).await?;
|
||||
println!("TmpReceiver ---> {:?}", msg);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
println!("TmpReceiver i32: sync");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<i16> for TmpReceiver {
|
||||
async fn handle(&self, msg: i16, _bus: &Bus) -> MbusResult {
|
||||
println!("---> i16 {}", msg);
|
||||
impl AsyncHandler<MsgI16> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, msg: MsgI16, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
println!("TmpReceiver ---> {:?}", msg);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
println!("TmpReceiver i16: sync");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<i32> for TmpReceiver2 {
|
||||
async fn handle(&self, msg: i32, bus: &Bus) -> MbusResult {
|
||||
bus.send(5i16).await?;
|
||||
println!("---> 2 i32 {}", msg);
|
||||
impl AsyncHandler<MsgI32> for TmpReceiver2 {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, msg: MsgI32, bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
println!("TmpReceiver2: ---> {:?}", msg);
|
||||
|
||||
bus.send(MsgI16(5)).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
println!("TmpReceiver2: i32: sync");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler<i16> for TmpReceiver2 {
|
||||
fn handle(&self, msg: i16, _bus: &Bus) -> MbusResult {
|
||||
println!("---> 2 i16 {}", msg);
|
||||
impl Handler<MsgI16> for TmpReceiver2 {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
fn handle(&self, msg: MsgI16, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
println!("TmpReceiver2: ---> {:?}", msg);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
println!("TmpReceiver2: i16: sync");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -74,20 +168,32 @@ impl Handler<i16> for TmpReceiver2 {
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
env_logger::init();
|
||||
|
||||
let (b, poller) = Bus::build()
|
||||
.register(TmpReceiver)
|
||||
.subscribe::<f32, receivers::BufferUnorderedAsync<_>>(Default::default())
|
||||
.subscribe::<u16, receivers::BufferUnorderedAsync<_>>(Default::default())
|
||||
.subscribe::<u32, receivers::BufferUnorderedAsync<_>>(Default::default())
|
||||
.subscribe::<i32, receivers::BufferUnorderedAsync<_>>(Default::default())
|
||||
.subscribe::<i16, receivers::BufferUnorderedAsync<_>>(Default::default())
|
||||
.subscribe_async::<MsgF32>(8, Default::default())
|
||||
.subscribe_async::<MsgU16>(8, Default::default())
|
||||
.subscribe_async::<MsgU32>(8, Default::default())
|
||||
.subscribe_async::<MsgI32>(8, Default::default())
|
||||
.subscribe_async::<MsgI16>(8, Default::default())
|
||||
.done()
|
||||
.register(TmpReceiver2)
|
||||
.subscribe::<i32, receivers::BufferUnorderedAsync<_>>(Default::default())
|
||||
.subscribe::<i16, receivers::BufferUnorderedSync<_>>(Default::default())
|
||||
.subscribe_async::<MsgI32>(8, Default::default())
|
||||
.subscribe_sync::<MsgI16>(8, Default::default())
|
||||
.done()
|
||||
.build();
|
||||
|
||||
b.send(0f32).await.unwrap();
|
||||
poller.await
|
||||
b.send(MsgF32(0.)).await.unwrap();
|
||||
|
||||
println!("flush");
|
||||
b.flush_all().await;
|
||||
|
||||
println!("close");
|
||||
b.close().await;
|
||||
|
||||
println!("closed");
|
||||
|
||||
poller.await;
|
||||
println!("[done]");
|
||||
}
|
||||
|
@ -1,63 +0,0 @@
|
||||
use messagebus::{receivers, Bus, Handler, Result as MbusResult};
|
||||
|
||||
struct TmpReceiver;
|
||||
|
||||
impl Handler<f32> for TmpReceiver {
|
||||
fn handle(&self, msg: f32, _bus: &Bus) -> MbusResult {
|
||||
println!("---> f32 {}", msg);
|
||||
|
||||
std::thread::sleep(std::time::Duration::from_secs(1));
|
||||
|
||||
println!("done");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let (b, poller) = Bus::build()
|
||||
.register(TmpReceiver)
|
||||
.subscribe::<f32, receivers::BufferUnorderedSync<_>>(receivers::BufferUnorderedConfig {
|
||||
buffer_size: 1,
|
||||
max_parallel: 1,
|
||||
})
|
||||
.done()
|
||||
.build();
|
||||
|
||||
println!("sending 1");
|
||||
b.send(32f32).await.unwrap();
|
||||
|
||||
println!("sending 2");
|
||||
b.send(32f32).await.unwrap();
|
||||
|
||||
println!("sending 3");
|
||||
b.send(32f32).await.unwrap();
|
||||
|
||||
println!("sending 4");
|
||||
b.send(32f32).await.unwrap();
|
||||
|
||||
println!("sending 5");
|
||||
b.send(32f32).await.unwrap();
|
||||
|
||||
println!("sending 6");
|
||||
b.send(32f32).await.unwrap();
|
||||
|
||||
println!("sending 7");
|
||||
b.send(32f32).await.unwrap();
|
||||
|
||||
println!("sending 8");
|
||||
b.send(32f32).await.unwrap();
|
||||
|
||||
println!("sending 9");
|
||||
b.send(32f32).await.unwrap();
|
||||
|
||||
println!("sending 10");
|
||||
b.send(32f32).await.unwrap();
|
||||
|
||||
println!("sending 11");
|
||||
b.send(32f32).await.unwrap();
|
||||
|
||||
println!("finish");
|
||||
|
||||
poller.await;
|
||||
}
|
211
examples/demo_boxed.rs
Normal file
211
examples/demo_boxed.rs
Normal file
@ -0,0 +1,211 @@
|
||||
use async_trait::async_trait;
|
||||
use messagebus::{
|
||||
derive::{Error as MbError, Message},
|
||||
error, AsyncHandler, Bus, Handler, Message,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error, MbError)]
|
||||
enum Error {
|
||||
#[error("Error({0})")]
|
||||
Error(anyhow::Error),
|
||||
}
|
||||
|
||||
impl<M: Message> From<error::Error<M>> for Error {
|
||||
fn from(err: error::Error<M>) -> Self {
|
||||
Self::Error(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[message(clone)]
|
||||
struct MsgF32(f32);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[message(clone)]
|
||||
struct MsgU16(u16);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[message(clone)]
|
||||
struct MsgU32(u32);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[message(clone)]
|
||||
struct MsgI32(i32);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[message(clone)]
|
||||
struct MsgI16(i16);
|
||||
|
||||
struct TmpReceiver;
|
||||
struct TmpReceiver2;
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<MsgF32> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, msg: MsgF32, bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
bus.send(MsgU16(1u16)).await?;
|
||||
|
||||
println!("TmpReceiver ---> {:?}", msg);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
println!("TmpReceiver f32: sync");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<MsgU16> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, msg: MsgU16, bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
bus.send(MsgU32(2u32)).await?;
|
||||
println!("TmpReceiver ---> {:?}", msg);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
println!("TmpReceiver u16: sync");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<MsgU32> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, msg: MsgU32, bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
bus.send(MsgI32(3i32)).await?;
|
||||
println!("TmpReceiver ---> {:?}", msg);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
println!("TmpReceiver u32: sync");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<MsgI32> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, msg: MsgI32, bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
bus.send(MsgI16(4i16)).await?;
|
||||
println!("TmpReceiver ---> {:?}", msg);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
println!("TmpReceiver i32: sync");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<MsgI16> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, msg: MsgI16, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
println!("TmpReceiver ---> {:?}", msg);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
println!("TmpReceiver i16: sync");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<MsgI32> for TmpReceiver2 {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, msg: MsgI32, bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
println!("TmpReceiver2: ---> {:?}", msg);
|
||||
|
||||
bus.send(MsgI16(5i16)).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
println!("TmpReceiver2: i32: sync");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler<MsgI16> for TmpReceiver2 {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
fn handle(&self, msg: MsgI16, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
println!("TmpReceiver2: ---> {:?}", msg);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
println!("TmpReceiver2: i16: sync");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
env_logger::init();
|
||||
|
||||
let (b, poller) = Bus::build()
|
||||
.register(TmpReceiver)
|
||||
.subscribe_async::<MsgF32>(8, Default::default())
|
||||
.subscribe_async::<MsgU16>(8, Default::default())
|
||||
.subscribe_async::<MsgU32>(8, Default::default())
|
||||
.subscribe_async::<MsgI32>(8, Default::default())
|
||||
.subscribe_async::<MsgI16>(8, Default::default())
|
||||
.done()
|
||||
.register(TmpReceiver2)
|
||||
.subscribe_async::<MsgI32>(8, Default::default())
|
||||
.subscribe_sync::<MsgI16>(8, Default::default())
|
||||
.done()
|
||||
.build();
|
||||
|
||||
b.send(MsgF32(0f32)).await.unwrap();
|
||||
println!("flush");
|
||||
|
||||
b.flush_all().await;
|
||||
|
||||
println!("sending boxed variant");
|
||||
|
||||
b.send_boxed(Box::new(MsgF32(0f32)), Default::default())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
println!("flush");
|
||||
b.flush_all().await;
|
||||
|
||||
println!("close");
|
||||
b.close().await;
|
||||
|
||||
println!("closed");
|
||||
|
||||
poller.await;
|
||||
println!("[done]");
|
||||
}
|
57
examples/demo_relay.rs
Normal file
57
examples/demo_relay.rs
Normal file
@ -0,0 +1,57 @@
|
||||
use messagebus::{
|
||||
derive::{Error as MbError, Message},
|
||||
error, Bus, Handler, Message, MessageBounds, Module,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error, MbError)]
|
||||
enum Error {
|
||||
#[error("Error({0})")]
|
||||
Error(anyhow::Error),
|
||||
}
|
||||
|
||||
impl<M: Message> From<error::Error<M>> for Error {
|
||||
fn from(err: error::Error<M>) -> Self {
|
||||
Self::Error(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
pub struct Msg<F: MessageBounds + Clone>(pub F);
|
||||
|
||||
struct TmpReceiver;
|
||||
|
||||
impl Handler<Msg<u32>> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
fn handle(&self, msg: Msg<u32>, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
println!("---> u32 {:?}", msg);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn module() -> Module {
|
||||
Module::new()
|
||||
.register(TmpReceiver)
|
||||
.subscribe_sync::<Msg<u32>>(8, Default::default())
|
||||
.done()
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let (b, poller) = Bus::build().add_module(module()).build();
|
||||
|
||||
// b.
|
||||
|
||||
println!("flush");
|
||||
b.flush_all().await;
|
||||
|
||||
println!("close");
|
||||
b.close().await;
|
||||
|
||||
println!("closed");
|
||||
|
||||
poller.await;
|
||||
println!("[done]");
|
||||
}
|
@ -1,10 +1,38 @@
|
||||
use messagebus::{receivers, Bus, Handler, Result as MbusResult};
|
||||
use messagebus::{
|
||||
derive::{Error as MbError, Message},
|
||||
error, Bus, Handler, Message, Module,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error, MbError)]
|
||||
enum Error {
|
||||
#[error("Error({0})")]
|
||||
Error(anyhow::Error),
|
||||
}
|
||||
|
||||
impl<M: Message> From<error::Error<M>> for Error {
|
||||
fn from(err: error::Error<M>) -> Self {
|
||||
Self::Error(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
struct MsgF32(pub f32);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
struct MsgU32(pub u32);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
struct MsgU16(pub u16);
|
||||
|
||||
struct TmpReceiver;
|
||||
|
||||
impl Handler<f32> for TmpReceiver {
|
||||
fn handle(&self, msg: f32, _bus: &Bus) -> MbusResult {
|
||||
println!("---> f32 {}", msg);
|
||||
impl Handler<MsgF32> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
fn handle(&self, msg: MsgF32, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
println!("---> f32 {:?}", msg);
|
||||
|
||||
std::thread::sleep(std::time::Duration::from_secs(5));
|
||||
|
||||
@ -14,33 +42,51 @@ impl Handler<f32> for TmpReceiver {
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler<u16> for TmpReceiver {
|
||||
fn handle(&self, msg: u16, _bus: &Bus) -> MbusResult {
|
||||
println!("---> u16 {}", msg);
|
||||
impl Handler<MsgU16> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
fn handle(&self, msg: MsgU16, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
println!("---> u16 {:?}", msg);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler<u32> for TmpReceiver {
|
||||
fn handle(&self, msg: u32, _bus: &Bus) -> MbusResult {
|
||||
println!("---> u32 {}", msg);
|
||||
impl Handler<MsgU32> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
fn handle(&self, msg: MsgU32, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
println!("---> u32 {:?}", msg);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn module() -> Module {
|
||||
Module::new()
|
||||
.register(TmpReceiver)
|
||||
.subscribe_sync::<MsgF32>(8, Default::default())
|
||||
.subscribe_sync::<MsgU16>(8, Default::default())
|
||||
.subscribe_sync::<MsgU32>(8, Default::default())
|
||||
.done()
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let (b, poller) = Bus::build()
|
||||
.register(TmpReceiver)
|
||||
.subscribe::<f32, receivers::BufferUnorderedSync<_>>(Default::default())
|
||||
.subscribe::<u16, receivers::BufferUnorderedSync<_>>(Default::default())
|
||||
.subscribe::<u32, receivers::BufferUnorderedSync<_>>(Default::default())
|
||||
.done()
|
||||
.build();
|
||||
let (b, poller) = Bus::build().add_module(module()).build();
|
||||
|
||||
b.send(32f32).await.unwrap();
|
||||
b.send(11u16).await.unwrap();
|
||||
b.send(32u32).await.unwrap();
|
||||
b.send(MsgF32(32f32)).await.unwrap();
|
||||
b.send(MsgU16(11u16)).await.unwrap();
|
||||
b.send(MsgU32(32u32)).await.unwrap();
|
||||
|
||||
poller.await
|
||||
println!("flush");
|
||||
b.flush_all().await;
|
||||
|
||||
println!("close");
|
||||
b.close().await;
|
||||
|
||||
println!("closed");
|
||||
|
||||
poller.await;
|
||||
println!("[done]");
|
||||
}
|
||||
|
93
examples/demo_sync_batch.rs
Normal file
93
examples/demo_sync_batch.rs
Normal file
@ -0,0 +1,93 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use messagebus::{
|
||||
derive::{Error as MbError, Message},
|
||||
error, AsyncBatchSynchronizedHandler, BatchSynchronizedHandler, Bus, Message,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error, Clone, MbError)]
|
||||
enum Error {
|
||||
#[error("Error({0})")]
|
||||
Error(Arc<anyhow::Error>),
|
||||
}
|
||||
|
||||
impl<M: Message> From<error::Error<M>> for Error {
|
||||
fn from(err: error::Error<M>) -> Self {
|
||||
Self::Error(Arc::new(err.into()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[message(clone)]
|
||||
struct MsgI32(i32);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[message(clone)]
|
||||
struct MsgI16(i16);
|
||||
|
||||
struct TmpReceiver;
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncBatchSynchronizedHandler<MsgI32> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
type InBatch = Vec<MsgI32>;
|
||||
type OutBatch = Vec<()>;
|
||||
|
||||
async fn handle(
|
||||
&mut self,
|
||||
msg: Vec<MsgI32>,
|
||||
_bus: &Bus,
|
||||
) -> Result<Vec<Self::Response>, Self::Error> {
|
||||
println!("---> [i32; {}] {:?}", msg.len(), msg);
|
||||
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
impl BatchSynchronizedHandler<MsgI16> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
type InBatch = Vec<MsgI16>;
|
||||
type OutBatch = Vec<()>;
|
||||
|
||||
fn handle(&mut self, msg: Vec<MsgI16>, _bus: &Bus) -> Result<Vec<Self::Response>, Self::Error> {
|
||||
println!("---> [i16; {}] {:?}", msg.len(), msg);
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let (b, poller) = Bus::build()
|
||||
.register_unsync(TmpReceiver)
|
||||
.subscribe_batch_async::<MsgI32>(16, Default::default())
|
||||
.subscribe_batch_sync::<MsgI16>(16, Default::default())
|
||||
.done()
|
||||
.build();
|
||||
|
||||
for i in 1..100i32 {
|
||||
b.send(MsgI32(i)).await.unwrap();
|
||||
}
|
||||
|
||||
b.send(MsgI16(1i16)).await.unwrap();
|
||||
b.send(MsgI16(2i16)).await.unwrap();
|
||||
b.send(MsgI16(3i16)).await.unwrap();
|
||||
b.send(MsgI16(4i16)).await.unwrap();
|
||||
b.send(MsgI16(5i16)).await.unwrap();
|
||||
b.send(MsgI16(6i16)).await.unwrap();
|
||||
b.send(MsgI16(7i16)).await.unwrap();
|
||||
|
||||
println!("flush");
|
||||
b.flush_all().await;
|
||||
|
||||
println!("close");
|
||||
b.close().await;
|
||||
|
||||
println!("closed");
|
||||
|
||||
poller.await;
|
||||
println!("[done]");
|
||||
}
|
@ -1,24 +1,51 @@
|
||||
use messagebus::{receivers, Bus, Result as MbusResult, SynchronizedHandler};
|
||||
use receivers::SynchronizedConfig;
|
||||
use async_trait::async_trait;
|
||||
use messagebus::{
|
||||
derive::{Error as MbError, Message},
|
||||
error, AsyncSynchronizedHandler, Bus, Message, SynchronizedHandler,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error, MbError)]
|
||||
enum Error {
|
||||
#[error("Error({0})")]
|
||||
Error(anyhow::Error),
|
||||
}
|
||||
|
||||
impl<M: Message> From<error::Error<M>> for Error {
|
||||
fn from(err: error::Error<M>) -> Self {
|
||||
Self::Error(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
struct MsgF32(pub f32);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
struct MsgI16(pub i16);
|
||||
|
||||
struct TmpReceiver;
|
||||
|
||||
impl SynchronizedHandler<f32> for TmpReceiver {
|
||||
fn handle(&mut self, msg: f32, _bus: &Bus) -> MbusResult {
|
||||
println!("---> f32 {}", msg);
|
||||
impl SynchronizedHandler<MsgF32> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
std::thread::sleep(std::time::Duration::from_secs(1));
|
||||
fn handle(&mut self, msg: MsgF32, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
// std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
println!("---> f32 {:?}", msg);
|
||||
|
||||
println!("done");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl SynchronizedHandler<i16> for TmpReceiver {
|
||||
fn handle(&mut self, msg: i16, _bus: &Bus) -> MbusResult {
|
||||
println!("---> i16 {}", msg);
|
||||
#[async_trait]
|
||||
impl AsyncSynchronizedHandler<MsgI16> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
std::thread::sleep(std::time::Duration::from_secs(1));
|
||||
async fn handle(&mut self, msg: MsgI16, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
println!("---> i16 {:?}", msg);
|
||||
|
||||
println!("done");
|
||||
Ok(())
|
||||
@ -29,29 +56,42 @@ impl SynchronizedHandler<i16> for TmpReceiver {
|
||||
async fn main() {
|
||||
let (b, poller) = Bus::build()
|
||||
.register_unsync(TmpReceiver)
|
||||
.subscribe::<f32, receivers::SynchronizedSync<_>>(SynchronizedConfig { buffer_size: 1 })
|
||||
.subscribe::<i16, receivers::SynchronizedSync<_>>(Default::default())
|
||||
.subscribe_sync::<MsgF32>(8, Default::default())
|
||||
.subscribe_async::<MsgI16>(8, Default::default())
|
||||
.done()
|
||||
.build();
|
||||
|
||||
b.send(12.0f32).await.unwrap();
|
||||
b.send(1i16).await.unwrap();
|
||||
b.send(12.0f32).await.unwrap();
|
||||
b.send(1i16).await.unwrap();
|
||||
b.send(12.0f32).await.unwrap();
|
||||
b.send(1i16).await.unwrap();
|
||||
b.send(12.0f32).await.unwrap();
|
||||
b.send(1i16).await.unwrap();
|
||||
b.send(12.0f32).await.unwrap();
|
||||
b.send(1i16).await.unwrap();
|
||||
b.send(12.0f32).await.unwrap();
|
||||
b.send(1i16).await.unwrap();
|
||||
b.send(12.0f32).await.unwrap();
|
||||
b.send(1i16).await.unwrap();
|
||||
b.send(12.0f32).await.unwrap();
|
||||
b.send(1i16).await.unwrap();
|
||||
b.send(MsgF32(12.0f32)).await.unwrap();
|
||||
b.send(MsgI16(1i16)).await.unwrap();
|
||||
b.send(MsgF32(12.0f32)).await.unwrap();
|
||||
b.send(MsgI16(1i16)).await.unwrap();
|
||||
b.send(MsgF32(12.0f32)).await.unwrap();
|
||||
b.send(MsgI16(1i16)).await.unwrap();
|
||||
b.send(MsgF32(12.0f32)).await.unwrap();
|
||||
b.send(MsgI16(1i16)).await.unwrap();
|
||||
b.send(MsgF32(12.0f32)).await.unwrap();
|
||||
b.send(MsgI16(1i16)).await.unwrap();
|
||||
b.send(MsgF32(12.0f32)).await.unwrap();
|
||||
b.send(MsgI16(1i16)).await.unwrap();
|
||||
b.send(MsgF32(12.0f32)).await.unwrap();
|
||||
b.send(MsgI16(1i16)).await.unwrap();
|
||||
b.send(MsgF32(12.0f32)).await.unwrap();
|
||||
b.send(MsgI16(1i16)).await.unwrap();
|
||||
|
||||
println!("finish");
|
||||
b.send(MsgF32(12.0f32)).await.unwrap();
|
||||
b.send(MsgI16(1i16)).await.unwrap();
|
||||
|
||||
println!("flush");
|
||||
|
||||
b.flush_all().await;
|
||||
|
||||
println!("closing");
|
||||
|
||||
b.close().await;
|
||||
|
||||
println!("closed");
|
||||
|
||||
poller.await;
|
||||
|
||||
println!("[done]");
|
||||
}
|
||||
|
396
src/builder.rs
396
src/builder.rs
@ -1,160 +1,388 @@
|
||||
use std::{any::TypeId, collections::HashMap, marker::PhantomData, pin::Pin, sync::Arc};
|
||||
use core::{marker::PhantomData, pin::Pin};
|
||||
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
sync::{
|
||||
atomic::{AtomicU64, Ordering},
|
||||
Arc,
|
||||
},
|
||||
};
|
||||
|
||||
use futures::{Future, FutureExt};
|
||||
use receiver::ReceiverTrait;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::{
|
||||
receiver::{self, Receiver},
|
||||
Bus, BusInner, Message, Untyped,
|
||||
error::StdSyncSendError,
|
||||
receiver::{
|
||||
BusPollerCallback, Receiver, ReciveTypedReceiver, SendTypedReceiver, SendUntypedReceiver,
|
||||
UntypedPollerCallback,
|
||||
},
|
||||
receivers, AsyncBatchHandler, AsyncBatchSynchronizedHandler, AsyncHandler,
|
||||
AsyncSynchronizedHandler, BatchHandler, BatchSynchronizedHandler, Bus, BusInner, Handler,
|
||||
Message, Relay, SynchronizedHandler, Untyped,
|
||||
};
|
||||
|
||||
pub trait ReceiverSubscriber<T: 'static> {
|
||||
fn subscribe(
|
||||
self,
|
||||
) -> (
|
||||
Arc<dyn ReceiverTrait>,
|
||||
Box<
|
||||
dyn FnOnce(Untyped) -> Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>,
|
||||
>,
|
||||
);
|
||||
}
|
||||
static RECEVIER_ID_SEQ: AtomicU64 = AtomicU64::new(1);
|
||||
|
||||
pub trait ReceiverSubscriberBuilder<M, T: 'static> {
|
||||
type Entry: ReceiverSubscriber<T>;
|
||||
pub trait ReceiverSubscriberBuilder<T, M, R, E>:
|
||||
SendUntypedReceiver + SendTypedReceiver<M> + ReciveTypedReceiver<R, E>
|
||||
where
|
||||
T: 'static,
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
type Config: Default;
|
||||
|
||||
fn build(cfg: Self::Config) -> Self::Entry;
|
||||
fn build(cfg: Self::Config) -> (Self, UntypedPollerCallback)
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
pub struct SyncEntry;
|
||||
pub struct UnsyncEntry;
|
||||
|
||||
#[must_use]
|
||||
pub struct RegisterEntry<K, T> {
|
||||
pub struct RegisterEntry<K, T, F, P, B> {
|
||||
item: Untyped,
|
||||
builder: BusBuilder,
|
||||
receivers: HashMap<
|
||||
TypeId,
|
||||
Vec<(
|
||||
Receiver,
|
||||
Box<
|
||||
dyn FnOnce(
|
||||
Untyped,
|
||||
)
|
||||
-> Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>,
|
||||
>,
|
||||
)>,
|
||||
>,
|
||||
payload: B,
|
||||
builder: F,
|
||||
poller: P,
|
||||
receivers: HashSet<Receiver>,
|
||||
pollers: Vec<BusPollerCallback>,
|
||||
_m: PhantomData<(K, T)>,
|
||||
}
|
||||
|
||||
impl<K, T: 'static> RegisterEntry<K, T> {
|
||||
pub fn done(self) -> BusBuilder {
|
||||
let mut builder = self.builder;
|
||||
|
||||
for (tid, v) in self.receivers {
|
||||
for (r, poller) in v {
|
||||
let poller = poller(self.item.clone());
|
||||
|
||||
builder.add_recevier((tid, r), poller);
|
||||
}
|
||||
impl<K, T: 'static, F, P, B> RegisterEntry<K, T, F, P, B>
|
||||
where
|
||||
F: FnMut(&mut B, Receiver),
|
||||
P: FnMut(&mut B, BusPollerCallback),
|
||||
{
|
||||
pub fn done(mut self) -> B {
|
||||
for r in self.receivers {
|
||||
(self.builder)(&mut self.payload, r);
|
||||
}
|
||||
|
||||
builder
|
||||
for p in self.pollers {
|
||||
(self.poller)(&mut self.payload, p);
|
||||
}
|
||||
|
||||
self.payload
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + 'static> RegisterEntry<UnsyncEntry, T> {
|
||||
pub fn subscribe<M, R>(mut self, cfg: R::Config) -> Self
|
||||
impl<T, F, P, B> RegisterEntry<UnsyncEntry, T, F, P, B> {
|
||||
pub fn subscribe<M, S, R, E>(mut self, queue: u64, cfg: S::Config) -> Self
|
||||
where
|
||||
T: Send + 'static,
|
||||
M: Message + 'static,
|
||||
R: ReceiverSubscriberBuilder<M, T> + 'static,
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
S: ReceiverSubscriberBuilder<T, M, R, E> + 'static,
|
||||
{
|
||||
let (inner, poller) = R::build(cfg).subscribe();
|
||||
let (inner, poller) = S::build(cfg);
|
||||
|
||||
let receiver = Receiver::new(inner);
|
||||
self.receivers
|
||||
.entry(TypeId::of::<M>())
|
||||
.or_insert_with(Vec::new)
|
||||
.push((receiver, poller));
|
||||
let receiver = Receiver::new::<M, R, E, S>(
|
||||
RECEVIER_ID_SEQ.fetch_add(1, Ordering::Relaxed),
|
||||
queue,
|
||||
true,
|
||||
inner,
|
||||
);
|
||||
|
||||
let poller2 = receiver.start_polling();
|
||||
self.receivers.insert(receiver);
|
||||
self.pollers.push(poller(self.item.clone()));
|
||||
self.pollers.push(poller2);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn subscribe_sync<M>(self, queue: u64, cfg: receivers::SynchronizedConfig) -> Self
|
||||
where
|
||||
T: SynchronizedHandler<M> + Send + 'static,
|
||||
M: Message,
|
||||
T::Response: Message,
|
||||
{
|
||||
self.subscribe::<M, receivers::SynchronizedSync<M, T::Response, T::Error>, T::Response, T::Error>(queue, cfg)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn subscribe_async<M>(self, queue: u64, cfg: receivers::SynchronizedConfig) -> Self
|
||||
where
|
||||
T: AsyncSynchronizedHandler<M> + Send + 'static,
|
||||
M: Message,
|
||||
T::Response: Message,
|
||||
{
|
||||
self.subscribe::<M, receivers::SynchronizedAsync<M, T::Response, T::Error>, T::Response, T::Error>(queue, cfg)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn subscribe_batch_sync<M>(
|
||||
self,
|
||||
queue: u64,
|
||||
cfg: receivers::SynchronizedBatchedConfig,
|
||||
) -> Self
|
||||
where
|
||||
T: BatchSynchronizedHandler<M> + Send + 'static,
|
||||
M: Message,
|
||||
T::Response: Message,
|
||||
{
|
||||
self.subscribe::<M, receivers::SynchronizedBatchedSync<M, T::Response, T::Error>, T::Response, T::Error>(queue, cfg)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn subscribe_batch_async<M>(
|
||||
self,
|
||||
queue: u64,
|
||||
cfg: receivers::SynchronizedBatchedConfig,
|
||||
) -> Self
|
||||
where
|
||||
T: AsyncBatchSynchronizedHandler<M> + Send + 'static,
|
||||
M: Message,
|
||||
T::Response: Message,
|
||||
{
|
||||
self.subscribe::<M, receivers::SynchronizedBatchedAsync<M, T::Response, T::Error>, T::Response, T::Error>(queue, cfg)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> RegisterEntry<SyncEntry, T> {
|
||||
pub fn subscribe<M, R>(mut self, cfg: R::Config) -> Self
|
||||
impl<T, F, P, B> RegisterEntry<SyncEntry, T, F, P, B> {
|
||||
pub fn subscribe<M, S, R, E>(mut self, queue: u64, cfg: S::Config) -> Self
|
||||
where
|
||||
T: Send + 'static,
|
||||
M: Message + 'static,
|
||||
R: ReceiverSubscriberBuilder<M, T> + 'static,
|
||||
T: Send + Sync + 'static,
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
S: ReceiverSubscriberBuilder<T, M, R, E> + 'static,
|
||||
{
|
||||
let (inner, poller) = R::build(cfg).subscribe();
|
||||
let (inner, poller) = S::build(cfg);
|
||||
|
||||
let receiver = Receiver::new(inner);
|
||||
self.receivers
|
||||
.entry(TypeId::of::<M>())
|
||||
.or_insert_with(Vec::new)
|
||||
.push((receiver, poller));
|
||||
let receiver = Receiver::new::<M, R, E, S>(
|
||||
RECEVIER_ID_SEQ.fetch_add(1, Ordering::Relaxed),
|
||||
queue,
|
||||
true,
|
||||
inner,
|
||||
);
|
||||
let poller2 = receiver.start_polling();
|
||||
self.receivers.insert(receiver);
|
||||
self.pollers.push(poller(self.item.clone()));
|
||||
self.pollers.push(poller2);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn subscribe_sync<M>(self, queue: u64, cfg: receivers::BufferUnorderedConfig) -> Self
|
||||
where
|
||||
T: Handler<M> + Send + Sync + 'static,
|
||||
M: Message,
|
||||
T::Response: Message,
|
||||
{
|
||||
self.subscribe::<M, receivers::BufferUnorderedSync<M, T::Response, T::Error>, T::Response, T::Error>(queue, cfg)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn subscribe_async<M>(self, queue: u64, cfg: receivers::BufferUnorderedConfig) -> Self
|
||||
where
|
||||
T: AsyncHandler<M> + Send + Sync + 'static,
|
||||
M: Message,
|
||||
T::Response: Message,
|
||||
T::Error: StdSyncSendError,
|
||||
{
|
||||
self.subscribe::<M, receivers::BufferUnorderedAsync<M, T::Response, T::Error>, T::Response, T::Error>(queue, cfg)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn subscribe_batch_sync<M>(
|
||||
self,
|
||||
queue: u64,
|
||||
cfg: receivers::BufferUnorderedBatchedConfig,
|
||||
) -> Self
|
||||
where
|
||||
T: BatchHandler<M> + Send + 'static,
|
||||
M: Message,
|
||||
T::Response: Message,
|
||||
{
|
||||
self.subscribe::<M, receivers::BufferUnorderedBatchedSync<M, T::Response, T::Error>, T::Response, T::Error>(queue, cfg)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn subscribe_batch_async<M>(
|
||||
self,
|
||||
queue: u64,
|
||||
cfg: receivers::BufferUnorderedBatchedConfig,
|
||||
) -> Self
|
||||
where
|
||||
T: AsyncBatchHandler<M> + Send + 'static,
|
||||
M: Message,
|
||||
T::Response: Message,
|
||||
{
|
||||
self.subscribe::<M, receivers::BufferUnorderedBatchedAsync<M, T::Response, T::Error>, T::Response, T::Error>(queue, cfg)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Module {
|
||||
receivers: HashSet<Receiver>,
|
||||
pollings: Vec<BusPollerCallback>,
|
||||
}
|
||||
|
||||
impl Module {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
receivers: HashSet::new(),
|
||||
pollings: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_relay<S: Relay + Send + Sync + 'static>(mut self, inner: S) -> Self {
|
||||
let receiver =
|
||||
Receiver::new_relay::<S>(RECEVIER_ID_SEQ.fetch_add(1, Ordering::Relaxed), inner);
|
||||
self.pollings.push(receiver.start_polling());
|
||||
self.receivers.insert(receiver);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn register<T: Send + Sync + 'static>(
|
||||
self,
|
||||
item: T,
|
||||
) -> RegisterEntry<
|
||||
SyncEntry,
|
||||
T,
|
||||
impl FnMut(&mut Self, Receiver),
|
||||
impl FnMut(&mut Self, Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>),
|
||||
Self,
|
||||
> {
|
||||
RegisterEntry {
|
||||
item: Arc::new(item) as Untyped,
|
||||
payload: self,
|
||||
builder: |p: &mut Self, r| {
|
||||
p.receivers.insert(r);
|
||||
},
|
||||
poller: |p: &mut Self, poller| p.pollings.push(poller),
|
||||
receivers: HashSet::new(),
|
||||
pollers: Vec::new(),
|
||||
_m: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_unsync<T: Send + 'static>(
|
||||
self,
|
||||
item: T,
|
||||
) -> RegisterEntry<
|
||||
UnsyncEntry,
|
||||
T,
|
||||
impl FnMut(&mut Self, Receiver),
|
||||
impl FnMut(&mut Self, Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>),
|
||||
Self,
|
||||
> {
|
||||
let item = Arc::new(Mutex::new(item)) as Untyped;
|
||||
|
||||
RegisterEntry {
|
||||
item,
|
||||
payload: self,
|
||||
builder: |p: &mut Self, r| {
|
||||
p.receivers.insert(r);
|
||||
},
|
||||
poller: |p: &mut Self, poller| p.pollings.push(poller),
|
||||
receivers: HashSet::new(),
|
||||
pollers: Vec::new(),
|
||||
_m: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_module(mut self, module: Module) -> Self {
|
||||
self.pollings.extend(module.pollings);
|
||||
self.receivers.extend(module.receivers);
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BusBuilder {
|
||||
receivers: Vec<(TypeId, Receiver)>,
|
||||
pollings: Vec<Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>>,
|
||||
inner: Module,
|
||||
}
|
||||
|
||||
impl BusBuilder {
|
||||
pub fn new() -> Self {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
receivers: Vec::new(),
|
||||
pollings: Vec::new(),
|
||||
inner: Module::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register<T: Send + Sync + 'static>(self, item: T) -> RegisterEntry<SyncEntry, T> {
|
||||
pub fn register_relay<S: Relay + Send + Sync + 'static>(self, inner: S) -> Self {
|
||||
let inner = self.inner.register_relay(inner);
|
||||
|
||||
BusBuilder { inner }
|
||||
}
|
||||
|
||||
pub fn register<T: Send + Sync + 'static>(
|
||||
self,
|
||||
item: T,
|
||||
) -> RegisterEntry<
|
||||
SyncEntry,
|
||||
T,
|
||||
impl FnMut(&mut Self, Receiver),
|
||||
impl FnMut(&mut Self, Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>),
|
||||
Self,
|
||||
> {
|
||||
RegisterEntry {
|
||||
item: Arc::new(item) as Untyped,
|
||||
builder: self,
|
||||
receivers: HashMap::new(),
|
||||
payload: self,
|
||||
builder: |p: &mut Self, r| {
|
||||
p.inner.receivers.insert(r);
|
||||
},
|
||||
poller: |p: &mut Self, poller| p.inner.pollings.push(poller),
|
||||
receivers: HashSet::new(),
|
||||
pollers: Vec::new(),
|
||||
_m: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_unsync<T: Send + 'static>(self, item: T) -> RegisterEntry<UnsyncEntry, T> {
|
||||
pub fn register_unsync<T: Send + 'static>(
|
||||
self,
|
||||
item: T,
|
||||
) -> RegisterEntry<
|
||||
UnsyncEntry,
|
||||
T,
|
||||
impl FnMut(&mut Self, Receiver),
|
||||
impl FnMut(&mut Self, Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>),
|
||||
Self,
|
||||
> {
|
||||
RegisterEntry {
|
||||
item: Arc::new(Mutex::new(item)) as Untyped,
|
||||
builder: self,
|
||||
receivers: HashMap::new(),
|
||||
payload: self,
|
||||
builder: |p: &mut Self, r| {
|
||||
p.inner.receivers.insert(r);
|
||||
},
|
||||
poller: |p: &mut Self, poller| p.inner.pollings.push(poller),
|
||||
receivers: HashSet::new(),
|
||||
pollers: Vec::new(),
|
||||
_m: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_recevier(
|
||||
&mut self,
|
||||
val: (TypeId, Receiver),
|
||||
poller: Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>,
|
||||
) {
|
||||
self.receivers.push(val);
|
||||
self.pollings.push(poller);
|
||||
pub fn add_module(mut self, module: Module) -> Self {
|
||||
self.inner = self.inner.add_module(module);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> (Bus, impl Future<Output = ()>) {
|
||||
let bus = Bus {
|
||||
inner: Arc::new(BusInner::new(self.receivers)),
|
||||
inner: Arc::new(BusInner::new(self.inner.receivers)),
|
||||
};
|
||||
|
||||
let mut futs = Vec::with_capacity(self.pollings.len());
|
||||
for poller in self.pollings {
|
||||
let mut futs = Vec::with_capacity(self.inner.pollings.len() * 2);
|
||||
for poller in self.inner.pollings {
|
||||
futs.push(tokio::task::spawn(poller(bus.clone())));
|
||||
}
|
||||
|
||||
let poller = futures::future::join_all(futs).map(|_| ()).map(|_| ());
|
||||
|
||||
bus.init();
|
||||
|
||||
(bus, poller)
|
||||
}
|
||||
}
|
||||
|
524
src/envelop.rs
524
src/envelop.rs
@ -1,102 +1,462 @@
|
||||
use core::any::{self, Any};
|
||||
use core::fmt;
|
||||
// use erased_serde::{Deserializer, Serialize};
|
||||
use core::{
|
||||
any::{type_name, Any},
|
||||
fmt,
|
||||
};
|
||||
|
||||
pub trait Message: Any + fmt::Debug/*Serialize + for<'a> Deserializer<'a> + */ + Unpin + Clone + Send + Sync + 'static {}
|
||||
impl<T: Any + fmt::Debug + Unpin + Clone + Send + Sync> Message for T {}
|
||||
use std::{alloc::Layout, borrow::Cow, sync::Arc};
|
||||
|
||||
trait SafeMessage: Any + fmt::Debug/*+ Serialize + for<'a> Deserializer<'a>*/ + Unpin + Send + Sync + 'static {
|
||||
fn type_name(&self) -> &'static str;
|
||||
fn clone_boxed(&self) -> Box<dyn SafeMessage>;
|
||||
pub trait MessageBounds: TypeTagged + fmt::Debug + Unpin + Send + Sync + 'static {}
|
||||
impl<T: TypeTagged + fmt::Debug + Unpin + Send + Sync + 'static> MessageBounds for T {}
|
||||
|
||||
pub type TypeTag = Cow<'static, str>;
|
||||
|
||||
pub trait TypeTagged {
|
||||
fn type_tag_() -> TypeTag
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
fn type_tag(&self) -> TypeTag;
|
||||
fn type_name(&self) -> Cow<str>;
|
||||
fn type_layout(&self) -> Layout;
|
||||
}
|
||||
|
||||
impl<T: Message> SafeMessage for T {
|
||||
fn type_name(&self) -> &'static str {
|
||||
any::type_name::<T>()
|
||||
pub trait Message: MessageBounds {
|
||||
fn as_any_ref(&self) -> &dyn Any;
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||
fn as_any_boxed(self: Box<Self>) -> Box<dyn Any>;
|
||||
fn as_any_arc(self: Arc<Self>) -> Arc<dyn Any>;
|
||||
|
||||
fn as_shared_ref(&self) -> Option<&dyn SharedMessage>;
|
||||
fn as_shared_mut(&mut self) -> Option<&mut dyn SharedMessage>;
|
||||
fn as_shared_boxed(self: Box<Self>) -> Result<Box<dyn SharedMessage>, Box<dyn Message>>;
|
||||
fn as_shared_arc(self: Arc<Self>) -> Option<Arc<dyn SharedMessage>>;
|
||||
|
||||
fn try_clone_into(&self, into: &mut dyn Any) -> bool;
|
||||
fn try_clone_boxed(&self) -> Option<Box<dyn Message>>;
|
||||
|
||||
fn try_clone(&self) -> Option<Self>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
macro_rules! gen_impls {
|
||||
($t:ty, $($rest:tt)*) => {
|
||||
impl TypeTagged for $t {
|
||||
fn type_tag_() -> TypeTag {
|
||||
type_name::<$t>().into()
|
||||
}
|
||||
fn type_tag(&self) -> TypeTag {
|
||||
type_name::<$t>().into()
|
||||
}
|
||||
fn type_name(&self) -> Cow<str> {
|
||||
type_name::<$t>().into()
|
||||
}
|
||||
fn type_layout(&self) -> Layout {
|
||||
Layout::for_value(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn clone_boxed(&self) -> Box<dyn SafeMessage> {
|
||||
Box::new(self.clone())
|
||||
gen_impls!{ $($rest)* }
|
||||
};
|
||||
|
||||
($t:ty) => {
|
||||
impl TypeTagged for $t {
|
||||
fn type_tag_() -> TypeTag {
|
||||
type_name::<$t>().into()
|
||||
}
|
||||
fn type_tag(&self) -> TypeTag {
|
||||
type_name::<$t>().into()
|
||||
}
|
||||
fn type_name(&self) -> Cow<str> {
|
||||
type_name::<$t>().into()
|
||||
}
|
||||
fn type_layout(&self) -> Layout {
|
||||
Layout::for_value(self)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
gen_impls! {
|
||||
(), bool,
|
||||
i8, u8,
|
||||
i16, u16,
|
||||
i32, u32,
|
||||
i64, u64,
|
||||
i128, u128,
|
||||
f32, f64,
|
||||
String
|
||||
}
|
||||
|
||||
impl<T: TypeTagged> TypeTagged for Arc<T> {
|
||||
fn type_tag_() -> TypeTag {
|
||||
T::type_tag_()
|
||||
}
|
||||
|
||||
fn type_tag(&self) -> TypeTag {
|
||||
T::type_tag(&*self)
|
||||
}
|
||||
fn type_name(&self) -> Cow<str> {
|
||||
T::type_name(&*self)
|
||||
}
|
||||
fn type_layout(&self) -> Layout {
|
||||
Layout::for_value(self)
|
||||
}
|
||||
}
|
||||
|
||||
// pub struct BoxedEnvelop {
|
||||
// inner: Box<dyn SafeMessage>,
|
||||
// }
|
||||
impl<T: TypeTagged> TypeTagged for Box<T> {
|
||||
fn type_tag_() -> TypeTag {
|
||||
T::type_tag_()
|
||||
}
|
||||
|
||||
// impl BoxedEnvelop {
|
||||
// pub fn from_message<M: Message>(m: M) -> Self {
|
||||
// Self {
|
||||
// inner: Box::new(m)
|
||||
// }
|
||||
// }
|
||||
|
||||
// pub fn as_ref(&self) -> Envelop<'_> {
|
||||
// Envelop { inner: &*self.inner }
|
||||
// }
|
||||
|
||||
// pub fn downcast<T: 'static>(self) -> Option<Box<T>> {
|
||||
// if (*self.inner).type_id() == TypeId::of::<T>() {
|
||||
// unsafe {
|
||||
// let raw: *mut dyn SafeMessage = Box::into_raw(self.inner);
|
||||
|
||||
// Some(Box::from_raw(raw as *mut T))
|
||||
// }
|
||||
// } else {
|
||||
// None
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Envelop<'inner> {
|
||||
inner: &'inner dyn SafeMessage,
|
||||
}
|
||||
|
||||
impl<'inner> fmt::Debug for Envelop<'inner> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Envelop(")?;
|
||||
self.inner.fmt(f)?;
|
||||
write!(f, ")")?;
|
||||
|
||||
Ok(())
|
||||
fn type_tag(&self) -> TypeTag {
|
||||
T::type_tag(&*self)
|
||||
}
|
||||
fn type_name(&self) -> Cow<str> {
|
||||
T::type_name(&*self)
|
||||
}
|
||||
fn type_layout(&self) -> Layout {
|
||||
Layout::for_value(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'inner> Envelop<'inner> {
|
||||
// pub fn new<T: Message>(inner: &'inner T) -> Self {
|
||||
// Self { inner }
|
||||
// }
|
||||
impl Message for () {
|
||||
fn as_any_ref(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
fn as_any_boxed(self: Box<Self>) -> Box<dyn Any> {
|
||||
self
|
||||
}
|
||||
fn as_any_arc(self: Arc<Self>) -> Arc<dyn Any> {
|
||||
self
|
||||
}
|
||||
|
||||
// #[inline]
|
||||
// pub fn downcast_to<T: 'static>(&self) -> Option<&T> {
|
||||
// if self.inner.type_id() == TypeId::of::<T>() {
|
||||
// unsafe { Some(&*(self.inner as *const dyn SafeMessage as *const T)) }
|
||||
// } else {
|
||||
// None
|
||||
// }
|
||||
// }
|
||||
fn as_shared_ref(&self) -> Option<&dyn SharedMessage> {
|
||||
Some(self)
|
||||
}
|
||||
fn as_shared_mut(&mut self) -> Option<&mut dyn SharedMessage> {
|
||||
Some(self)
|
||||
}
|
||||
fn as_shared_boxed(self: Box<Self>) -> Result<Box<dyn SharedMessage>, Box<dyn Message>> {
|
||||
Ok(self)
|
||||
}
|
||||
fn as_shared_arc(self: Arc<Self>) -> Option<Arc<dyn SharedMessage>> {
|
||||
Some(self)
|
||||
}
|
||||
fn try_clone_into(&self, into: &mut dyn Any) -> bool {
|
||||
let into = if let Some(inner) = into.downcast_mut::<Option<()>>() {
|
||||
inner
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
|
||||
// #[inline]
|
||||
// pub fn type_id(&self) -> TypeId {
|
||||
// self.inner.type_id()
|
||||
// }
|
||||
into.replace(());
|
||||
true
|
||||
}
|
||||
fn try_clone_boxed(&self) -> Option<Box<dyn Message>> {
|
||||
Some(Box::new(()))
|
||||
}
|
||||
|
||||
// #[inline]
|
||||
// pub fn type_name(&self) -> &'static str {
|
||||
// self.inner.type_name()
|
||||
// }
|
||||
|
||||
// #[inline]
|
||||
// pub fn clone_boxed(&self) -> BoxedEnvelop {
|
||||
// BoxedEnvelop {
|
||||
// inner: self.inner.clone_boxed(),
|
||||
// }
|
||||
// }
|
||||
fn try_clone(&self) -> Option<Self> {
|
||||
Some(())
|
||||
}
|
||||
}
|
||||
|
||||
// impl<'inner> serde::Serialize for Envelop<'inner> {
|
||||
// fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
// erased_serde::serialize(self.inner, serializer)
|
||||
pub trait IntoBoxedMessage {
|
||||
fn into_boxed(self) -> Box<dyn Message>;
|
||||
}
|
||||
|
||||
impl<T: Message> IntoBoxedMessage for T {
|
||||
fn into_boxed(self) -> Box<dyn Message> {
|
||||
Box::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait IntoSharedMessage {
|
||||
fn into_shared(self) -> Box<dyn SharedMessage>;
|
||||
}
|
||||
|
||||
impl<T: Message + serde::Serialize> IntoSharedMessage for T {
|
||||
fn into_shared(self) -> Box<dyn SharedMessage> {
|
||||
Box::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait SharedMessage: Message + erased_serde::Serialize {
|
||||
fn upcast_arc(self: Arc<Self>) -> Arc<dyn Message>;
|
||||
fn upcast_box(self: Box<Self>) -> Box<dyn Message>;
|
||||
fn upcast_ref(&self) -> &dyn Message;
|
||||
fn upcast_mut(&mut self) -> &mut dyn Message;
|
||||
}
|
||||
impl<T: Message + erased_serde::Serialize> SharedMessage for T {
|
||||
fn upcast_arc(self: Arc<Self>) -> Arc<dyn Message> {
|
||||
self
|
||||
}
|
||||
fn upcast_box(self: Box<Self>) -> Box<dyn Message> {
|
||||
self
|
||||
}
|
||||
fn upcast_ref(&self) -> &dyn Message {
|
||||
self
|
||||
}
|
||||
fn upcast_mut(&mut self) -> &mut dyn Message {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
// pub trait IntoTakeable {
|
||||
// fn into_takeable(&mut self) -> Takeable<'_>;
|
||||
// }
|
||||
|
||||
// impl<T: 'static> IntoTakeable for Option<T> {
|
||||
// fn into_takeable(&mut self) -> Takeable<'_> {
|
||||
// Takeable {
|
||||
// inner_ref: self
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// pub struct Takeable<'a> {
|
||||
// inner_ref: &'a mut dyn Any,
|
||||
// }
|
||||
|
||||
// impl Takeable<'_> {
|
||||
// pub fn take<M: Message>(&mut self) -> Option<M> {
|
||||
// let m = self.inner_ref.downcast_mut::<Option<M>>()?;
|
||||
// m.take()
|
||||
// }
|
||||
// }
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use erased_serde::Serializer;
|
||||
use std::{any::type_name, borrow::Cow};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Msg0;
|
||||
|
||||
impl TypeTagged for Msg0 {
|
||||
fn type_tag_() -> TypeTag {
|
||||
type_name::<Self>().into()
|
||||
}
|
||||
fn type_tag(&self) -> TypeTag {
|
||||
type_name::<Self>().into()
|
||||
}
|
||||
fn type_name(&self) -> Cow<str> {
|
||||
type_name::<Self>().into()
|
||||
}
|
||||
fn type_layout(&self) -> Layout {
|
||||
Layout::for_value(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Message for Msg0 {
|
||||
fn as_any_ref(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
fn as_any_boxed(self: Box<Self>) -> Box<dyn Any> {
|
||||
self
|
||||
}
|
||||
fn as_any_arc(self: Arc<Self>) -> Arc<dyn Any> {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_shared_ref(&self) -> Option<&dyn SharedMessage> {
|
||||
None
|
||||
}
|
||||
fn as_shared_mut(&mut self) -> Option<&mut dyn SharedMessage> {
|
||||
None
|
||||
}
|
||||
fn as_shared_boxed(self: Box<Self>) -> Result<Box<dyn SharedMessage>, Box<dyn Message>> {
|
||||
Err(self)
|
||||
}
|
||||
fn as_shared_arc(self: Arc<Self>) -> Option<Arc<dyn SharedMessage>> {
|
||||
None
|
||||
}
|
||||
fn try_clone_into(&self, _: &mut dyn Any) -> bool {
|
||||
false
|
||||
}
|
||||
fn try_clone_boxed(&self) -> Option<Box<dyn Message>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn try_clone(&self) -> Option<Self> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Msg1;
|
||||
|
||||
impl TypeTagged for Msg1 {
|
||||
fn type_tag_() -> TypeTag {
|
||||
type_name::<Self>().into()
|
||||
}
|
||||
fn type_tag(&self) -> TypeTag {
|
||||
type_name::<Self>().into()
|
||||
}
|
||||
fn type_name(&self) -> Cow<str> {
|
||||
type_name::<Self>().into()
|
||||
}
|
||||
fn type_layout(&self) -> Layout {
|
||||
Layout::for_value(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Message for Msg1 {
|
||||
fn as_any_ref(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
fn as_any_boxed(self: Box<Self>) -> Box<dyn Any> {
|
||||
self
|
||||
}
|
||||
fn as_any_arc(self: Arc<Self>) -> Arc<dyn Any> {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_shared_ref(&self) -> Option<&dyn SharedMessage> {
|
||||
None
|
||||
}
|
||||
fn as_shared_mut(&mut self) -> Option<&mut dyn SharedMessage> {
|
||||
None
|
||||
}
|
||||
fn as_shared_boxed(self: Box<Self>) -> Result<Box<dyn SharedMessage>, Box<dyn Message>> {
|
||||
Err(self)
|
||||
}
|
||||
fn as_shared_arc(self: Arc<Self>) -> Option<Arc<dyn SharedMessage>> {
|
||||
None
|
||||
}
|
||||
fn try_clone_into(&self, into: &mut dyn Any) -> bool {
|
||||
let into = if let Some(inner) = into.downcast_mut::<Option<Msg1>>() {
|
||||
inner
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
|
||||
into.replace(self.clone());
|
||||
true
|
||||
}
|
||||
fn try_clone_boxed(&self) -> Option<Box<dyn Message>> {
|
||||
Some(Box::new(self.clone()))
|
||||
}
|
||||
|
||||
fn try_clone(&self) -> Option<Self> {
|
||||
Some(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde_derive::Serialize, serde_derive::Deserialize)]
|
||||
struct Msg2 {
|
||||
inner: [i32; 2],
|
||||
}
|
||||
|
||||
impl TypeTagged for Msg2 {
|
||||
fn type_tag_() -> TypeTag {
|
||||
type_name::<Self>().into()
|
||||
}
|
||||
fn type_tag(&self) -> TypeTag {
|
||||
type_name::<Self>().into()
|
||||
}
|
||||
fn type_name(&self) -> Cow<str> {
|
||||
type_name::<Self>().into()
|
||||
}
|
||||
fn type_layout(&self) -> Layout {
|
||||
Layout::for_value(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Message for Msg2 {
|
||||
fn as_any_ref(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
fn as_any_boxed(self: Box<Self>) -> Box<dyn Any> {
|
||||
self
|
||||
}
|
||||
fn as_any_arc(self: Arc<Self>) -> Arc<dyn Any> {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_shared_ref(&self) -> Option<&dyn SharedMessage> {
|
||||
Some(self)
|
||||
}
|
||||
fn as_shared_mut(&mut self) -> Option<&mut dyn SharedMessage> {
|
||||
Some(self)
|
||||
}
|
||||
fn as_shared_boxed(self: Box<Self>) -> Result<Box<dyn SharedMessage>, Box<dyn Message>> {
|
||||
Ok(self)
|
||||
}
|
||||
fn as_shared_arc(self: Arc<Self>) -> Option<Arc<dyn SharedMessage>> {
|
||||
Some(self)
|
||||
}
|
||||
fn try_clone_into(&self, into: &mut dyn Any) -> bool {
|
||||
let into = if let Some(inner) = into.downcast_mut::<Option<Msg2>>() {
|
||||
inner
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
|
||||
into.replace(self.clone());
|
||||
true
|
||||
}
|
||||
fn try_clone_boxed(&self) -> Option<Box<dyn Message>> {
|
||||
Some(Box::new(self.clone()))
|
||||
}
|
||||
|
||||
fn try_clone(&self) -> Option<Self> {
|
||||
Some(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_static_upcast() {
|
||||
let mut buff: Vec<u8> = Vec::new();
|
||||
let json = &mut serde_json::Serializer::new(&mut buff);
|
||||
let mut json = <dyn Serializer>::erase(json);
|
||||
|
||||
let x = Msg1;
|
||||
let y = Msg2 { inner: [12, 13] };
|
||||
|
||||
assert!(x.as_shared_ref().is_none());
|
||||
assert!(y.as_shared_ref().is_some());
|
||||
assert!(y
|
||||
.as_shared_ref()
|
||||
.unwrap()
|
||||
.erased_serialize(&mut json)
|
||||
.is_ok());
|
||||
assert_eq!(buff.as_slice(), b"{\"inner\":[12,13]}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dyn_upcast() {
|
||||
let mut buff: Vec<u8> = Vec::new();
|
||||
let json = &mut serde_json::Serializer::new(&mut buff);
|
||||
let mut json = <dyn Serializer>::erase(json);
|
||||
|
||||
let x = Msg1;
|
||||
let y = Msg2 { inner: [12, 13] };
|
||||
|
||||
let x_dyn: &dyn Message = &x;
|
||||
let y_dyn: &dyn Message = &y;
|
||||
|
||||
assert!(x_dyn.as_shared_ref().is_none());
|
||||
assert!(y_dyn.as_shared_ref().is_some());
|
||||
assert!(y_dyn
|
||||
.as_shared_ref()
|
||||
.unwrap()
|
||||
.erased_serialize(&mut json)
|
||||
.is_ok());
|
||||
assert_eq!(buff.as_slice(), b"{\"inner\":[12,13]}");
|
||||
}
|
||||
}
|
||||
|
284
src/error.rs
Normal file
284
src/error.rs
Normal file
@ -0,0 +1,284 @@
|
||||
use core::fmt;
|
||||
use std::any::type_name;
|
||||
|
||||
use thiserror::Error;
|
||||
use tokio::sync::oneshot;
|
||||
|
||||
use crate::{
|
||||
envelop::{IntoBoxedMessage, TypeTag, TypeTagged},
|
||||
Message,
|
||||
};
|
||||
|
||||
pub trait DynError: TypeTagged {
|
||||
fn description(&self) -> String;
|
||||
}
|
||||
|
||||
pub trait StdSyncSendError: std::error::Error + TypeTagged + Send + Sync + Unpin + 'static {}
|
||||
impl<T: std::error::Error + TypeTagged + Send + Sync + Unpin + 'static> StdSyncSendError for T {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GenericError {
|
||||
pub type_tag: TypeTag,
|
||||
pub description: String,
|
||||
}
|
||||
|
||||
impl GenericError {
|
||||
pub fn from_any<T: TypeTagged + fmt::Display>(err: T) -> Self {
|
||||
GenericError {
|
||||
type_tag: err.type_tag(),
|
||||
description: format!("{}[{}]", err.type_tag(), err),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_err(tt: TypeTag, err: impl fmt::Display) -> Self {
|
||||
GenericError {
|
||||
description: format!("{}[{}]", tt, err),
|
||||
type_tag: tt,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for GenericError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "GenericError({}): {}", self.type_tag, self.description)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for GenericError {}
|
||||
|
||||
impl TypeTagged for GenericError {
|
||||
fn type_tag_() -> TypeTag {
|
||||
type_name::<GenericError>().into()
|
||||
}
|
||||
|
||||
fn type_tag(&self) -> TypeTag {
|
||||
type_name::<GenericError>().into()
|
||||
}
|
||||
|
||||
fn type_name(&self) -> TypeTag {
|
||||
type_name::<GenericError>().into()
|
||||
}
|
||||
fn type_layout(&self) -> std::alloc::Layout {
|
||||
std::alloc::Layout::for_value(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum SendError<M: fmt::Debug> {
|
||||
#[error("Closed")]
|
||||
Closed(M),
|
||||
|
||||
#[error("Full")]
|
||||
Full(M),
|
||||
}
|
||||
|
||||
impl<M: fmt::Debug> SendError<M> {
|
||||
pub fn map_msg<UM: fmt::Debug + 'static, F: FnOnce(M) -> UM>(self, f: F) -> SendError<UM> {
|
||||
match self {
|
||||
SendError::Closed(inner) => SendError::Closed(f(inner)),
|
||||
SendError::Full(inner) => SendError::Full(f(inner)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Message> SendError<M> {
|
||||
pub fn into_boxed(self) -> SendError<Box<dyn Message>> {
|
||||
match self {
|
||||
SendError::Closed(m) => SendError::Closed(m.into_boxed()),
|
||||
SendError::Full(m) => SendError::Closed(m.into_boxed()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error<M: fmt::Debug + 'static = (), E: StdSyncSendError = GenericError> {
|
||||
#[error("Message Send Error: {0}")]
|
||||
SendError(#[from] SendError<M>),
|
||||
|
||||
#[error("Message receiver dropped try again another receiver")]
|
||||
TryAgain(M),
|
||||
|
||||
#[error("NoResponse")]
|
||||
NoResponse,
|
||||
|
||||
#[error("NoReceivers")]
|
||||
NoReceivers,
|
||||
|
||||
#[error("AddListenerError")]
|
||||
AddListenerError,
|
||||
|
||||
#[error("MessageCastError")]
|
||||
MessageCastError,
|
||||
|
||||
#[error("Not Ready")]
|
||||
NotReady,
|
||||
|
||||
#[error("Other({0})")]
|
||||
Other(E),
|
||||
|
||||
#[error("Serialization({0})")]
|
||||
Serialization(#[from] erased_serde::Error),
|
||||
|
||||
#[error("Other({0})")]
|
||||
OtherBoxed(Box<dyn StdSyncSendError>),
|
||||
|
||||
#[error("WrongMessageType()")]
|
||||
WrongMessageType(M),
|
||||
|
||||
#[error("TypeTagNotRegistered({0})")]
|
||||
TypeTagNotRegistered(TypeTag),
|
||||
|
||||
#[error("Unknown Error: {0}")]
|
||||
Unknown(String),
|
||||
}
|
||||
|
||||
impl<M: fmt::Debug + 'static, E: StdSyncSendError> Error<M, E> {
|
||||
pub fn send_closed(m: M) -> Self {
|
||||
Error::SendError(SendError::Closed(m))
|
||||
}
|
||||
|
||||
pub fn send_full(m: M) -> Self {
|
||||
Error::SendError(SendError::Full(m))
|
||||
}
|
||||
|
||||
pub fn map_msg<UM: fmt::Debug + 'static, F: FnOnce(M) -> UM>(self, f: F) -> Error<UM, E> {
|
||||
match self {
|
||||
Error::SendError(inner) => Error::SendError(inner.map_msg(f)),
|
||||
Error::TryAgain(inner) => Error::TryAgain(f(inner)),
|
||||
Error::NoResponse => Error::NoResponse,
|
||||
Error::NoReceivers => Error::NoReceivers,
|
||||
Error::Serialization(s) => Error::Serialization(s),
|
||||
Error::Other(inner) => Error::Other(inner),
|
||||
Error::OtherBoxed(inner) => Error::OtherBoxed(inner),
|
||||
Error::WrongMessageType(inner) => Error::WrongMessageType(f(inner)),
|
||||
Error::AddListenerError => Error::AddListenerError,
|
||||
Error::MessageCastError => Error::MessageCastError,
|
||||
Error::TypeTagNotRegistered(tt) => Error::TypeTagNotRegistered(tt),
|
||||
Error::NotReady => Error::NotReady,
|
||||
Error::Unknown(msg) => Error::Unknown(msg),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_err<UE: StdSyncSendError, F: FnOnce(E) -> UE>(self, f: F) -> Error<M, UE> {
|
||||
match self {
|
||||
Error::SendError(inner) => Error::SendError(inner),
|
||||
Error::TryAgain(inner) => Error::TryAgain(inner),
|
||||
Error::NoResponse => Error::NoResponse,
|
||||
Error::NoReceivers => Error::NoReceivers,
|
||||
Error::Serialization(s) => Error::Serialization(s),
|
||||
Error::Other(inner) => Error::Other(f(inner)),
|
||||
Error::OtherBoxed(inner) => Error::OtherBoxed(inner),
|
||||
Error::WrongMessageType(inner) => Error::WrongMessageType(inner),
|
||||
Error::AddListenerError => Error::AddListenerError,
|
||||
Error::MessageCastError => Error::MessageCastError,
|
||||
Error::TypeTagNotRegistered(tt) => Error::TypeTagNotRegistered(tt),
|
||||
Error::NotReady => Error::NotReady,
|
||||
Error::Unknown(msg) => Error::Unknown(msg),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_unwrap(self) -> Result<E, Self> {
|
||||
match self {
|
||||
Error::Other(inner) => Ok(inner),
|
||||
s => Err(s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Message, E: StdSyncSendError> Error<M, E> {
|
||||
pub fn into_dyn(self) -> Error<M> {
|
||||
match self {
|
||||
Error::SendError(inner) => Error::SendError(inner),
|
||||
Error::TryAgain(inner) => Error::TryAgain(inner),
|
||||
Error::NoResponse => Error::NoResponse,
|
||||
Error::NoReceivers => Error::NoReceivers,
|
||||
Error::Serialization(s) => Error::Serialization(s),
|
||||
Error::Other(inner) => Error::OtherBoxed(Box::new(inner) as _),
|
||||
Error::OtherBoxed(inner) => Error::OtherBoxed(inner),
|
||||
Error::WrongMessageType(inner) => Error::WrongMessageType(inner),
|
||||
Error::AddListenerError => Error::AddListenerError,
|
||||
Error::MessageCastError => Error::MessageCastError,
|
||||
Error::TypeTagNotRegistered(tt) => Error::TypeTagNotRegistered(tt),
|
||||
Error::NotReady => Error::NotReady,
|
||||
Error::Unknown(msg) => Error::Unknown(msg),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map<U: From<Box<dyn StdSyncSendError>> + StdSyncSendError>(self) -> Error<M, U> {
|
||||
match self {
|
||||
Error::SendError(inner) => Error::SendError(inner),
|
||||
Error::TryAgain(inner) => Error::TryAgain(inner),
|
||||
Error::NoResponse => Error::NoResponse,
|
||||
Error::NoReceivers => Error::NoReceivers,
|
||||
Error::Serialization(s) => Error::Serialization(s),
|
||||
Error::Other(_) => panic!("expected boxed error!"),
|
||||
Error::OtherBoxed(inner) => Error::Other(inner.into()),
|
||||
Error::WrongMessageType(inner) => Error::WrongMessageType(inner),
|
||||
Error::AddListenerError => Error::AddListenerError,
|
||||
Error::MessageCastError => Error::MessageCastError,
|
||||
Error::TypeTagNotRegistered(tt) => Error::TypeTagNotRegistered(tt),
|
||||
Error::NotReady => Error::NotReady,
|
||||
Error::Unknown(msg) => Error::Unknown(msg),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: StdSyncSendError> Error<(), E> {
|
||||
pub fn specify<M: fmt::Debug>(self) -> Error<M, E> {
|
||||
match self {
|
||||
Error::SendError(_) => panic!("cannot specify type on typed error"),
|
||||
Error::TryAgain(_) => panic!("cannot specify type on typed error"),
|
||||
Error::WrongMessageType(_) => panic!("cannot specify type on typed error"),
|
||||
Error::NoResponse => Error::NoResponse,
|
||||
Error::NoReceivers => Error::NoReceivers,
|
||||
Error::Serialization(s) => Error::Serialization(s),
|
||||
Error::Other(inner) => Error::Other(inner),
|
||||
Error::OtherBoxed(inner) => Error::OtherBoxed(inner),
|
||||
Error::AddListenerError => Error::AddListenerError,
|
||||
Error::MessageCastError => Error::MessageCastError,
|
||||
Error::TypeTagNotRegistered(tt) => Error::TypeTagNotRegistered(tt),
|
||||
Error::NotReady => Error::NotReady,
|
||||
Error::Unknown(msg) => Error::Unknown(msg),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: fmt::Debug, E: StdSyncSendError> From<oneshot::error::RecvError> for Error<M, E> {
|
||||
fn from(_: oneshot::error::RecvError) -> Self {
|
||||
Error::NoResponse
|
||||
}
|
||||
}
|
||||
|
||||
impl Error<Box<dyn Message>> {
|
||||
pub fn from_typed<M: Message>(err: Error<M>) -> Self {
|
||||
match err {
|
||||
Error::SendError(SendError::Closed(m)) => {
|
||||
Error::SendError(SendError::Closed(m.into_boxed()))
|
||||
}
|
||||
Error::SendError(SendError::Full(m)) => {
|
||||
Error::SendError(SendError::Full(m.into_boxed()))
|
||||
}
|
||||
Error::TryAgain(inner) => Error::TryAgain(inner.into_boxed()),
|
||||
Error::WrongMessageType(m) => Error::WrongMessageType(m.into_boxed()),
|
||||
Error::NoResponse => Error::NoResponse,
|
||||
Error::NoReceivers => Error::NoReceivers,
|
||||
Error::Serialization(s) => Error::Serialization(s),
|
||||
Error::Other(inner) => Error::Other(inner),
|
||||
Error::OtherBoxed(inner) => Error::OtherBoxed(inner),
|
||||
Error::AddListenerError => Error::AddListenerError,
|
||||
Error::MessageCastError => Error::MessageCastError,
|
||||
Error::TypeTagNotRegistered(tt) => Error::TypeTagNotRegistered(tt),
|
||||
Error::NotReady => Error::NotReady,
|
||||
Error::Unknown(msg) => Error::Unknown(msg),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// impl<M: fmt::Debug> Error<M> {
|
||||
// pub fn downcast<E>(self) -> Result<E, Self> {
|
||||
// match self {
|
||||
// Error::OtherBoxed(inner) => Ok(),
|
||||
// err => Err(err)
|
||||
// }
|
||||
// }
|
||||
// }
|
131
src/handler.rs
131
src/handler.rs
@ -1,92 +1,173 @@
|
||||
use crate::{Bus, Message};
|
||||
use core::iter::FromIterator;
|
||||
use std::pin::Pin;
|
||||
|
||||
use crate::{error::StdSyncSendError, Bus, Message};
|
||||
use async_trait::async_trait;
|
||||
use futures::Stream;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct ProducerStats {
|
||||
pub completed: usize,
|
||||
pub failed: usize,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait AsyncProducer<M: Message>: Send + Sync {
|
||||
type Item: Message;
|
||||
type Response: Message;
|
||||
type Error: StdSyncSendError;
|
||||
|
||||
async fn producer(
|
||||
&self,
|
||||
msg: M,
|
||||
bus: &Bus,
|
||||
) -> Result<Pin<Box<dyn Stream<Item = Result<Self::Item, Self::Error>> + Send + '_>>, Self::Error>;
|
||||
|
||||
async fn finish(&self, stats: ProducerStats, bus: &Bus) -> Result<Self::Response, Self::Error>;
|
||||
}
|
||||
|
||||
pub trait Handler<M: Message>: Send + Sync {
|
||||
fn handle(&self, msg: M, bus: &Bus) -> anyhow::Result<()>;
|
||||
fn sync(&self, _bus: &Bus) -> anyhow::Result<()> {
|
||||
type Error: StdSyncSendError;
|
||||
type Response: Message;
|
||||
|
||||
fn handle(&self, msg: M, bus: &Bus) -> Result<Self::Response, Self::Error>;
|
||||
fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait AsyncHandler<M: Message>: Send + Sync {
|
||||
async fn handle(&self, msg: M, bus: &Bus) -> anyhow::Result<()>;
|
||||
async fn sync(&self, _bus: &Bus) -> anyhow::Result<()> {
|
||||
type Error: StdSyncSendError;
|
||||
type Response: Message;
|
||||
|
||||
async fn handle(&self, msg: M, bus: &Bus) -> Result<Self::Response, Self::Error>;
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait SynchronizedHandler<M: Message>: Send {
|
||||
fn handle(&mut self, msg: M, bus: &Bus) -> anyhow::Result<()>;
|
||||
fn sync(&mut self, _bus: &Bus) -> anyhow::Result<()> {
|
||||
type Error: StdSyncSendError;
|
||||
type Response: Message;
|
||||
|
||||
fn handle(&mut self, msg: M, bus: &Bus) -> Result<Self::Response, Self::Error>;
|
||||
fn sync(&mut self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait AsyncSynchronizedHandler<M: Message>: Send {
|
||||
async fn handle(&mut self, msg: M, bus: &Bus) -> anyhow::Result<()>;
|
||||
async fn sync(&mut self, _bus: &Bus) -> anyhow::Result<()> {
|
||||
type Error: StdSyncSendError;
|
||||
type Response: Message;
|
||||
|
||||
async fn handle(&mut self, msg: M, bus: &Bus) -> Result<Self::Response, Self::Error>;
|
||||
async fn sync(&mut self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait BatchHandler<M: Message>: Send + Sync {
|
||||
fn handle(&self, msg: Vec<M>, bus: &Bus) -> anyhow::Result<()>;
|
||||
fn sync(&self, _bus: &Bus) -> anyhow::Result<()> {
|
||||
type Error: StdSyncSendError + Clone;
|
||||
type Response: Message;
|
||||
type InBatch: FromIterator<M> + Send;
|
||||
type OutBatch: IntoIterator<Item = Self::Response> + Send;
|
||||
|
||||
fn handle(&self, msg: Self::InBatch, bus: &Bus) -> Result<Self::OutBatch, Self::Error>;
|
||||
fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait AsyncBatchHandler<M: Message>: Send + Sync {
|
||||
async fn handle(&self, msg: Vec<M>, bus: &Bus) -> anyhow::Result<()>;
|
||||
async fn sync(&self, _bus: &Bus) -> anyhow::Result<()> {
|
||||
type Error: StdSyncSendError + Clone;
|
||||
type Response: Message;
|
||||
type InBatch: FromIterator<M> + Send;
|
||||
type OutBatch: IntoIterator<Item = Self::Response> + Send;
|
||||
|
||||
async fn handle(&self, msg: Self::InBatch, bus: &Bus) -> Result<Self::OutBatch, Self::Error>;
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait BatchSynchronizedHandler<M: Message>: Send {
|
||||
fn handle(&mut self, msg: Vec<M>, bus: &Bus) -> anyhow::Result<()>;
|
||||
fn sync(&mut self, _bus: &Bus) -> anyhow::Result<()> {
|
||||
type Error: StdSyncSendError + Clone;
|
||||
type Response: Message;
|
||||
type InBatch: FromIterator<M> + Send;
|
||||
type OutBatch: IntoIterator<Item = Self::Response> + Send;
|
||||
|
||||
fn handle(&mut self, msg: Self::InBatch, bus: &Bus) -> Result<Self::OutBatch, Self::Error>;
|
||||
fn sync(&mut self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait AsyncBatchSynchronizedHandler<M: Message>: Send {
|
||||
async fn handle(&mut self, msg: Vec<M>, bus: &Bus) -> anyhow::Result<()>;
|
||||
async fn sync(&mut self, _bus: &Bus) -> anyhow::Result<()> {
|
||||
type Error: StdSyncSendError + Clone;
|
||||
type Response: Message;
|
||||
type InBatch: FromIterator<M> + Send;
|
||||
type OutBatch: IntoIterator<Item = Self::Response> + Send;
|
||||
|
||||
async fn handle(
|
||||
&mut self,
|
||||
msg: Self::InBatch,
|
||||
bus: &Bus,
|
||||
) -> Result<Self::OutBatch, Self::Error>;
|
||||
async fn sync(&mut self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait LocalHandler<M: Message> {
|
||||
fn handle(&mut self, msg: Vec<M>, bus: &Bus) -> anyhow::Result<()>;
|
||||
fn sync(&mut self, _bus: &Bus) -> anyhow::Result<()> {
|
||||
type Error: StdSyncSendError;
|
||||
type Response: Message;
|
||||
|
||||
fn handle(&mut self, msg: Vec<M>, bus: &Bus) -> Result<Self::Response, Self::Error>;
|
||||
fn sync(&mut self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait LocalAsyncHandler<M: Message> {
|
||||
async fn handle(&mut self, msg: Vec<M>, bus: &Bus) -> anyhow::Result<()>;
|
||||
async fn sync(&mut self, _bus: &Bus) -> anyhow::Result<()> {
|
||||
type Error: StdSyncSendError;
|
||||
type Response: Message;
|
||||
|
||||
async fn handle(&mut self, msg: Vec<M>, bus: &Bus) -> Result<Self::Response, Self::Error>;
|
||||
async fn sync(&mut self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait LocalBatchHandler<M: Message> {
|
||||
fn handle(&mut self, msg: Vec<M>, bus: &Bus) -> anyhow::Result<()>;
|
||||
fn sync(&mut self, _bus: &Bus) -> anyhow::Result<()> {
|
||||
type Error: StdSyncSendError + Clone;
|
||||
type Response: Message;
|
||||
type InBatch: FromIterator<M> + Send;
|
||||
type OutBatch: IntoIterator<Item = Self::Response> + Send;
|
||||
|
||||
fn handle(&mut self, msg: Self::InBatch, bus: &Bus) -> Result<Self::OutBatch, Self::Error>;
|
||||
fn sync(&mut self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait LocalAsyncBatchHandler<M: Message> {
|
||||
async fn handle(&mut self, msg: Vec<M>, bus: &Bus) -> anyhow::Result<()>;
|
||||
async fn sync(&mut self, _bus: &Bus) -> anyhow::Result<()> {
|
||||
type Error: StdSyncSendError + Clone;
|
||||
type Response: Message;
|
||||
type InBatch: FromIterator<M> + Send;
|
||||
type OutBatch: IntoIterator<Item = Self::Response> + Send;
|
||||
|
||||
async fn handle(
|
||||
&mut self,
|
||||
msg: Self::InBatch,
|
||||
bus: &Bus,
|
||||
) -> Result<Self::OutBatch, Self::Error>;
|
||||
async fn sync(&mut self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
875
src/lib.rs
875
src/lib.rs
@ -1,108 +1,124 @@
|
||||
mod builder;
|
||||
mod envelop;
|
||||
pub mod error;
|
||||
mod handler;
|
||||
pub mod msgs;
|
||||
mod receiver;
|
||||
pub mod receivers;
|
||||
mod relay;
|
||||
mod stats;
|
||||
mod trait_object;
|
||||
mod utils;
|
||||
pub mod type_tag;
|
||||
|
||||
pub mod __reexport {
|
||||
pub use ctor;
|
||||
pub use serde;
|
||||
}
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
pub mod derive {
|
||||
pub use messagebus_derive::*;
|
||||
}
|
||||
|
||||
// privavte
|
||||
use core::{
|
||||
any::Any,
|
||||
sync::atomic::{AtomicBool, AtomicU64, Ordering},
|
||||
time::Duration,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
sync::Arc,
|
||||
};
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use builder::BusBuilder;
|
||||
pub use envelop::Message;
|
||||
use error::{Error, SendError, StdSyncSendError};
|
||||
use receiver::{Permit, Receiver};
|
||||
use stats::Stats;
|
||||
|
||||
// public
|
||||
pub use builder::Module;
|
||||
pub use ctor;
|
||||
pub use envelop::{IntoBoxedMessage, Message, MessageBounds, SharedMessage, TypeTag, TypeTagged};
|
||||
pub use handler::*;
|
||||
pub use receiver::SendError;
|
||||
use receiver::{Receiver, ReceiverStats};
|
||||
use utils::binary_search_range_by_key;
|
||||
|
||||
use core::any::{Any, TypeId};
|
||||
use std::sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc,
|
||||
pub use receiver::{
|
||||
Action, Event, EventBoxed, ReciveTypedReceiver, ReciveUntypedReceiver, SendTypedReceiver,
|
||||
SendUntypedReceiver, TypeTagAccept, TypeTagAcceptItem,
|
||||
};
|
||||
|
||||
pub use relay::Relay;
|
||||
pub use type_tag::{deserialize_shared_message, register_shared_message};
|
||||
pub type Untyped = Arc<dyn Any + Send + Sync>;
|
||||
pub type Result = anyhow::Result<()>;
|
||||
|
||||
type LookupQuery = (TypeTag, Option<TypeTag>, Option<TypeTag>);
|
||||
|
||||
static ID_COUNTER: AtomicU64 = AtomicU64::new(1);
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum SendOptions {
|
||||
Broadcast,
|
||||
Except(u64),
|
||||
Direct(u64),
|
||||
Random,
|
||||
Balanced,
|
||||
}
|
||||
|
||||
impl Default for SendOptions {
|
||||
fn default() -> Self {
|
||||
Self::Broadcast
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BusInner {
|
||||
receivers: Vec<(TypeId, Receiver)>,
|
||||
receivers: HashSet<Receiver>,
|
||||
lookup: HashMap<LookupQuery, SmallVec<[Receiver; 4]>>,
|
||||
closed: AtomicBool,
|
||||
maintain: Mutex<()>,
|
||||
}
|
||||
|
||||
impl BusInner {
|
||||
pub(crate) fn new(mut receivers: Vec<(TypeId, Receiver)>) -> Self {
|
||||
receivers.sort_unstable_by_key(|(k, _)| *k);
|
||||
pub(crate) fn new(receivers: HashSet<Receiver>) -> Self {
|
||||
let mut lookup = HashMap::new();
|
||||
for recv in receivers.iter() {
|
||||
for (msg, resp) in recv.iter_types() {
|
||||
lookup
|
||||
.entry((msg.clone(), None, None))
|
||||
.or_insert_with(HashSet::new)
|
||||
.insert(recv.clone());
|
||||
|
||||
if let Some((resp, err)) = resp {
|
||||
lookup
|
||||
.entry((msg.clone(), Some(resp.clone()), None))
|
||||
.or_insert_with(HashSet::new)
|
||||
.insert(recv.clone());
|
||||
|
||||
lookup
|
||||
.entry((msg.clone(), None, Some(err.clone())))
|
||||
.or_insert_with(HashSet::new)
|
||||
.insert(recv.clone());
|
||||
|
||||
lookup
|
||||
.entry((msg, Some(resp), Some(err)))
|
||||
.or_insert_with(HashSet::new)
|
||||
.insert(recv.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let lookup = lookup
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, v.into_iter().collect()))
|
||||
.collect();
|
||||
|
||||
Self {
|
||||
receivers,
|
||||
lookup,
|
||||
closed: AtomicBool::new(false),
|
||||
maintain: Mutex::new(()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn close(&self) {
|
||||
self.closed.store(true, Ordering::SeqCst);
|
||||
|
||||
for (_, r) in &self.receivers {
|
||||
r.close();
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn sync(&self) {
|
||||
for (_, r) in &self.receivers {
|
||||
r.sync().await;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stats(&self) -> impl Iterator<Item = ReceiverStats> + '_ {
|
||||
self.receivers.iter().map(|(_, r)| r.stats())
|
||||
}
|
||||
|
||||
pub fn try_send<M: Message>(&self, msg: M) -> core::result::Result<(), SendError<M>> {
|
||||
if self.closed.load(Ordering::SeqCst) {
|
||||
println!("Bus closed. Skipping send!");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let tid = TypeId::of::<M>();
|
||||
let range = binary_search_range_by_key(&self.receivers, &tid, |(k, _)| *k);
|
||||
|
||||
for i in (range.start + 1)..range.end {
|
||||
self.receivers[i].1.try_broadcast(msg.clone())?;
|
||||
}
|
||||
|
||||
if let Some((_, r)) = self.receivers.get(range.start) {
|
||||
r.try_broadcast(msg.clone())?;
|
||||
} else {
|
||||
println!("Unhandled message {:?}", core::any::type_name::<M>());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn send_blocking<M: Message>(&self, msg: M) -> core::result::Result<(), SendError<M>> {
|
||||
futures::executor::block_on(self.send(msg))
|
||||
}
|
||||
|
||||
pub async fn send<M: Message>(&self, msg: M) -> core::result::Result<(), SendError<M>> {
|
||||
if self.closed.load(Ordering::SeqCst) {
|
||||
return Err(SendError::Closed(msg));
|
||||
}
|
||||
|
||||
let tid = TypeId::of::<M>();
|
||||
let range = binary_search_range_by_key(&self.receivers, &tid, |(k, _)| *k);
|
||||
|
||||
for i in (range.start + 1)..range.end {
|
||||
self.receivers[i].1.broadcast(msg.clone()).await?;
|
||||
}
|
||||
|
||||
if let Some((_, r)) = self.receivers.get(range.start) {
|
||||
r.broadcast(msg.clone()).await?;
|
||||
} else {
|
||||
println!("Unhandled message {:?}", core::any::type_name::<M>());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -110,17 +126,696 @@ pub struct Bus {
|
||||
inner: Arc<BusInner>,
|
||||
}
|
||||
|
||||
impl core::ops::Deref for Bus {
|
||||
type Target = BusInner;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.inner.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl Bus {
|
||||
#[inline]
|
||||
pub fn build() -> BusBuilder {
|
||||
BusBuilder::new()
|
||||
}
|
||||
|
||||
pub fn is_closing(&self) -> bool {
|
||||
self.inner.closed.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
pub(crate) fn init(&self) {
|
||||
for r in self.inner.receivers.iter() {
|
||||
r.init(self).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn ready(&self) {
|
||||
for r in self.inner.receivers.iter() {
|
||||
r.ready().await;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn close(&self) {
|
||||
let _handle = self.inner.maintain.lock().await;
|
||||
self.inner.closed.store(true, Ordering::SeqCst);
|
||||
|
||||
for r in self.inner.receivers.iter() {
|
||||
let err = tokio::time::timeout(Duration::from_secs(20), r.close(self)).await;
|
||||
|
||||
if let Err(err) = err {
|
||||
error!("Close timeout on {}: {}", r.name(), err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn flush_all(&self) {
|
||||
let fuse_count = 32i32;
|
||||
let mut breaked = false;
|
||||
let mut iters = 0usize;
|
||||
|
||||
for _ in 0..fuse_count {
|
||||
iters += 1;
|
||||
let mut flushed = false;
|
||||
for r in self.inner.receivers.iter() {
|
||||
if r.need_flush() {
|
||||
flushed = true;
|
||||
|
||||
r.flush(self).await;
|
||||
}
|
||||
}
|
||||
|
||||
if !flushed {
|
||||
breaked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if !breaked {
|
||||
warn!(
|
||||
"!!! WARNING: unable to reach equilibrium in {} iterations !!!",
|
||||
fuse_count
|
||||
);
|
||||
} else {
|
||||
info!("flushed in {} iterations !!!", iters);
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn flush<M: Message>(&self) {
|
||||
let fuse_count = 32i32;
|
||||
let mut breaked = false;
|
||||
let mut iters = 0usize;
|
||||
|
||||
for _ in 0..fuse_count {
|
||||
let receivers =
|
||||
self.select_receivers(M::type_tag_(), Default::default(), None, None, false);
|
||||
iters += 1;
|
||||
let mut flushed = false;
|
||||
for r in receivers {
|
||||
if r.need_flush() {
|
||||
flushed = true;
|
||||
|
||||
r.flush(self).await;
|
||||
}
|
||||
}
|
||||
|
||||
if !flushed {
|
||||
breaked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if !breaked {
|
||||
warn!(
|
||||
"!!! WARNING: unable to reach equilibrium in {} iterations !!!",
|
||||
fuse_count
|
||||
);
|
||||
} else {
|
||||
info!("flushed in {} iterations !!!", iters);
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn flush2<M1: Message, M2: Message>(&self) {
|
||||
let fuse_count = 32i32;
|
||||
let mut breaked = false;
|
||||
let mut iters = 0usize;
|
||||
for _ in 0..fuse_count {
|
||||
let receivers1 =
|
||||
self.select_receivers(M1::type_tag_(), Default::default(), None, None, false);
|
||||
|
||||
let receivers2 =
|
||||
self.select_receivers(M2::type_tag_(), Default::default(), None, None, false);
|
||||
|
||||
iters += 1;
|
||||
let mut flushed = false;
|
||||
for r in receivers1.chain(receivers2) {
|
||||
if r.need_flush() {
|
||||
flushed = true;
|
||||
|
||||
r.flush(self).await;
|
||||
}
|
||||
}
|
||||
|
||||
if !flushed {
|
||||
breaked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if !breaked {
|
||||
warn!(
|
||||
"!!! WARNING: unable to reach equilibrium in {} iterations !!!",
|
||||
fuse_count
|
||||
);
|
||||
} else {
|
||||
info!("flushed in {} iterations !!!", iters);
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn sync_all(&self) {
|
||||
for r in self.inner.receivers.iter() {
|
||||
r.sync(self).await;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn sync<M: Message>(&self) {
|
||||
let receivers =
|
||||
self.select_receivers(M::type_tag_(), Default::default(), None, None, false);
|
||||
|
||||
for r in receivers {
|
||||
r.sync(self).await;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn sync2<M1: Message, M2: Message>(&self) {
|
||||
let receivers1 =
|
||||
self.select_receivers(M1::type_tag_(), Default::default(), None, None, false);
|
||||
|
||||
let receivers2 =
|
||||
self.select_receivers(M2::type_tag_(), Default::default(), None, None, false);
|
||||
|
||||
for r in receivers1.chain(receivers2) {
|
||||
r.sync(self).await;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn idle_all(&self) {
|
||||
for r in self.inner.receivers.iter() {
|
||||
r.flush(self).await;
|
||||
r.idle().await;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn idle<M: Message>(&self) {
|
||||
let receivers =
|
||||
self.select_receivers(M::type_tag_(), Default::default(), None, None, false);
|
||||
|
||||
for r in receivers {
|
||||
r.flush(self).await;
|
||||
r.idle().await;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn idle2<M1: Message, M2: Message>(&self) {
|
||||
let receivers1 =
|
||||
self.select_receivers(M1::type_tag_(), Default::default(), None, None, false);
|
||||
|
||||
let receivers2 =
|
||||
self.select_receivers(M2::type_tag_(), Default::default(), None, None, false);
|
||||
|
||||
for r in receivers1.chain(receivers2) {
|
||||
r.flush(self).await;
|
||||
r.idle().await;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn flush_and_sync_all(&self, force: bool) {
|
||||
if !force {
|
||||
self.idle_all().await;
|
||||
}
|
||||
|
||||
println!("flushing all begin");
|
||||
self.flush_all().await;
|
||||
self.sync_all().await;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn flush_and_sync<M: Message>(&self, force: bool) {
|
||||
if !force {
|
||||
self.idle::<M>().await;
|
||||
}
|
||||
|
||||
println!("flushing 1 begin");
|
||||
self.flush::<M>().await;
|
||||
self.sync::<M>().await;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn flush_and_sync2<M1: Message, M2: Message>(&self, force: bool) {
|
||||
if !force {
|
||||
self.idle2::<M1, M2>().await;
|
||||
}
|
||||
println!("flushing 2 begin");
|
||||
self.flush2::<M1, M2>().await;
|
||||
self.sync2::<M1, M2>().await;
|
||||
}
|
||||
|
||||
fn try_reserve(&self, tt: &TypeTag, rs: &[Receiver]) -> Option<SmallVec<[Permit; 32]>> {
|
||||
let mut permits = SmallVec::<[Permit; 32]>::new();
|
||||
|
||||
for r in rs {
|
||||
if let Some(prmt) = r.try_reserve(tt) {
|
||||
permits.push(prmt);
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
}
|
||||
|
||||
Some(permits)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_send<M: Message + Clone>(&self, msg: M) -> Result<(), Error<M>> {
|
||||
self.try_send_ext(msg, SendOptions::Broadcast)
|
||||
}
|
||||
|
||||
pub fn try_send_ext<M: Message + Clone>(
|
||||
&self,
|
||||
msg: M,
|
||||
_options: SendOptions,
|
||||
) -> core::result::Result<(), Error<M>> {
|
||||
if self.inner.closed.load(Ordering::SeqCst) {
|
||||
return Err(SendError::Closed(msg).into());
|
||||
}
|
||||
|
||||
let tt = msg.type_tag();
|
||||
let mid = ID_COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
if let Some(rs) = self.inner.lookup.get(&(msg.type_tag(), None, None)) {
|
||||
let permits = if let Some(x) = self.try_reserve(&tt, rs) {
|
||||
x
|
||||
} else {
|
||||
return Err(SendError::Full(msg).into());
|
||||
};
|
||||
|
||||
let mut iter = permits.into_iter().zip(rs.iter());
|
||||
let mut counter = 1;
|
||||
let total = rs.len();
|
||||
|
||||
while counter < total {
|
||||
let (p, r) = iter.next().unwrap();
|
||||
let _ = r.send(self, mid, msg.clone(), false, p);
|
||||
|
||||
counter += 1;
|
||||
}
|
||||
|
||||
if let Some((p, r)) = iter.next() {
|
||||
let _ = r.send(self, mid, msg, false, p);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
warn!(
|
||||
"Unhandled message {:?}: no receivers",
|
||||
core::any::type_name::<M>()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn send_blocking<M: Message + Clone>(&self, msg: M) -> Result<(), Error<M>> {
|
||||
self.send_blocking_ext(msg, SendOptions::Broadcast)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn send_blocking_ext<M: Message + Clone>(
|
||||
&self,
|
||||
msg: M,
|
||||
options: SendOptions,
|
||||
) -> core::result::Result<(), Error<M>> {
|
||||
futures::executor::block_on(self.send_ext(msg, options))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn send<M: Message + Clone>(&self, msg: M) -> core::result::Result<(), Error<M>> {
|
||||
Ok(self.send_ext(msg, SendOptions::Broadcast).await?)
|
||||
}
|
||||
|
||||
pub async fn send_ext<M: Message + Clone>(
|
||||
&self,
|
||||
msg: M,
|
||||
_options: SendOptions,
|
||||
) -> core::result::Result<(), Error<M>> {
|
||||
if self.inner.closed.load(Ordering::SeqCst) {
|
||||
return Err(SendError::Closed(msg).into());
|
||||
}
|
||||
|
||||
let tt = msg.type_tag();
|
||||
let mid = ID_COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
if let Some(rs) = self.inner.lookup.get(&(msg.type_tag(), None, None)) {
|
||||
if let Some((last, head)) = rs.split_last() {
|
||||
for r in head {
|
||||
let _ = r.send(self, mid, msg.clone(), false, r.reserve(&tt).await);
|
||||
}
|
||||
|
||||
let _ = last.send(self, mid, msg, false, last.reserve(&tt).await);
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
warn!(
|
||||
"Unhandled message {:?}: no receivers",
|
||||
core::any::type_name::<M>()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn force_send<M: Message + Clone>(&self, msg: M) -> Result<(), Error<M>> {
|
||||
self.force_send_ext(msg, SendOptions::Broadcast)
|
||||
}
|
||||
|
||||
pub fn force_send_ext<M: Message + Clone>(
|
||||
&self,
|
||||
msg: M,
|
||||
_options: SendOptions,
|
||||
) -> core::result::Result<(), Error<M>> {
|
||||
if self.inner.closed.load(Ordering::SeqCst) {
|
||||
return Err(SendError::Closed(msg).into());
|
||||
}
|
||||
|
||||
let mid = ID_COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
if let Some(rs) = self.inner.lookup.get(&(msg.type_tag(), None, None)) {
|
||||
if let Some((last, head)) = rs.split_last() {
|
||||
for r in head {
|
||||
let _ = r.force_send(self, mid, msg.clone(), false);
|
||||
}
|
||||
|
||||
let _ = last.force_send(self, mid, msg, false);
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
warn!(
|
||||
"Unhandled message {:?}: no receivers",
|
||||
core::any::type_name::<M>()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_send_one<M: Message>(&self, msg: M) -> Result<(), Error<M>> {
|
||||
if self.inner.closed.load(Ordering::SeqCst) {
|
||||
return Err(SendError::Closed(msg).into());
|
||||
}
|
||||
|
||||
let tt = msg.type_tag();
|
||||
let mid = ID_COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
if let Some(rs) = self
|
||||
.inner
|
||||
.lookup
|
||||
.get(&(msg.type_tag(), None, None))
|
||||
.and_then(|rs| rs.first())
|
||||
{
|
||||
let permits = if let Some(x) = rs.try_reserve(&tt) {
|
||||
x
|
||||
} else {
|
||||
return Err(SendError::Full(msg).into());
|
||||
};
|
||||
|
||||
Ok(rs.send(self, mid, msg, false, permits)?)
|
||||
} else {
|
||||
Err(Error::NoReceivers)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send_one<M: Message>(&self, msg: M) -> Result<(), Error<M>> {
|
||||
if self.inner.closed.load(Ordering::SeqCst) {
|
||||
return Err(SendError::Closed(msg).into());
|
||||
}
|
||||
|
||||
let tt = msg.type_tag();
|
||||
let mid = ID_COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
if let Some(rs) = self
|
||||
.inner
|
||||
.lookup
|
||||
.get(&(msg.type_tag(), None, None))
|
||||
.and_then(|rs| rs.first())
|
||||
{
|
||||
Ok(rs.send(self, mid, msg, false, rs.reserve(&tt).await)?)
|
||||
} else {
|
||||
Err(Error::NoReceivers)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn send_one_blocking<M: Message>(&self, msg: M) -> Result<(), Error<M>> {
|
||||
futures::executor::block_on(self.send_one(msg))
|
||||
}
|
||||
|
||||
pub async fn request<M: Message, R: Message>(
|
||||
&self,
|
||||
req: M,
|
||||
options: SendOptions,
|
||||
) -> Result<R, Error<M>> {
|
||||
let tid = M::type_tag_();
|
||||
let rid = R::type_tag_();
|
||||
|
||||
let mut iter = self.select_receivers(tid.clone(), options, Some(rid), None, true);
|
||||
if let Some(rc) = iter.next() {
|
||||
let (mid, rx) = rc
|
||||
.add_response_waiter::<R>()
|
||||
.map_err(|x| x.specify::<M>())?;
|
||||
|
||||
let mid = mid | 1 << (u64::BITS - 1);
|
||||
|
||||
rc.send(self, mid, req, true, rc.reserve(&tid).await)?;
|
||||
rx.await.map_err(|x| x.specify::<M>())
|
||||
} else {
|
||||
Err(Error::NoReceivers)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn request_we<M, R, E>(&self, req: M, options: SendOptions) -> Result<R, Error<M, E>>
|
||||
where
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
let tid = M::type_tag_();
|
||||
let rid = R::type_tag_();
|
||||
let eid = E::type_tag_();
|
||||
|
||||
let mut iter = self.select_receivers(tid.clone(), options, Some(rid), Some(eid), true);
|
||||
if let Some(rc) = iter.next() {
|
||||
let (mid, rx) = rc.add_response_waiter_we::<R, E>().map_err(|x| {
|
||||
x.map_err(|_| unimplemented!())
|
||||
.map_msg(|_| unimplemented!())
|
||||
})?;
|
||||
|
||||
rc.send(
|
||||
self,
|
||||
mid | 1 << (u64::BITS - 1),
|
||||
req,
|
||||
true,
|
||||
rc.reserve(&tid).await,
|
||||
)
|
||||
.map_err(|x| x.map_err(|_| unimplemented!()))?;
|
||||
|
||||
rx.await.map_err(|x| x.specify::<M>())
|
||||
} else {
|
||||
Err(Error::NoReceivers)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send_boxed(
|
||||
&self,
|
||||
msg: Box<dyn Message>,
|
||||
options: SendOptions,
|
||||
) -> Result<(), Error<Box<dyn Message>>> {
|
||||
if self.inner.closed.load(Ordering::SeqCst) {
|
||||
return Err(SendError::Closed(msg).into());
|
||||
}
|
||||
|
||||
let tt = msg.type_tag();
|
||||
let mid = ID_COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
let mut iter = self.select_receivers(tt.clone(), options, None, None, false);
|
||||
let first = iter.next();
|
||||
|
||||
for r in iter {
|
||||
let _ = r.send_boxed(
|
||||
self,
|
||||
mid,
|
||||
msg.try_clone_boxed().unwrap(),
|
||||
false,
|
||||
r.reserve(&tt).await,
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(r) = first {
|
||||
let _ = r.send_boxed(
|
||||
self,
|
||||
mid,
|
||||
msg.try_clone_boxed().unwrap(),
|
||||
false,
|
||||
r.reserve(&tt).await,
|
||||
);
|
||||
} else {
|
||||
warn!("Unhandled message: no receivers");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn send_boxed_one(
|
||||
&self,
|
||||
msg: Box<dyn Message>,
|
||||
options: SendOptions,
|
||||
) -> Result<(), Error<Box<dyn Message>>> {
|
||||
if self.inner.closed.load(Ordering::SeqCst) {
|
||||
return Err(SendError::Closed(msg).into());
|
||||
}
|
||||
|
||||
let tt = msg.type_tag();
|
||||
let mid = ID_COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
let mut iter = self.select_receivers(tt.clone(), options, None, None, false);
|
||||
if let Some(rs) = iter.next() {
|
||||
Ok(rs.send_boxed(self, mid, msg, false, rs.reserve(&tt).await)?)
|
||||
} else {
|
||||
Err(Error::NoReceivers)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn request_boxed(
|
||||
&self,
|
||||
req: Box<dyn Message>,
|
||||
options: SendOptions,
|
||||
) -> Result<Box<dyn Message>, Error<Box<dyn Message>>> {
|
||||
if self.inner.closed.load(Ordering::SeqCst) {
|
||||
return Err(SendError::Closed(req).into());
|
||||
}
|
||||
|
||||
let tt = req.type_tag();
|
||||
|
||||
let mut iter = self.select_receivers(tt.clone(), options, None, None, true);
|
||||
if let Some(rc) = iter.next() {
|
||||
let (mid, rx) = rc.add_response_waiter_boxed().map_err(|x| {
|
||||
x.map_err(|_| unimplemented!())
|
||||
.map_msg(|_| unimplemented!())
|
||||
})?;
|
||||
|
||||
rc.send_boxed(
|
||||
self,
|
||||
mid | 1 << (usize::BITS - 1),
|
||||
req,
|
||||
true,
|
||||
rc.reserve(&tt).await,
|
||||
)?;
|
||||
|
||||
rx.await.map_err(|x| x.specify::<Box<dyn Message>>())
|
||||
} else {
|
||||
Err(Error::NoReceivers)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn request_boxed_we<E: StdSyncSendError>(
|
||||
&self,
|
||||
req: Box<dyn Message>,
|
||||
options: SendOptions,
|
||||
) -> Result<Box<dyn Message>, Error<Box<dyn Message>, E>> {
|
||||
if self.inner.closed.load(Ordering::SeqCst) {
|
||||
return Err(SendError::Closed(req).into());
|
||||
}
|
||||
|
||||
let tt = req.type_tag();
|
||||
let eid = E::type_tag_();
|
||||
|
||||
let mut iter = self.select_receivers(tt.clone(), options, None, Some(eid), true);
|
||||
if let Some(rc) = iter.next() {
|
||||
let (mid, rx) = rc.add_response_waiter_boxed_we().map_err(|x| {
|
||||
x.map_err(|_| unimplemented!())
|
||||
.map_msg(|_| unimplemented!())
|
||||
})?;
|
||||
|
||||
rc.send_boxed(
|
||||
self,
|
||||
mid | 1 << (usize::BITS - 1),
|
||||
req,
|
||||
true,
|
||||
rc.reserve(&tt).await,
|
||||
)
|
||||
.map_err(|x| x.map_err(|_| unimplemented!()))?;
|
||||
|
||||
rx.await.map_err(|x| x.specify::<Box<dyn Message>>())
|
||||
} else {
|
||||
Err(Error::NoReceivers)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send_deserialize_one<'a, 'b: 'a, 'c: 'a>(
|
||||
&'a self,
|
||||
tt: TypeTag,
|
||||
de: &'b mut dyn erased_serde::Deserializer<'c>,
|
||||
_options: SendOptions,
|
||||
) -> Result<(), Error<Box<dyn Message>>> {
|
||||
if self.inner.closed.load(Ordering::SeqCst) {
|
||||
warn!("closed message bus");
|
||||
return Err(Error::NoResponse);
|
||||
}
|
||||
|
||||
let mid = ID_COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
if let Some(rs) = self
|
||||
.inner
|
||||
.lookup
|
||||
.get(&(tt.clone(), None, None))
|
||||
.and_then(|rs| rs.first())
|
||||
{
|
||||
let msg = deserialize_shared_message(tt.clone(), de)?;
|
||||
|
||||
Ok(rs.send_boxed(self, mid, msg.upcast_box(), false, rs.reserve(&tt).await)?)
|
||||
} else {
|
||||
Err(Error::NoReceivers)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn request_deserialize<'a, 'b: 'a, 'c: 'a>(
|
||||
&'a self,
|
||||
tt: TypeTag,
|
||||
de: &'b mut dyn erased_serde::Deserializer<'c>,
|
||||
options: SendOptions,
|
||||
) -> Result<Box<dyn Message>, Error<Box<dyn Message>>> {
|
||||
if self.inner.closed.load(Ordering::SeqCst) {
|
||||
warn!("closed message bus");
|
||||
return Err(Error::NoResponse);
|
||||
}
|
||||
|
||||
let mut iter = self.select_receivers(tt.clone(), options, None, None, true);
|
||||
if let Some(rc) = iter.next() {
|
||||
let (mid, rx) = rc.add_response_waiter_boxed().unwrap();
|
||||
let msg = deserialize_shared_message(tt.clone(), de)?;
|
||||
|
||||
rc.send_boxed(
|
||||
self,
|
||||
mid | 1 << (usize::BITS - 1),
|
||||
msg.upcast_box(),
|
||||
true,
|
||||
rc.reserve(&tt).await,
|
||||
)?;
|
||||
|
||||
rx.await.map_err(|x| x.specify::<Box<dyn Message>>())
|
||||
} else {
|
||||
Err(Error::NoReceivers)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stats(&self) -> impl Iterator<Item = Stats> + '_ {
|
||||
self.inner.receivers.iter().map(|x| x.stats())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn select_receivers(
|
||||
&self,
|
||||
tid: TypeTag,
|
||||
options: SendOptions,
|
||||
rid: Option<TypeTag>,
|
||||
eid: Option<TypeTag>,
|
||||
is_req: bool,
|
||||
) -> impl Iterator<Item = &Receiver> + '_ {
|
||||
self.inner
|
||||
.lookup
|
||||
.get(&(tid.clone(), rid.clone(), eid.clone()))
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.filter(move |r| r.accept(is_req, &tid, rid.as_ref(), eid.as_ref()))
|
||||
.filter(move |r| match options {
|
||||
SendOptions::Except(id) => id != r.id(),
|
||||
SendOptions::Direct(id) => id == r.id(),
|
||||
_ => true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
10
src/msgs.rs
10
src/msgs.rs
@ -1,10 +0,0 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Error(pub Arc<anyhow::Error>);
|
||||
|
||||
impl<T: Into<anyhow::Error>> From<T> for Error {
|
||||
fn from(e: T) -> Self {
|
||||
Self(Arc::new(e.into()))
|
||||
}
|
||||
}
|
1113
src/receiver.rs
1113
src/receiver.rs
File diff suppressed because it is too large
Load Diff
@ -1,48 +1,65 @@
|
||||
use std::{
|
||||
any::TypeId,
|
||||
marker::PhantomData,
|
||||
pin::Pin,
|
||||
sync::{
|
||||
atomic::{AtomicU64, Ordering},
|
||||
Arc,
|
||||
},
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
use crate::{receiver::ReceiverStats, receivers::mpsc};
|
||||
use futures::{Future, StreamExt};
|
||||
|
||||
use super::{BufferUnorderedConfig, BufferUnorderedStats};
|
||||
use crate::{
|
||||
builder::{ReceiverSubscriber, ReceiverSubscriberBuilder},
|
||||
msgs,
|
||||
receiver::{AnyReceiver, ReceiverTrait, SendError, TypedReceiver},
|
||||
buffer_unordered_poller_macro,
|
||||
builder::ReceiverSubscriberBuilder,
|
||||
error::{Error, StdSyncSendError},
|
||||
receiver::{
|
||||
Action, Event, ReciveTypedReceiver, SendTypedReceiver, SendUntypedReceiver,
|
||||
UntypedPollerCallback,
|
||||
},
|
||||
receivers::Request,
|
||||
AsyncHandler, Bus, Message, Untyped,
|
||||
};
|
||||
|
||||
pub struct BufferUnorderedAsyncSubscriber<T, M>
|
||||
use super::{BufferUnorderedConfig, BufferUnorderedStats};
|
||||
|
||||
use futures::{Future, Stream};
|
||||
use parking_lot::Mutex;
|
||||
use tokio::sync::mpsc::{self, UnboundedSender};
|
||||
|
||||
buffer_unordered_poller_macro!(
|
||||
T,
|
||||
AsyncHandler,
|
||||
|mid, msg, bus, ut: Arc<T>, stx: UnboundedSender<_>, task_permit| {
|
||||
tokio::spawn(async move {
|
||||
let resp = ut.handle(msg, &bus).await;
|
||||
drop(task_permit);
|
||||
|
||||
stx.send(Event::Response(mid, resp.map_err(Error::Other)))
|
||||
.unwrap();
|
||||
})
|
||||
},
|
||||
|bus, ut: Arc<T>| { async move { ut.sync(&bus).await } }
|
||||
);
|
||||
|
||||
pub struct BufferUnorderedAsync<M, R, E>
|
||||
where
|
||||
T: AsyncHandler<M> + 'static,
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
cfg: BufferUnorderedConfig,
|
||||
_m: PhantomData<(T, M)>,
|
||||
tx: mpsc::UnboundedSender<Request<M>>,
|
||||
stats: Arc<BufferUnorderedStats>,
|
||||
srx: Mutex<Option<mpsc::UnboundedReceiver<Event<R, E>>>>,
|
||||
}
|
||||
|
||||
impl<T, M> ReceiverSubscriber<T> for BufferUnorderedAsyncSubscriber<T, M>
|
||||
impl<T, M, R, E> ReceiverSubscriberBuilder<T, M, R, E> for BufferUnorderedAsync<M, R, E>
|
||||
where
|
||||
T: AsyncHandler<M> + 'static,
|
||||
T: AsyncHandler<M, Response = R, Error = E> + 'static,
|
||||
R: Message,
|
||||
M: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
fn subscribe(
|
||||
self,
|
||||
) -> (
|
||||
Arc<dyn ReceiverTrait>,
|
||||
Box<
|
||||
dyn FnOnce(Untyped) -> Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>,
|
||||
>,
|
||||
) {
|
||||
let cfg = self.cfg;
|
||||
type Config = BufferUnorderedConfig;
|
||||
|
||||
fn build(cfg: Self::Config) -> (Self, UntypedPollerCallback) {
|
||||
let stats = Arc::new(BufferUnorderedStats {
|
||||
buffer: AtomicU64::new(0),
|
||||
buffer_total: AtomicU64::new(cfg.buffer_size as _),
|
||||
@ -50,154 +67,81 @@ where
|
||||
parallel_total: AtomicU64::new(cfg.max_parallel as _),
|
||||
});
|
||||
|
||||
let (tx, rx) = mpsc::channel(cfg.buffer_size);
|
||||
let arc = Arc::new(BufferUnorderedAsync::<M> {
|
||||
tx,
|
||||
stats: stats.clone(),
|
||||
});
|
||||
let (stx, srx) = mpsc::unbounded_channel();
|
||||
let (tx, rx) = mpsc::unbounded_channel();
|
||||
let stats_clone = stats.clone();
|
||||
|
||||
let poller = Box::new(move |ut| {
|
||||
Box::new(move |bus| {
|
||||
Box::pin(buffer_unordered_poller::<T, M>(rx, bus, ut, stats, cfg))
|
||||
as Pin<Box<dyn Future<Output = ()> + Send>>
|
||||
Box::pin(buffer_unordered_poller::<T, M, R, E>(
|
||||
rx,
|
||||
bus,
|
||||
ut,
|
||||
stats_clone,
|
||||
cfg,
|
||||
stx,
|
||||
)) as Pin<Box<dyn Future<Output = ()> + Send>>
|
||||
}) as Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>
|
||||
});
|
||||
|
||||
(arc, poller)
|
||||
(
|
||||
BufferUnorderedAsync::<M, R, E> {
|
||||
tx,
|
||||
stats,
|
||||
srx: Mutex::new(Some(srx)),
|
||||
},
|
||||
poller,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async fn buffer_unordered_poller<T, M>(
|
||||
rx: mpsc::Receiver<M>,
|
||||
bus: Bus,
|
||||
ut: Untyped,
|
||||
stats: Arc<BufferUnorderedStats>,
|
||||
cfg: BufferUnorderedConfig,
|
||||
) where
|
||||
T: AsyncHandler<M> + 'static,
|
||||
M: Message,
|
||||
{
|
||||
let ut = ut.downcast::<T>().unwrap();
|
||||
|
||||
let mut x = rx
|
||||
.map(|msg| {
|
||||
stats.buffer.fetch_sub(1, Ordering::Relaxed);
|
||||
stats.parallel.fetch_add(1, Ordering::Relaxed);
|
||||
let bus = bus.clone();
|
||||
let ut = ut.clone();
|
||||
|
||||
tokio::task::spawn(async move { ut.handle(msg, &bus).await })
|
||||
})
|
||||
.buffer_unordered(cfg.max_parallel);
|
||||
|
||||
while let Some(err) = x.next().await {
|
||||
stats.parallel.fetch_sub(1, Ordering::Relaxed);
|
||||
|
||||
match err {
|
||||
Ok(Err(err)) => {
|
||||
let _ = bus.send(msgs::Error(Arc::new(err))).await;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
let ut = ut.clone();
|
||||
let bus_clone = bus.clone();
|
||||
let res = tokio::task::spawn(async move { ut.sync(&bus_clone).await }).await;
|
||||
|
||||
match res {
|
||||
Ok(Err(err)) => {
|
||||
let _ = bus.send(msgs::Error(Arc::new(err))).await;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
println!(
|
||||
"[EXIT] BufferUnorderedAsync<{}>",
|
||||
std::any::type_name::<M>()
|
||||
);
|
||||
}
|
||||
|
||||
pub struct BufferUnorderedAsync<M: Message> {
|
||||
tx: mpsc::Sender<M>,
|
||||
stats: Arc<BufferUnorderedStats>,
|
||||
}
|
||||
|
||||
impl<T, M> ReceiverSubscriberBuilder<M, T> for BufferUnorderedAsync<M>
|
||||
impl<M, R, E> SendUntypedReceiver for BufferUnorderedAsync<M, R, E>
|
||||
where
|
||||
T: AsyncHandler<M> + 'static,
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
type Entry = BufferUnorderedAsyncSubscriber<T, M>;
|
||||
type Config = BufferUnorderedConfig;
|
||||
|
||||
fn build(cfg: Self::Config) -> Self::Entry {
|
||||
BufferUnorderedAsyncSubscriber {
|
||||
cfg,
|
||||
_m: Default::default(),
|
||||
fn send(&self, m: Action, _bus: &Bus) -> Result<(), Error<Action>> {
|
||||
match self.tx.send(Request::Action(m)) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(mpsc::error::SendError(Request::Action(msg))) => Err(Error::send_closed(msg)),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Message> TypedReceiver<M> for BufferUnorderedAsync<M> {
|
||||
fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll<()> {
|
||||
match self.tx.poll_ready(ctx) {
|
||||
Poll::Ready(_) => Poll::Ready(()),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
|
||||
fn try_send(&self, m: M) -> Result<(), SendError<M>> {
|
||||
match self.tx.try_send(m) {
|
||||
impl<M, R, E> SendTypedReceiver<M> for BufferUnorderedAsync<M, R, E>
|
||||
where
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
fn send(&self, mid: u64, m: M, req: bool, _bus: &Bus) -> Result<(), Error<M>> {
|
||||
match self.tx.send(Request::Request(mid, m, req)) {
|
||||
Ok(_) => {
|
||||
self.stats.buffer.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
Err(mpsc::error::SendError(Request::Request(_, msg, _))) => {
|
||||
Err(Error::send_closed(msg))
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Message> ReceiverTrait for BufferUnorderedAsync<M> {
|
||||
fn typed(&self) -> AnyReceiver<'_> {
|
||||
AnyReceiver::new(self)
|
||||
}
|
||||
impl<M, R, E> ReciveTypedReceiver<R, E> for BufferUnorderedAsync<M, R, E>
|
||||
where
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
type Stream = Pin<Box<dyn Stream<Item = Event<R, E>> + Send>>;
|
||||
|
||||
fn type_id(&self) -> TypeId {
|
||||
TypeId::of::<BufferUnorderedAsync<M>>()
|
||||
}
|
||||
fn event_stream(&self, _: Bus) -> Self::Stream {
|
||||
let mut rx = self.srx.lock().take().unwrap();
|
||||
|
||||
fn close(&self) {
|
||||
self.tx.close();
|
||||
}
|
||||
|
||||
fn stats(&self) -> ReceiverStats {
|
||||
ReceiverStats {
|
||||
name: std::any::type_name::<M>().into(),
|
||||
fields: vec![
|
||||
("buffer".into(), self.stats.buffer.load(Ordering::SeqCst)),
|
||||
(
|
||||
"buffer_total".into(),
|
||||
self.stats.buffer_total.load(Ordering::SeqCst),
|
||||
),
|
||||
(
|
||||
"parallel".into(),
|
||||
self.stats.parallel.load(Ordering::SeqCst),
|
||||
),
|
||||
(
|
||||
"parallel_total".into(),
|
||||
self.stats.parallel_total.load(Ordering::SeqCst),
|
||||
),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
fn sync(&self) {
|
||||
self.tx.flush();
|
||||
}
|
||||
|
||||
fn poll_synchronized(&self, _ctx: &mut Context<'_>) -> Poll<()> {
|
||||
Poll::Ready(())
|
||||
Box::pin(futures::stream::poll_fn(move |cx| rx.poll_recv(cx)))
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,9 @@ mod sync;
|
||||
|
||||
use std::sync::atomic::AtomicU64;
|
||||
|
||||
pub use r#async::{BufferUnorderedAsync, BufferUnorderedAsyncSubscriber};
|
||||
pub use sync::{BufferUnorderedSync, BufferUnorderedSyncSubscriber};
|
||||
pub use r#async::BufferUnorderedAsync;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
pub use sync::BufferUnorderedSync;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BufferUnorderedStats {
|
||||
@ -14,7 +15,7 @@ pub struct BufferUnorderedStats {
|
||||
pub parallel_total: AtomicU64,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct BufferUnorderedConfig {
|
||||
pub buffer_size: usize,
|
||||
pub max_parallel: usize,
|
||||
@ -28,3 +29,62 @@ impl Default for BufferUnorderedConfig {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! buffer_unordered_poller_macro {
|
||||
($t: tt, $h: tt, $st1: expr, $st2: expr) => {
|
||||
async fn buffer_unordered_poller<$t, M, R, E>(
|
||||
mut rx: mpsc::UnboundedReceiver<Request<M>>,
|
||||
bus: Bus,
|
||||
ut: Untyped,
|
||||
_stats: Arc<BufferUnorderedStats>,
|
||||
cfg: BufferUnorderedConfig,
|
||||
stx: mpsc::UnboundedSender<Event<R, E>>,
|
||||
) where
|
||||
$t: $h<M, Response = R, Error = E> + 'static,
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
let ut = ut.downcast::<$t>().unwrap();
|
||||
let semaphore = Arc::new(tokio::sync::Semaphore::new(cfg.max_parallel));
|
||||
|
||||
while let Some(msg) = rx.recv().await {
|
||||
match msg {
|
||||
Request::Request(mid, msg, _req) => {
|
||||
#[allow(clippy::redundant_closure_call)]
|
||||
let _ = ($st1)(
|
||||
mid,
|
||||
msg,
|
||||
bus.clone(),
|
||||
ut.clone(),
|
||||
stx.clone(),
|
||||
semaphore.clone().acquire_owned().await,
|
||||
);
|
||||
}
|
||||
|
||||
Request::Action(Action::Init(..)) => stx.send(Event::Ready).unwrap(),
|
||||
Request::Action(Action::Close) => rx.close(),
|
||||
|
||||
Request::Action(Action::Flush) => {
|
||||
let _ = semaphore.acquire_many(cfg.max_parallel as _).await;
|
||||
stx.send(Event::Flushed).unwrap();
|
||||
}
|
||||
|
||||
Request::Action(Action::Sync) => {
|
||||
let lock = semaphore.acquire_many(cfg.max_parallel as _).await;
|
||||
|
||||
#[allow(clippy::redundant_closure_call)]
|
||||
let resp = ($st2)(bus.clone(), ut.clone()).await;
|
||||
drop(lock);
|
||||
|
||||
stx.send(Event::Synchronized(resp.map_err(Error::Other)))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1,48 +1,68 @@
|
||||
use crate::{receiver::ReceiverStats, receivers::mpsc};
|
||||
use futures::{Future, StreamExt};
|
||||
use std::{
|
||||
any::TypeId,
|
||||
marker::PhantomData,
|
||||
pin::Pin,
|
||||
sync::{
|
||||
atomic::{AtomicU64, Ordering},
|
||||
Arc,
|
||||
},
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
use super::{BufferUnorderedConfig, BufferUnorderedStats};
|
||||
use crate::{
|
||||
builder::{ReceiverSubscriber, ReceiverSubscriberBuilder},
|
||||
msgs,
|
||||
receiver::{AnyReceiver, ReceiverTrait, SendError, TypedReceiver},
|
||||
buffer_unordered_poller_macro,
|
||||
builder::ReceiverSubscriberBuilder,
|
||||
error::{Error, StdSyncSendError},
|
||||
receiver::{
|
||||
Action, Event, ReciveTypedReceiver, SendTypedReceiver, SendUntypedReceiver,
|
||||
UntypedPollerCallback,
|
||||
},
|
||||
receivers::Request,
|
||||
Bus, Handler, Message, Untyped,
|
||||
};
|
||||
|
||||
pub struct BufferUnorderedSyncSubscriber<T, M>
|
||||
use futures::{Future, Stream};
|
||||
use parking_lot::Mutex;
|
||||
use tokio::sync::mpsc::{self, UnboundedSender};
|
||||
|
||||
buffer_unordered_poller_macro!(
|
||||
T,
|
||||
Handler,
|
||||
|mid, msg, bus, ut: Arc<T>, stx: UnboundedSender<_>, task_permit| {
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let resp = ut.handle(msg, &bus);
|
||||
drop(task_permit);
|
||||
|
||||
stx.send(Event::Response(mid, resp.map_err(Error::Other)))
|
||||
.unwrap();
|
||||
})
|
||||
},
|
||||
|bus, ut: Arc<T>| async move {
|
||||
tokio::task::spawn_blocking(move || ut.sync(&bus))
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
);
|
||||
|
||||
pub struct BufferUnorderedSync<M, R, E>
|
||||
where
|
||||
T: Handler<M> + 'static,
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
cfg: BufferUnorderedConfig,
|
||||
_m: PhantomData<(M, T)>,
|
||||
tx: mpsc::UnboundedSender<Request<M>>,
|
||||
stats: Arc<BufferUnorderedStats>,
|
||||
srx: Mutex<Option<mpsc::UnboundedReceiver<Event<R, E>>>>,
|
||||
}
|
||||
|
||||
impl<T, M> ReceiverSubscriber<T> for BufferUnorderedSyncSubscriber<T, M>
|
||||
impl<T, M, R, E> ReceiverSubscriberBuilder<T, M, R, E> for BufferUnorderedSync<M, R, E>
|
||||
where
|
||||
T: Handler<M> + 'static,
|
||||
T: Handler<M, Response = R, Error = E> + 'static,
|
||||
R: Message,
|
||||
M: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
fn subscribe(
|
||||
self,
|
||||
) -> (
|
||||
Arc<dyn ReceiverTrait>,
|
||||
Box<
|
||||
dyn FnOnce(Untyped) -> Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>,
|
||||
>,
|
||||
) {
|
||||
let cfg = self.cfg;
|
||||
let (tx, rx) = mpsc::channel(cfg.buffer_size);
|
||||
type Config = BufferUnorderedConfig;
|
||||
|
||||
fn build(cfg: Self::Config) -> (Self, UntypedPollerCallback) {
|
||||
let stats = Arc::new(BufferUnorderedStats {
|
||||
buffer: AtomicU64::new(0),
|
||||
buffer_total: AtomicU64::new(cfg.buffer_size as _),
|
||||
@ -50,154 +70,81 @@ where
|
||||
parallel_total: AtomicU64::new(cfg.max_parallel as _),
|
||||
});
|
||||
|
||||
let arc = Arc::new(BufferUnorderedSync::<M> {
|
||||
tx,
|
||||
stats: stats.clone(),
|
||||
});
|
||||
let (stx, srx) = mpsc::unbounded_channel();
|
||||
let (tx, rx) = mpsc::unbounded_channel();
|
||||
let stats_clone = stats.clone();
|
||||
|
||||
let poller = Box::new(move |ut| {
|
||||
Box::new(move |bus| {
|
||||
Box::pin(buffer_unordered_poller::<T, M>(rx, bus, ut, stats, cfg))
|
||||
as Pin<Box<dyn Future<Output = ()> + Send>>
|
||||
Box::pin(buffer_unordered_poller::<T, M, R, E>(
|
||||
rx,
|
||||
bus,
|
||||
ut,
|
||||
stats_clone,
|
||||
cfg,
|
||||
stx,
|
||||
)) as Pin<Box<dyn Future<Output = ()> + Send>>
|
||||
}) as Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>
|
||||
});
|
||||
|
||||
(arc, poller)
|
||||
(
|
||||
BufferUnorderedSync::<M, R, E> {
|
||||
tx,
|
||||
stats,
|
||||
srx: Mutex::new(Some(srx)),
|
||||
},
|
||||
poller,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async fn buffer_unordered_poller<T, M>(
|
||||
rx: mpsc::Receiver<M>,
|
||||
bus: Bus,
|
||||
ut: Untyped,
|
||||
stats: Arc<BufferUnorderedStats>,
|
||||
cfg: BufferUnorderedConfig,
|
||||
) where
|
||||
T: Handler<M> + 'static,
|
||||
M: Message,
|
||||
{
|
||||
let ut = ut.downcast::<T>().unwrap();
|
||||
|
||||
let mut x = rx
|
||||
.map(|msg| {
|
||||
stats.buffer.fetch_sub(1, Ordering::Relaxed);
|
||||
stats.parallel.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
let bus = bus.clone();
|
||||
let ut = ut.clone();
|
||||
|
||||
tokio::task::spawn_blocking(move || ut.handle(msg, &bus))
|
||||
})
|
||||
.buffer_unordered(cfg.max_parallel);
|
||||
|
||||
while let Some(err) = x.next().await {
|
||||
stats.parallel.fetch_sub(1, Ordering::Relaxed);
|
||||
|
||||
match err {
|
||||
Ok(Err(err)) => {
|
||||
let _ = bus.send(msgs::Error(Arc::new(err))).await;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
let ut = ut.clone();
|
||||
let bus_clone = bus.clone();
|
||||
let res = tokio::task::spawn_blocking(move || ut.sync(&bus_clone)).await;
|
||||
|
||||
match res {
|
||||
Ok(Err(err)) => {
|
||||
let _ = bus.send(msgs::Error(Arc::new(err))).await;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
println!(
|
||||
"[EXIT] BufferUnorderedSync<{}>",
|
||||
std::any::type_name::<M>()
|
||||
);
|
||||
}
|
||||
|
||||
pub struct BufferUnorderedSync<M: Message> {
|
||||
tx: mpsc::Sender<M>,
|
||||
stats: Arc<BufferUnorderedStats>,
|
||||
}
|
||||
|
||||
impl<T, M> ReceiverSubscriberBuilder<M, T> for BufferUnorderedSync<M>
|
||||
impl<M, R, E> SendUntypedReceiver for BufferUnorderedSync<M, R, E>
|
||||
where
|
||||
T: Handler<M> + 'static,
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
type Entry = BufferUnorderedSyncSubscriber<T, M>;
|
||||
type Config = BufferUnorderedConfig;
|
||||
|
||||
fn build(cfg: Self::Config) -> Self::Entry {
|
||||
BufferUnorderedSyncSubscriber {
|
||||
cfg,
|
||||
_m: Default::default(),
|
||||
fn send(&self, msg: Action, _bus: &Bus) -> Result<(), Error<Action>> {
|
||||
match self.tx.send(Request::Action(msg)) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(mpsc::error::SendError(Request::Action(msg))) => Err(Error::send_closed(msg)),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Message> TypedReceiver<M> for BufferUnorderedSync<M> {
|
||||
fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll<()> {
|
||||
match self.tx.poll_ready(ctx) {
|
||||
Poll::Ready(_) => Poll::Ready(()),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
|
||||
fn try_send(&self, m: M) -> Result<(), SendError<M>> {
|
||||
match self.tx.try_send(m) {
|
||||
impl<M, R, E> SendTypedReceiver<M> for BufferUnorderedSync<M, R, E>
|
||||
where
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
fn send(&self, mid: u64, m: M, req: bool, _bus: &Bus) -> Result<(), Error<M>> {
|
||||
match self.tx.send(Request::Request(mid, m, req)) {
|
||||
Ok(_) => {
|
||||
self.stats.buffer.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
Err(mpsc::error::SendError(Request::Request(_, msg, _))) => {
|
||||
Err(Error::send_closed(msg))
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Message> ReceiverTrait for BufferUnorderedSync<M> {
|
||||
fn typed(&self) -> AnyReceiver<'_> {
|
||||
AnyReceiver::new(self)
|
||||
}
|
||||
impl<M, R, E> ReciveTypedReceiver<R, E> for BufferUnorderedSync<M, R, E>
|
||||
where
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
type Stream = Pin<Box<dyn Stream<Item = Event<R, E>> + Send>>;
|
||||
|
||||
fn type_id(&self) -> TypeId {
|
||||
TypeId::of::<BufferUnorderedSync<M>>()
|
||||
}
|
||||
fn event_stream(&self, _: Bus) -> Self::Stream {
|
||||
let mut rx = self.srx.lock().take().unwrap();
|
||||
|
||||
fn stats(&self) -> ReceiverStats {
|
||||
ReceiverStats {
|
||||
name: std::any::type_name::<M>().into(),
|
||||
fields: vec![
|
||||
("buffer".into(), self.stats.buffer.load(Ordering::SeqCst)),
|
||||
(
|
||||
"buffer_total".into(),
|
||||
self.stats.buffer_total.load(Ordering::SeqCst),
|
||||
),
|
||||
(
|
||||
"parallel".into(),
|
||||
self.stats.parallel.load(Ordering::SeqCst),
|
||||
),
|
||||
(
|
||||
"parallel_total".into(),
|
||||
self.stats.parallel_total.load(Ordering::SeqCst),
|
||||
),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
fn close(&self) {
|
||||
self.tx.close();
|
||||
}
|
||||
|
||||
fn sync(&self) {
|
||||
self.tx.flush();
|
||||
}
|
||||
|
||||
fn poll_synchronized(&self, _ctx: &mut Context<'_>) -> Poll<()> {
|
||||
Poll::Ready(())
|
||||
Box::pin(futures::stream::poll_fn(move |cx| rx.poll_recv(cx)))
|
||||
}
|
||||
}
|
||||
|
@ -1,48 +1,64 @@
|
||||
use std::{
|
||||
any::TypeId,
|
||||
marker::PhantomData,
|
||||
pin::Pin,
|
||||
sync::{
|
||||
atomic::{AtomicU64, Ordering},
|
||||
Arc,
|
||||
},
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
use crate::{receiver::ReceiverStats, receivers::mpsc};
|
||||
use futures::{Future, StreamExt};
|
||||
|
||||
use super::{BufferUnorderedBatchedConfig, BufferUnorderedBatchedStats};
|
||||
use crate::{
|
||||
builder::{ReceiverSubscriber, ReceiverSubscriberBuilder},
|
||||
msgs,
|
||||
receiver::{AnyReceiver, ReceiverTrait, SendError, TypedReceiver},
|
||||
buffer_unordered_batch_poller_macro,
|
||||
builder::ReceiverSubscriberBuilder,
|
||||
error::{Error, StdSyncSendError},
|
||||
receiver::{
|
||||
Action, Event, ReciveTypedReceiver, SendTypedReceiver, SendUntypedReceiver,
|
||||
UntypedPollerCallback,
|
||||
},
|
||||
receivers::Request,
|
||||
AsyncBatchHandler, Bus, Message, Untyped,
|
||||
};
|
||||
|
||||
pub struct BufferUnorderedBatchedAsyncSubscriber<T, M>
|
||||
use super::{BufferUnorderedBatchedConfig, BufferUnorderedBatchedStats};
|
||||
use futures::{Future, Stream};
|
||||
use parking_lot::Mutex;
|
||||
use tokio::sync::mpsc::{self, UnboundedSender};
|
||||
|
||||
buffer_unordered_batch_poller_macro!(
|
||||
T,
|
||||
AsyncBatchHandler,
|
||||
|mids: Vec<_>, msgs, bus, ut: Arc<T>, task_permit, stx: UnboundedSender<_>| {
|
||||
tokio::spawn(async move {
|
||||
let resp = ut.handle(msgs, &bus).await;
|
||||
drop(task_permit);
|
||||
|
||||
crate::process_batch_result!(resp, mids, stx);
|
||||
})
|
||||
},
|
||||
|bus, ut: Arc<T>| { async move { ut.sync(&bus).await } }
|
||||
);
|
||||
|
||||
pub struct BufferUnorderedBatchedAsync<M, R, E>
|
||||
where
|
||||
T: AsyncBatchHandler<M> + 'static,
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
cfg: BufferUnorderedBatchedConfig,
|
||||
_m: PhantomData<(T, M)>,
|
||||
tx: mpsc::UnboundedSender<Request<M>>,
|
||||
stats: Arc<BufferUnorderedBatchedStats>,
|
||||
srx: Mutex<Option<mpsc::UnboundedReceiver<Event<R, E>>>>,
|
||||
}
|
||||
|
||||
impl<T, M> ReceiverSubscriber<T> for BufferUnorderedBatchedAsyncSubscriber<T, M>
|
||||
impl<T, M, R> ReceiverSubscriberBuilder<T, M, R, T::Error>
|
||||
for BufferUnorderedBatchedAsync<M, R, T::Error>
|
||||
where
|
||||
T: AsyncBatchHandler<M> + 'static,
|
||||
T: AsyncBatchHandler<M, Response = R> + 'static,
|
||||
T::Error: StdSyncSendError + Clone,
|
||||
R: Message,
|
||||
M: Message,
|
||||
{
|
||||
fn subscribe(
|
||||
self,
|
||||
) -> (
|
||||
Arc<dyn ReceiverTrait>,
|
||||
Box<
|
||||
dyn FnOnce(Untyped) -> Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>,
|
||||
>,
|
||||
) {
|
||||
let cfg = self.cfg;
|
||||
type Config = BufferUnorderedBatchedConfig;
|
||||
|
||||
fn build(cfg: Self::Config) -> (Self, UntypedPollerCallback) {
|
||||
let stats = Arc::new(BufferUnorderedBatchedStats {
|
||||
buffer: AtomicU64::new(0),
|
||||
buffer_total: AtomicU64::new(cfg.buffer_size as _),
|
||||
@ -52,173 +68,81 @@ where
|
||||
batch_size: AtomicU64::new(cfg.batch_size as _),
|
||||
});
|
||||
|
||||
let (tx, rx) = mpsc::channel(cfg.buffer_size);
|
||||
let arc = Arc::new(BufferUnorderedBatchedAsync::<M> {
|
||||
tx,
|
||||
stats: stats.clone(),
|
||||
});
|
||||
let (stx, srx) = mpsc::unbounded_channel();
|
||||
let (tx, rx) = mpsc::unbounded_channel();
|
||||
let stats_clone = stats.clone();
|
||||
|
||||
let poller = Box::new(move |ut| {
|
||||
Box::new(move |bus| {
|
||||
Box::pin(buffer_unordered_poller::<T, M>(rx, bus, ut, stats, cfg))
|
||||
as Pin<Box<dyn Future<Output = ()> + Send>>
|
||||
Box::pin(buffer_unordered_batch_poller::<T, M, R>(
|
||||
rx,
|
||||
bus,
|
||||
ut,
|
||||
stats_clone,
|
||||
cfg,
|
||||
stx,
|
||||
)) as Pin<Box<dyn Future<Output = ()> + Send>>
|
||||
}) as Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>
|
||||
});
|
||||
|
||||
(arc, poller)
|
||||
(
|
||||
BufferUnorderedBatchedAsync::<M, R, T::Error> {
|
||||
tx,
|
||||
stats,
|
||||
srx: Mutex::new(Some(srx)),
|
||||
},
|
||||
poller,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async fn buffer_unordered_poller<T, M>(
|
||||
rx: mpsc::Receiver<M>,
|
||||
bus: Bus,
|
||||
ut: Untyped,
|
||||
stats: Arc<BufferUnorderedBatchedStats>,
|
||||
cfg: BufferUnorderedBatchedConfig,
|
||||
) where
|
||||
T: AsyncBatchHandler<M> + 'static,
|
||||
M: Message,
|
||||
{
|
||||
let ut = ut.downcast::<T>().unwrap();
|
||||
let rx = rx
|
||||
.inspect(|_| {
|
||||
stats.buffer.fetch_sub(1, Ordering::Relaxed);
|
||||
stats.batch.fetch_add(1, Ordering::Relaxed);
|
||||
});
|
||||
|
||||
let rx = if cfg.when_ready {
|
||||
rx.ready_chunks(cfg.batch_size)
|
||||
.left_stream()
|
||||
} else {
|
||||
rx.chunks(cfg.batch_size)
|
||||
.right_stream()
|
||||
};
|
||||
|
||||
let mut rx = rx
|
||||
.map(|msgs| {
|
||||
stats.batch.fetch_sub(msgs.len() as _, Ordering::Relaxed);
|
||||
stats.parallel.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
let bus_clone = bus.clone();
|
||||
let ut = ut.clone();
|
||||
|
||||
tokio::task::spawn(async move { ut.handle(msgs, &bus_clone).await })
|
||||
})
|
||||
.buffer_unordered(cfg.max_parallel);
|
||||
|
||||
while let Some(err) = rx.next().await {
|
||||
stats.parallel.fetch_sub(1, Ordering::Relaxed);
|
||||
|
||||
match err {
|
||||
Ok(Err(err)) => {
|
||||
let _ = bus.send(msgs::Error(Arc::new(err))).await;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
let ut = ut.clone();
|
||||
let bus_clone = bus.clone();
|
||||
let res = tokio::task::spawn(async move { ut.sync(&bus_clone).await }).await;
|
||||
|
||||
match res {
|
||||
Ok(Err(err)) => {
|
||||
let _ = bus.send(msgs::Error(Arc::new(err))).await;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
println!(
|
||||
"[EXIT] BufferUnorderedBatchedAsync<{}>",
|
||||
std::any::type_name::<M>()
|
||||
);
|
||||
}
|
||||
|
||||
pub struct BufferUnorderedBatchedAsync<M: Message> {
|
||||
tx: mpsc::Sender<M>,
|
||||
stats: Arc<BufferUnorderedBatchedStats>,
|
||||
}
|
||||
|
||||
impl<T, M> ReceiverSubscriberBuilder<M, T> for BufferUnorderedBatchedAsync<M>
|
||||
impl<M, R, E> SendUntypedReceiver for BufferUnorderedBatchedAsync<M, R, E>
|
||||
where
|
||||
T: AsyncBatchHandler<M> + 'static,
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
type Entry = BufferUnorderedBatchedAsyncSubscriber<T, M>;
|
||||
type Config = BufferUnorderedBatchedConfig;
|
||||
|
||||
fn build(cfg: Self::Config) -> Self::Entry {
|
||||
BufferUnorderedBatchedAsyncSubscriber {
|
||||
cfg,
|
||||
_m: Default::default(),
|
||||
fn send(&self, m: Action, _bus: &Bus) -> Result<(), Error<Action>> {
|
||||
match self.tx.send(Request::Action(m)) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(mpsc::error::SendError(Request::Action(msg))) => Err(Error::send_closed(msg)),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Message> TypedReceiver<M> for BufferUnorderedBatchedAsync<M> {
|
||||
fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll<()> {
|
||||
match self.tx.poll_ready(ctx) {
|
||||
Poll::Ready(_) => Poll::Ready(()),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
|
||||
fn try_send(&self, m: M) -> Result<(), SendError<M>> {
|
||||
match self.tx.try_send(m) {
|
||||
impl<M, R, E> SendTypedReceiver<M> for BufferUnorderedBatchedAsync<M, R, E>
|
||||
where
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
fn send(&self, mid: u64, m: M, req: bool, _bus: &Bus) -> Result<(), Error<M>> {
|
||||
match self.tx.send(Request::Request(mid, m, req)) {
|
||||
Ok(_) => {
|
||||
self.stats.buffer.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
Err(mpsc::error::SendError(Request::Request(_, msg, _))) => {
|
||||
Err(Error::send_closed(msg))
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Message> ReceiverTrait for BufferUnorderedBatchedAsync<M> {
|
||||
fn typed(&self) -> AnyReceiver<'_> {
|
||||
AnyReceiver::new(self)
|
||||
}
|
||||
impl<M, R, E> ReciveTypedReceiver<R, E> for BufferUnorderedBatchedAsync<M, R, E>
|
||||
where
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
type Stream = Pin<Box<dyn Stream<Item = Event<R, E>> + Send>>;
|
||||
|
||||
fn type_id(&self) -> TypeId {
|
||||
TypeId::of::<BufferUnorderedBatchedAsync<M>>()
|
||||
}
|
||||
fn event_stream(&self, _: Bus) -> Self::Stream {
|
||||
let mut rx = self.srx.lock().take().unwrap();
|
||||
|
||||
fn close(&self) {
|
||||
self.tx.close();
|
||||
}
|
||||
|
||||
fn stats(&self) -> ReceiverStats {
|
||||
ReceiverStats {
|
||||
name: std::any::type_name::<M>().into(),
|
||||
fields: vec![
|
||||
("buffer".into(), self.stats.buffer.load(Ordering::SeqCst)),
|
||||
(
|
||||
"buffer_total".into(),
|
||||
self.stats.buffer_total.load(Ordering::SeqCst),
|
||||
),
|
||||
(
|
||||
"parallel".into(),
|
||||
self.stats.parallel.load(Ordering::SeqCst),
|
||||
),
|
||||
(
|
||||
"parallel_total".into(),
|
||||
self.stats.parallel_total.load(Ordering::SeqCst),
|
||||
),
|
||||
("batch".into(), self.stats.batch.load(Ordering::SeqCst)),
|
||||
(
|
||||
"batch_size".into(),
|
||||
self.stats.batch_size.load(Ordering::SeqCst),
|
||||
),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
fn sync(&self) {
|
||||
self.tx.flush();
|
||||
}
|
||||
|
||||
fn poll_synchronized(&self, _ctx: &mut Context<'_>) -> Poll<()> {
|
||||
Poll::Ready(())
|
||||
Box::pin(futures::stream::poll_fn(move |cx| rx.poll_recv(cx)))
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,9 @@ mod sync;
|
||||
|
||||
use std::sync::atomic::AtomicU64;
|
||||
|
||||
pub use r#async::{BufferUnorderedBatchedAsync, BufferUnorderedBatchedAsyncSubscriber};
|
||||
pub use sync::{BufferUnorderedBatchedSync, BufferUnorderedBatchedSyncSubscriber};
|
||||
pub use r#async::BufferUnorderedBatchedAsync;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
pub use sync::BufferUnorderedBatchedSync;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BufferUnorderedBatchedStats {
|
||||
@ -16,7 +17,7 @@ pub struct BufferUnorderedBatchedStats {
|
||||
pub batch_size: AtomicU64,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct BufferUnorderedBatchedConfig {
|
||||
pub buffer_size: usize,
|
||||
pub max_parallel: usize,
|
||||
@ -34,3 +35,87 @@ impl Default for BufferUnorderedBatchedConfig {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! buffer_unordered_batch_poller_macro {
|
||||
($t: tt, $h: tt, $st1: expr, $st2: expr) => {
|
||||
async fn buffer_unordered_batch_poller<$t, M, R>(
|
||||
mut rx: mpsc::UnboundedReceiver<Request<M>>,
|
||||
bus: Bus,
|
||||
ut: Untyped,
|
||||
_stats: Arc<BufferUnorderedBatchedStats>,
|
||||
cfg: BufferUnorderedBatchedConfig,
|
||||
stx: mpsc::UnboundedSender<Event<R, $t::Error>>,
|
||||
) where
|
||||
$t: $h<M, Response = R> + 'static,
|
||||
M: Message,
|
||||
R: Message,
|
||||
{
|
||||
let ut = ut.downcast::<$t>().unwrap();
|
||||
let semaphore = Arc::new(tokio::sync::Semaphore::new(cfg.max_parallel));
|
||||
|
||||
let mut buffer_mid = Vec::with_capacity(cfg.batch_size);
|
||||
let mut buffer = Vec::with_capacity(cfg.batch_size);
|
||||
|
||||
while let Some(msg) = rx.recv().await {
|
||||
let bus = bus.clone();
|
||||
let ut = ut.clone();
|
||||
let semaphore = semaphore.clone();
|
||||
let stx = stx.clone();
|
||||
|
||||
match msg {
|
||||
Request::Request(mid, msg, req) => {
|
||||
buffer_mid.push((mid, req));
|
||||
buffer.push(msg);
|
||||
|
||||
if buffer_mid.len() >= cfg.batch_size {
|
||||
let task_permit = semaphore.acquire_owned().await;
|
||||
|
||||
let buffer_mid_clone = buffer_mid.drain(..).collect::<Vec<_>>();
|
||||
let buffer_clone = buffer.drain(..).collect();
|
||||
|
||||
#[allow(clippy::redundant_closure_call)]
|
||||
let _ =
|
||||
($st1)(buffer_mid_clone, buffer_clone, bus, ut, task_permit, stx);
|
||||
}
|
||||
}
|
||||
Request::Action(Action::Init(..)) => {
|
||||
stx.send(Event::Ready).unwrap();
|
||||
}
|
||||
Request::Action(Action::Close) => {
|
||||
rx.close();
|
||||
}
|
||||
Request::Action(Action::Flush) => {
|
||||
let stx_clone = stx.clone();
|
||||
|
||||
if !buffer_mid.is_empty() {
|
||||
let buffer_mid_clone = buffer_mid.drain(..).collect::<Vec<_>>();
|
||||
let buffer_clone = buffer.drain(..).collect();
|
||||
let task_permit = semaphore.clone().acquire_owned().await;
|
||||
|
||||
#[allow(clippy::redundant_closure_call)]
|
||||
let _ =
|
||||
($st1)(buffer_mid_clone, buffer_clone, bus, ut, task_permit, stx);
|
||||
}
|
||||
|
||||
let _ = semaphore.acquire_many(cfg.max_parallel as _).await;
|
||||
stx_clone.send(Event::Flushed).unwrap();
|
||||
}
|
||||
|
||||
Request::Action(Action::Sync) => {
|
||||
let lock = semaphore.acquire_many(cfg.max_parallel as _).await;
|
||||
|
||||
#[allow(clippy::redundant_closure_call)]
|
||||
let resp = ($st2)(bus.clone(), ut.clone()).await;
|
||||
drop(lock);
|
||||
|
||||
stx.send(Event::Synchronized(resp.map_err(Error::Other)))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1,48 +1,70 @@
|
||||
use crate::{receiver::ReceiverStats, receivers::mpsc};
|
||||
use futures::{Future, StreamExt};
|
||||
use std::{
|
||||
any::TypeId,
|
||||
marker::PhantomData,
|
||||
pin::Pin,
|
||||
sync::{
|
||||
atomic::{AtomicU64, Ordering},
|
||||
Arc,
|
||||
},
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
use super::{BufferUnorderedBatchedConfig, BufferUnorderedBatchedStats};
|
||||
use crate::{
|
||||
builder::{ReceiverSubscriber, ReceiverSubscriberBuilder},
|
||||
msgs,
|
||||
receiver::{AnyReceiver, ReceiverTrait, SendError, TypedReceiver},
|
||||
Bus, BatchHandler, Message, Untyped,
|
||||
buffer_unordered_batch_poller_macro,
|
||||
builder::ReceiverSubscriberBuilder,
|
||||
error::{Error, StdSyncSendError},
|
||||
receiver::{
|
||||
Action, Event, ReciveTypedReceiver, SendTypedReceiver, SendUntypedReceiver,
|
||||
UntypedPollerCallback,
|
||||
},
|
||||
receivers::Request,
|
||||
BatchHandler, Bus, Message, Untyped,
|
||||
};
|
||||
|
||||
pub struct BufferUnorderedBatchedSyncSubscriber<T, M>
|
||||
use futures::{Future, Stream};
|
||||
use parking_lot::Mutex;
|
||||
use tokio::sync::mpsc::{self, UnboundedSender};
|
||||
|
||||
buffer_unordered_batch_poller_macro!(
|
||||
T,
|
||||
BatchHandler,
|
||||
|mids: Vec<_>, msgs, bus, ut: Arc<T>, task_permit, stx: UnboundedSender<_>| {
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let resp = ut.handle(msgs, &bus);
|
||||
drop(task_permit);
|
||||
|
||||
crate::process_batch_result!(resp, mids, stx);
|
||||
})
|
||||
},
|
||||
|bus, ut: Arc<T>| {
|
||||
async move {
|
||||
tokio::task::spawn_blocking(move || ut.sync(&bus))
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
pub struct BufferUnorderedBatchedSync<M, R, E>
|
||||
where
|
||||
T: BatchHandler<M> + 'static,
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
cfg: BufferUnorderedBatchedConfig,
|
||||
_m: PhantomData<(M, T)>,
|
||||
tx: mpsc::UnboundedSender<Request<M>>,
|
||||
stats: Arc<BufferUnorderedBatchedStats>,
|
||||
srx: Mutex<Option<mpsc::UnboundedReceiver<Event<R, E>>>>,
|
||||
}
|
||||
|
||||
impl<T, M> ReceiverSubscriber<T> for BufferUnorderedBatchedSyncSubscriber<T, M>
|
||||
impl<T, M, R> ReceiverSubscriberBuilder<T, M, R, T::Error>
|
||||
for BufferUnorderedBatchedSync<M, R, T::Error>
|
||||
where
|
||||
T: BatchHandler<M> + 'static,
|
||||
T: BatchHandler<M, Response = R> + 'static,
|
||||
T::Error: StdSyncSendError,
|
||||
R: Message,
|
||||
M: Message,
|
||||
{
|
||||
fn subscribe(
|
||||
self,
|
||||
) -> (
|
||||
Arc<dyn ReceiverTrait>,
|
||||
Box<
|
||||
dyn FnOnce(Untyped) -> Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>,
|
||||
>,
|
||||
) {
|
||||
let cfg = self.cfg;
|
||||
let (tx, rx) = mpsc::channel(cfg.buffer_size);
|
||||
type Config = BufferUnorderedBatchedConfig;
|
||||
|
||||
fn build(cfg: Self::Config) -> (Self, UntypedPollerCallback) {
|
||||
let stats = Arc::new(BufferUnorderedBatchedStats {
|
||||
buffer: AtomicU64::new(0),
|
||||
buffer_total: AtomicU64::new(cfg.buffer_size as _),
|
||||
@ -52,172 +74,81 @@ where
|
||||
batch_size: AtomicU64::new(cfg.batch_size as _),
|
||||
});
|
||||
|
||||
let arc = Arc::new(BufferUnorderedBatchedSync::<M> {
|
||||
tx,
|
||||
stats: stats.clone(),
|
||||
});
|
||||
let (stx, srx) = mpsc::unbounded_channel();
|
||||
let (tx, rx) = mpsc::unbounded_channel();
|
||||
let stats_clone = stats.clone();
|
||||
|
||||
let poller = Box::new(move |ut| {
|
||||
Box::new(move |bus| {
|
||||
Box::pin(buffer_unordered_poller::<T, M>(rx, bus, ut, stats, cfg))
|
||||
as Pin<Box<dyn Future<Output = ()> + Send>>
|
||||
Box::pin(buffer_unordered_batch_poller::<T, M, R>(
|
||||
rx,
|
||||
bus,
|
||||
ut,
|
||||
stats_clone,
|
||||
cfg,
|
||||
stx,
|
||||
)) as Pin<Box<dyn Future<Output = ()> + Send>>
|
||||
}) as Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>
|
||||
});
|
||||
|
||||
(arc, poller)
|
||||
(
|
||||
BufferUnorderedBatchedSync::<M, R, T::Error> {
|
||||
tx,
|
||||
stats,
|
||||
srx: Mutex::new(Some(srx)),
|
||||
},
|
||||
poller,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async fn buffer_unordered_poller<T, M>(
|
||||
rx: mpsc::Receiver<M>,
|
||||
bus: Bus,
|
||||
ut: Untyped,
|
||||
stats: Arc<BufferUnorderedBatchedStats>,
|
||||
cfg: BufferUnorderedBatchedConfig,
|
||||
) where
|
||||
T: BatchHandler<M> + 'static,
|
||||
M: Message,
|
||||
{
|
||||
let ut = ut.downcast::<T>().unwrap();
|
||||
let rx = rx
|
||||
.inspect(|_| {
|
||||
stats.buffer.fetch_sub(1, Ordering::Relaxed);
|
||||
stats.batch.fetch_add(1, Ordering::Relaxed);
|
||||
});
|
||||
|
||||
let rx = if cfg.when_ready {
|
||||
rx.ready_chunks(cfg.batch_size)
|
||||
.left_stream()
|
||||
} else {
|
||||
rx.chunks(cfg.batch_size)
|
||||
.right_stream()
|
||||
};
|
||||
|
||||
let mut rx = rx
|
||||
.map(|msgs| {
|
||||
stats.batch.fetch_sub(msgs.len() as _, Ordering::Relaxed);
|
||||
stats.parallel.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
let bus = bus.clone();
|
||||
let ut = ut.clone();
|
||||
|
||||
tokio::task::spawn_blocking(move || ut.handle(msgs, &bus))
|
||||
})
|
||||
.buffer_unordered(cfg.max_parallel);
|
||||
|
||||
while let Some(err) = rx.next().await {
|
||||
stats.parallel.fetch_sub(1, Ordering::Relaxed);
|
||||
|
||||
match err {
|
||||
Ok(Err(err)) => {
|
||||
let _ = bus.send(msgs::Error(Arc::new(err))).await;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
let ut = ut.clone();
|
||||
let bus_clone = bus.clone();
|
||||
let res = tokio::task::spawn_blocking(move || ut.sync(&bus_clone)).await;
|
||||
|
||||
match res {
|
||||
Ok(Err(err)) => {
|
||||
let _ = bus.send(msgs::Error(Arc::new(err))).await;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
println!(
|
||||
"[EXIT] BufferUnorderedBatchedSync<{}>",
|
||||
std::any::type_name::<M>()
|
||||
);
|
||||
}
|
||||
|
||||
pub struct BufferUnorderedBatchedSync<M: Message> {
|
||||
tx: mpsc::Sender<M>,
|
||||
stats: Arc<BufferUnorderedBatchedStats>,
|
||||
}
|
||||
|
||||
impl<T, M> ReceiverSubscriberBuilder<M, T> for BufferUnorderedBatchedSync<M>
|
||||
impl<M, R, E> SendUntypedReceiver for BufferUnorderedBatchedSync<M, R, E>
|
||||
where
|
||||
T: BatchHandler<M> + 'static,
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
type Entry = BufferUnorderedBatchedSyncSubscriber<T, M>;
|
||||
type Config = BufferUnorderedBatchedConfig;
|
||||
|
||||
fn build(cfg: Self::Config) -> Self::Entry {
|
||||
BufferUnorderedBatchedSyncSubscriber {
|
||||
cfg,
|
||||
_m: Default::default(),
|
||||
fn send(&self, msg: Action, _bus: &Bus) -> Result<(), Error<Action>> {
|
||||
match self.tx.send(Request::Action(msg)) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(mpsc::error::SendError(Request::Action(msg))) => Err(Error::send_closed(msg)),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Message> TypedReceiver<M> for BufferUnorderedBatchedSync<M> {
|
||||
fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll<()> {
|
||||
match self.tx.poll_ready(ctx) {
|
||||
Poll::Ready(_) => Poll::Ready(()),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
|
||||
fn try_send(&self, m: M) -> Result<(), SendError<M>> {
|
||||
match self.tx.try_send(m) {
|
||||
impl<M, R, E> SendTypedReceiver<M> for BufferUnorderedBatchedSync<M, R, E>
|
||||
where
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
fn send(&self, mid: u64, m: M, req: bool, _bus: &Bus) -> Result<(), Error<M>> {
|
||||
match self.tx.send(Request::Request(mid, m, req)) {
|
||||
Ok(_) => {
|
||||
self.stats.buffer.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
Err(mpsc::error::SendError(Request::Request(_, msg, _))) => {
|
||||
Err(Error::send_closed(msg))
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Message> ReceiverTrait for BufferUnorderedBatchedSync<M> {
|
||||
fn typed(&self) -> AnyReceiver<'_> {
|
||||
AnyReceiver::new(self)
|
||||
}
|
||||
impl<M, R, E> ReciveTypedReceiver<R, E> for BufferUnorderedBatchedSync<M, R, E>
|
||||
where
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
type Stream = Pin<Box<dyn Stream<Item = Event<R, E>> + Send>>;
|
||||
|
||||
fn type_id(&self) -> TypeId {
|
||||
TypeId::of::<BufferUnorderedBatchedSync<M>>()
|
||||
}
|
||||
fn event_stream(&self, _: Bus) -> Self::Stream {
|
||||
let mut rx = self.srx.lock().take().unwrap();
|
||||
|
||||
fn stats(&self) -> ReceiverStats {
|
||||
ReceiverStats {
|
||||
name: std::any::type_name::<M>().into(),
|
||||
fields: vec![
|
||||
("buffer".into(), self.stats.buffer.load(Ordering::SeqCst)),
|
||||
(
|
||||
"buffer_total".into(),
|
||||
self.stats.buffer_total.load(Ordering::SeqCst),
|
||||
),
|
||||
(
|
||||
"parallel".into(),
|
||||
self.stats.parallel.load(Ordering::SeqCst),
|
||||
),
|
||||
(
|
||||
"parallel_total".into(),
|
||||
self.stats.parallel_total.load(Ordering::SeqCst),
|
||||
),
|
||||
("batch".into(), self.stats.batch.load(Ordering::SeqCst)),
|
||||
(
|
||||
"batch_size".into(),
|
||||
self.stats.batch_size.load(Ordering::SeqCst),
|
||||
),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
fn close(&self) {
|
||||
self.tx.close();
|
||||
}
|
||||
|
||||
fn sync(&self) {
|
||||
self.tx.flush();
|
||||
}
|
||||
|
||||
fn poll_synchronized(&self, _ctx: &mut Context<'_>) -> Poll<()> {
|
||||
Poll::Ready(())
|
||||
Box::pin(futures::stream::poll_fn(move |cx| rx.poll_recv(cx)))
|
||||
}
|
||||
}
|
||||
|
@ -1,29 +1,56 @@
|
||||
mod buffer_unordered;
|
||||
mod buffer_unordered_batched;
|
||||
mod mpsc_futures;
|
||||
// mod producer;
|
||||
mod synchronize_batched;
|
||||
mod synchronized;
|
||||
|
||||
mod mpsc {
|
||||
pub use super::mpsc_futures::*;
|
||||
}
|
||||
|
||||
pub use buffer_unordered::{
|
||||
BufferUnorderedAsync, BufferUnorderedAsyncSubscriber, BufferUnorderedConfig,
|
||||
BufferUnorderedSync, BufferUnorderedSyncSubscriber,
|
||||
};
|
||||
|
||||
pub use buffer_unordered::{BufferUnorderedAsync, BufferUnorderedConfig, BufferUnorderedSync};
|
||||
pub use buffer_unordered_batched::{
|
||||
BufferUnorderedBatchedAsync, BufferUnorderedBatchedAsyncSubscriber, BufferUnorderedBatchedConfig,
|
||||
BufferUnorderedBatchedSync, BufferUnorderedBatchedSyncSubscriber,
|
||||
};
|
||||
|
||||
pub use synchronized::{
|
||||
SynchronizedAsync, SynchronizedAsyncSubscriber, SynchronizedConfig, SynchronizedSync,
|
||||
SynchronizedSyncSubscriber,
|
||||
BufferUnorderedBatchedAsync, BufferUnorderedBatchedConfig, BufferUnorderedBatchedSync,
|
||||
};
|
||||
pub use synchronized::{SynchronizedAsync, SynchronizedConfig, SynchronizedSync};
|
||||
|
||||
pub use synchronize_batched::{
|
||||
SynchronizeBatchedAsync, SynchronizeBatchedAsyncSubscriber, SynchronizeBatchedConfig,
|
||||
SynchronizeBatchedSync, SynchronizeBatchedSyncSubscriber,
|
||||
SynchronizedBatchedAsync, SynchronizedBatchedConfig, SynchronizedBatchedSync,
|
||||
};
|
||||
|
||||
// pub use producer::{AsyncProducer, AsyncProducerConfig};
|
||||
|
||||
use crate::receiver::Action;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! process_batch_result {
|
||||
($resp: expr, $mids: expr, $stx: expr) => {
|
||||
let mids = $mids;
|
||||
|
||||
match $resp {
|
||||
Ok(re) => {
|
||||
let mut mids = mids.into_iter();
|
||||
let mut re = re.into_iter();
|
||||
|
||||
while let Some((mid, _req)) = mids.next() {
|
||||
if let Some(r) = re.next() {
|
||||
$stx.send(Event::Response(mid, Ok(r))).unwrap();
|
||||
} else {
|
||||
$stx.send(Event::Response(mid, Err(Error::NoResponse)))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(er) => {
|
||||
for (mid, _req) in mids {
|
||||
$stx.send(Event::Response(mid, Err(Error::Other(er.clone()))))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
$stx.send(Event::Error(Error::Other(er))).unwrap();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum Request<M> {
|
||||
Action(Action),
|
||||
Request(u64, M, bool),
|
||||
}
|
||||
|
@ -1,142 +0,0 @@
|
||||
use futures::{Stream, StreamExt};
|
||||
use core::pin::Pin;
|
||||
use crossbeam::queue::ArrayQueue;
|
||||
use crossbeam::atomic::AtomicCell;
|
||||
use core::task::{Waker, Context, Poll};
|
||||
use std::sync::{Arc, atomic::*};
|
||||
|
||||
use crate::receiver::SendError;
|
||||
|
||||
|
||||
|
||||
struct ChannelInner<T> {
|
||||
queue: ArrayQueue<T>,
|
||||
send_waker: AtomicCell<Option<Box<Waker>>>,
|
||||
recv_waker: AtomicCell<Option<Box<Waker>>>,
|
||||
closed: AtomicBool,
|
||||
}
|
||||
|
||||
pub fn channel<T>(buffer: usize) -> (Sender<T>, Receiver<T>) {
|
||||
let inner = Arc::new(ChannelInner {
|
||||
queue: ArrayQueue::new(buffer),
|
||||
send_waker: AtomicCell::new(None),
|
||||
recv_waker: AtomicCell::new(None),
|
||||
closed: AtomicBool::new(false),
|
||||
});
|
||||
|
||||
(
|
||||
Sender {
|
||||
inner: inner.clone(),
|
||||
},
|
||||
Receiver {
|
||||
inner,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Sender<T> {
|
||||
inner: Arc<ChannelInner<T>>
|
||||
}
|
||||
|
||||
impl <T> Sender<T> {
|
||||
pub fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<()> {
|
||||
if self.inner.closed.load(Ordering::SeqCst) {
|
||||
return Poll::Ready(());
|
||||
}
|
||||
|
||||
if self.inner.queue.is_full() {
|
||||
self.inner.send_waker.store(Some(Box::new(cx.waker().clone())));
|
||||
}
|
||||
|
||||
let mut counter = 4;
|
||||
loop {
|
||||
if self.inner.queue.is_full() {
|
||||
if counter > 0 {
|
||||
counter -= 1;
|
||||
continue;
|
||||
} else {
|
||||
break Poll::Pending;
|
||||
}
|
||||
} else {
|
||||
break Poll::Ready(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_send(&self, mut item: T) -> Result<(), SendError<T>> {
|
||||
if self.inner.closed.load(Ordering::SeqCst) {
|
||||
return Err(SendError::Closed(item));
|
||||
}
|
||||
|
||||
let mut counter = 0;
|
||||
loop {
|
||||
match self.inner.queue.push(item) {
|
||||
Ok(_) => {
|
||||
if let Some(waker) = self.inner.recv_waker.take() {
|
||||
waker.wake();
|
||||
}
|
||||
|
||||
break Ok(());
|
||||
}
|
||||
|
||||
Err(inner) => {
|
||||
if counter >= 4 {
|
||||
break Err(SendError::Full(inner));
|
||||
} else {
|
||||
item = inner;
|
||||
counter += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn close(&self) {
|
||||
self.inner.closed.store(true, Ordering::SeqCst);
|
||||
if let Some(waker) = self.inner.recv_waker.take() {
|
||||
waker.wake();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Receiver<T> {
|
||||
inner: Arc<ChannelInner<T>>
|
||||
}
|
||||
|
||||
impl <T> Stream for Receiver<T> {
|
||||
type Item = T;
|
||||
|
||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
let this = self.get_mut();
|
||||
let mut counter = 0;
|
||||
|
||||
loop {
|
||||
match this.inner.queue.pop() {
|
||||
Some(inner) => {
|
||||
if let Some(waker) = this.inner.send_waker.take() {
|
||||
waker.wake();
|
||||
}
|
||||
|
||||
break Poll::Ready(Some(inner));
|
||||
},
|
||||
None => {
|
||||
if this.inner.closed.load(Ordering::SeqCst) {
|
||||
break Poll::Ready(None);
|
||||
} else {
|
||||
if counter == 0 {
|
||||
this.inner.recv_waker.store(Some(Box::new(cx.waker().clone())));
|
||||
}
|
||||
|
||||
if counter >= 8 {
|
||||
break Poll::Pending;
|
||||
} else {
|
||||
counter += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
use crate::receiver::SendError;
|
||||
use core::pin::Pin;
|
||||
use core::task::{Context, Poll};
|
||||
use crossbeam::queue::SegQueue;
|
||||
use futures::{channel::mpsc, Stream};
|
||||
use std::{
|
||||
sync::{
|
||||
atomic::{AtomicUsize, Ordering},
|
||||
Arc,
|
||||
},
|
||||
task::Waker,
|
||||
};
|
||||
|
||||
pub struct State {
|
||||
buffer: usize,
|
||||
counter: AtomicUsize,
|
||||
send_wakers: SegQueue<Waker>,
|
||||
}
|
||||
|
||||
pub fn channel<T>(buffer: usize) -> (Sender<T>, Receiver<T>) {
|
||||
let state = Arc::new(State {
|
||||
buffer,
|
||||
counter: AtomicUsize::new(0),
|
||||
send_wakers: SegQueue::new(),
|
||||
});
|
||||
let (tx, rx) = mpsc::unbounded();
|
||||
|
||||
(
|
||||
Sender {
|
||||
inner: tx,
|
||||
state: state.clone(),
|
||||
},
|
||||
Receiver { inner: rx, state },
|
||||
)
|
||||
}
|
||||
|
||||
pub struct Sender<T> {
|
||||
inner: mpsc::UnboundedSender<T>,
|
||||
state: Arc<State>,
|
||||
}
|
||||
|
||||
impl<T> Sender<T> {
|
||||
pub fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<()> {
|
||||
if self.state.counter.load(Ordering::SeqCst) >= self.state.buffer {
|
||||
self.state.send_wakers.push(cx.waker().clone());
|
||||
return Poll::Pending;
|
||||
}
|
||||
|
||||
Poll::Ready(())
|
||||
}
|
||||
|
||||
pub fn try_send(&self, item: T) -> Result<(), SendError<T>> {
|
||||
if self.state.counter.load(Ordering::Relaxed) >= self.state.buffer {
|
||||
return Err(SendError::Full(item));
|
||||
}
|
||||
|
||||
self.state.counter.fetch_add(1, Ordering::SeqCst);
|
||||
match self.inner.unbounded_send(item) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) if err.is_full() => Err(SendError::Full(err.into_inner())),
|
||||
Err(err) => Err(SendError::Closed(err.into_inner())),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn flush(&self) {}
|
||||
|
||||
#[inline]
|
||||
pub fn close(&self) {
|
||||
self.inner.close_channel();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Receiver<T> {
|
||||
inner: mpsc::UnboundedReceiver<T>,
|
||||
state: Arc<State>,
|
||||
}
|
||||
|
||||
impl<T> Stream for Receiver<T> {
|
||||
type Item = T;
|
||||
|
||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
let this = self.get_mut();
|
||||
match Pin::new(&mut this.inner).poll_next(cx) {
|
||||
Poll::Ready(inner) => {
|
||||
let val = this.state.counter.fetch_sub(1, Ordering::SeqCst);
|
||||
|
||||
if val <= this.state.buffer {
|
||||
if let Some(waker) = this.state.send_wakers.pop() {
|
||||
waker.wake();
|
||||
}
|
||||
}
|
||||
|
||||
Poll::Ready(inner)
|
||||
}
|
||||
Poll::Pending => {
|
||||
while let Some(waker) = this.state.send_wakers.pop() {
|
||||
waker.wake();
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
147
src/receivers/producer/mod.rs
Normal file
147
src/receivers/producer/mod.rs
Normal file
@ -0,0 +1,147 @@
|
||||
use std::pin::Pin;
|
||||
|
||||
use futures::{pin_mut, Future, Stream};
|
||||
use tokio::sync::{mpsc, Mutex};
|
||||
|
||||
use crate::builder::ReceiverSubscriberBuilder;
|
||||
use crate::error::{Error, StdSyncSendError};
|
||||
use crate::handler::AsyncProducer as AsyncProducerHandler;
|
||||
use crate::receiver::UntypedPollerCallback;
|
||||
use crate::receivers::Request;
|
||||
use crate::{
|
||||
Action, Bus, Event, Message, ReciveTypedReceiver, SendTypedReceiver, SendUntypedReceiver,
|
||||
Untyped,
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct AsyncProducerConfig {}
|
||||
|
||||
async fn producer_poller<T, M>(
|
||||
mut rx: mpsc::UnboundedReceiver<Request<M>>,
|
||||
bus: Bus,
|
||||
ut: Untyped,
|
||||
stx: mpsc::UnboundedSender<Event<T::Response, T::Error>>,
|
||||
) where
|
||||
T: AsyncProducerHandler<M> + 'static,
|
||||
T::Error: StdSyncSendError,
|
||||
T::Item: Message,
|
||||
T::Response: Message,
|
||||
M: Message,
|
||||
{
|
||||
let ut = ut.downcast::<Mutex<T>>().unwrap();
|
||||
let stream = Option<Pin<Box<dyn Stream<Item = Result<Self::Item, Self::Error>> + Send + '_>>, Self::Error>;
|
||||
|
||||
while let Some(msg) = rx.recv().await {
|
||||
match msg {
|
||||
Request::Request(mid, msg, _req) => {
|
||||
let lock = ut.lock().await;
|
||||
let stream = lock.producer(msg, &bus).await.unwrap();
|
||||
pin_mut!(stream);
|
||||
|
||||
stx.send(Event::BatchComplete(M::type_tag_(), 1)).unwrap();
|
||||
}
|
||||
Request::Action(Action::Init(..)) => {
|
||||
stx.send(Event::Ready).unwrap();
|
||||
}
|
||||
Request::Action(Action::Close) => {
|
||||
rx.close();
|
||||
}
|
||||
Request::Action(Action::Flush) => {
|
||||
stx.send(Event::Flushed).unwrap();
|
||||
}
|
||||
Request::Action(Action::Sync) => {}
|
||||
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AsyncProducer<M, R, E>
|
||||
where
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
tx: mpsc::UnboundedSender<Request<M>>,
|
||||
srx: parking_lot::Mutex<Option<mpsc::UnboundedReceiver<Event<R, E>>>>,
|
||||
}
|
||||
|
||||
impl<T, M> ReceiverSubscriberBuilder<T, M, T::Response, T::Error>
|
||||
for AsyncProducer<M, T::Response, T::Error>
|
||||
where
|
||||
T: AsyncProducerHandler<M> + 'static,
|
||||
T::Item: Message,
|
||||
T::Response: Message,
|
||||
T::Error: StdSyncSendError,
|
||||
M: Message,
|
||||
{
|
||||
type Config = AsyncProducerConfig;
|
||||
|
||||
fn build(_cfg: Self::Config) -> (Self, UntypedPollerCallback) {
|
||||
let (stx, srx) = mpsc::unbounded_channel();
|
||||
let (tx, rx) = mpsc::unbounded_channel();
|
||||
|
||||
let poller = Box::new(move |ut| {
|
||||
Box::new(move |bus| {
|
||||
Box::pin(producer_poller::<T, M>(rx, bus, ut, stx))
|
||||
as Pin<Box<dyn Future<Output = ()> + Send>>
|
||||
}) as Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>
|
||||
});
|
||||
|
||||
(
|
||||
AsyncProducer::<M, T::Response, T::Error> {
|
||||
tx,
|
||||
srx: parking_lot::Mutex::new(Some(srx)),
|
||||
},
|
||||
poller,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<M, R, E> SendUntypedReceiver for AsyncProducer<M, R, E>
|
||||
where
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
fn send(&self, m: Action, _bus: &Bus) -> Result<(), Error<Action>> {
|
||||
match self.tx.send(Request::Action(m)) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(mpsc::error::SendError(Request::Action(msg))) => Err(Error::send_closed(msg)),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M, R, E> SendTypedReceiver<M> for AsyncProducer<M, R, E>
|
||||
where
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
fn send(&self, mid: u64, m: M, req: bool, _bus: &Bus) -> Result<(), Error<M>> {
|
||||
match self.tx.send(Request::Request(mid, m, req)) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(mpsc::error::SendError(Request::Request(_, msg, _))) => {
|
||||
Err(Error::send_closed(msg))
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M, R, E> ReciveTypedReceiver<R, E> for AsyncProducer<M, R, E>
|
||||
where
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
type Stream = Pin<Box<dyn Stream<Item = Event<R, E>> + Send>>;
|
||||
|
||||
fn event_stream(&self, _: Bus) -> Self::Stream {
|
||||
let mut rx = self.srx.lock().take().unwrap();
|
||||
|
||||
Box::pin(futures::stream::poll_fn(move |cx| rx.poll_recv(cx)))
|
||||
}
|
||||
}
|
@ -1,211 +1,121 @@
|
||||
use std::{
|
||||
any::TypeId,
|
||||
marker::PhantomData,
|
||||
pin::Pin,
|
||||
sync::{
|
||||
atomic::{AtomicU64, Ordering},
|
||||
Arc,
|
||||
},
|
||||
task::{Context, Poll},
|
||||
};
|
||||
use std::{pin::Pin, sync::Arc};
|
||||
|
||||
use crate::{receiver::ReceiverStats, receivers::mpsc};
|
||||
use futures::{Future, StreamExt};
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use super::{SynchronizeBatchedConfig, SynchronizeBatchedStats};
|
||||
use super::SynchronizedBatchedConfig;
|
||||
use crate::{
|
||||
builder::{ReceiverSubscriber, ReceiverSubscriberBuilder},
|
||||
msgs,
|
||||
receiver::{AnyReceiver, ReceiverTrait, SendError, TypedReceiver},
|
||||
batch_synchronized_poller_macro,
|
||||
builder::ReceiverSubscriberBuilder,
|
||||
error::{Error, StdSyncSendError},
|
||||
receiver::{
|
||||
Action, Event, ReciveTypedReceiver, SendTypedReceiver, SendUntypedReceiver,
|
||||
UntypedPollerCallback,
|
||||
},
|
||||
receivers::Request,
|
||||
AsyncBatchSynchronizedHandler, Bus, Message, Untyped,
|
||||
};
|
||||
|
||||
pub struct SynchronizeBatchedAsyncSubscriber<T, M>
|
||||
where
|
||||
T: AsyncBatchSynchronizedHandler<M> + 'static,
|
||||
M: Message,
|
||||
{
|
||||
cfg: SynchronizeBatchedConfig,
|
||||
_m: PhantomData<(T, M)>,
|
||||
use futures::{Future, Stream};
|
||||
use tokio::sync::{
|
||||
mpsc::{self, UnboundedSender},
|
||||
Mutex,
|
||||
};
|
||||
|
||||
batch_synchronized_poller_macro! {
|
||||
T,
|
||||
AsyncBatchSynchronizedHandler,
|
||||
|mids: Vec<_>, msgs, bus, ut: Arc<Mutex<T>>, stx: UnboundedSender<_>| {
|
||||
tokio::spawn(async move {
|
||||
let resp = ut.lock().await.handle(msgs, &bus).await;
|
||||
|
||||
crate::process_batch_result!(resp, mids, stx);
|
||||
})
|
||||
},
|
||||
|bus, ut: Arc<Mutex<T>>| { async move { ut.lock().await.sync(&bus).await } }
|
||||
}
|
||||
|
||||
impl<T, M> ReceiverSubscriber<T> for SynchronizeBatchedAsyncSubscriber<T, M>
|
||||
pub struct SynchronizedBatchedAsync<M, R, E>
|
||||
where
|
||||
T: AsyncBatchSynchronizedHandler<M> + 'static,
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
tx: mpsc::UnboundedSender<Request<M>>,
|
||||
srx: parking_lot::Mutex<Option<mpsc::UnboundedReceiver<Event<R, E>>>>,
|
||||
}
|
||||
|
||||
impl<T, M, R> ReceiverSubscriberBuilder<T, M, R, T::Error>
|
||||
for SynchronizedBatchedAsync<M, R, T::Error>
|
||||
where
|
||||
T: AsyncBatchSynchronizedHandler<M, Response = R> + 'static,
|
||||
T::Error: StdSyncSendError + Clone,
|
||||
R: Message,
|
||||
M: Message,
|
||||
{
|
||||
fn subscribe(
|
||||
self,
|
||||
) -> (
|
||||
Arc<dyn ReceiverTrait>,
|
||||
Box<
|
||||
dyn FnOnce(Untyped) -> Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>,
|
||||
>,
|
||||
) {
|
||||
let cfg = self.cfg;
|
||||
let (tx, rx) = mpsc::channel(cfg.buffer_size);
|
||||
let stats = Arc::new(SynchronizeBatchedStats {
|
||||
buffer: AtomicU64::new(0),
|
||||
buffer_total: AtomicU64::new(cfg.buffer_size as _),
|
||||
batch: AtomicU64::new(0),
|
||||
batch_size: AtomicU64::new(cfg.batch_size as _),
|
||||
});
|
||||
type Config = SynchronizedBatchedConfig;
|
||||
|
||||
let arc = Arc::new(SynchronizeBatchedAsync::<M> {
|
||||
tx,
|
||||
stats: stats.clone(),
|
||||
});
|
||||
fn build(cfg: Self::Config) -> (Self, UntypedPollerCallback) {
|
||||
let (stx, srx) = mpsc::unbounded_channel();
|
||||
let (tx, rx) = mpsc::unbounded_channel();
|
||||
|
||||
let poller = Box::new(move |ut| {
|
||||
Box::new(move |bus| {
|
||||
Box::pin(buffer_unordered_poller::<T, M>(rx, bus, ut, stats, cfg))
|
||||
Box::pin(batch_synchronized_poller::<T, M, R>(rx, bus, ut, cfg, stx))
|
||||
as Pin<Box<dyn Future<Output = ()> + Send>>
|
||||
}) as Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>
|
||||
});
|
||||
|
||||
(arc, poller)
|
||||
(
|
||||
SynchronizedBatchedAsync::<M, R, T::Error> {
|
||||
tx,
|
||||
srx: parking_lot::Mutex::new(Some(srx)),
|
||||
},
|
||||
poller,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async fn buffer_unordered_poller<T, M>(
|
||||
rx: mpsc::Receiver<M>,
|
||||
bus: Bus,
|
||||
ut: Untyped,
|
||||
stats: Arc<SynchronizeBatchedStats>,
|
||||
cfg: SynchronizeBatchedConfig,
|
||||
) where
|
||||
T: AsyncBatchSynchronizedHandler<M> + 'static,
|
||||
M: Message,
|
||||
{
|
||||
let ut = ut.downcast::<Mutex<T>>().unwrap();
|
||||
|
||||
let rx = rx
|
||||
.inspect(|_|{
|
||||
stats.buffer.fetch_sub(1, Ordering::Relaxed);
|
||||
stats.batch.fetch_add(1, Ordering::Relaxed);
|
||||
});
|
||||
|
||||
let mut rx = if cfg.when_ready {
|
||||
rx.ready_chunks(cfg.batch_size)
|
||||
.left_stream()
|
||||
} else {
|
||||
rx.chunks(cfg.batch_size)
|
||||
.right_stream()
|
||||
};
|
||||
|
||||
while let Some(msgs) = rx.next().await {
|
||||
stats.batch.fetch_sub(msgs.len() as _, Ordering::Relaxed);
|
||||
|
||||
let bus_clone = bus.clone();
|
||||
let ut = ut.clone();
|
||||
|
||||
let res =
|
||||
tokio::task::spawn(async move { ut.lock().await.handle(msgs, &bus_clone).await })
|
||||
.await;
|
||||
|
||||
match res {
|
||||
Ok(Err(err)) => {
|
||||
let _ = bus.send(msgs::Error(Arc::new(err))).await;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
let ut = ut.clone();
|
||||
let bus_clone = bus.clone();
|
||||
let res = tokio::task::spawn(async move { ut.lock().await.sync(&bus_clone).await }).await;
|
||||
|
||||
match res {
|
||||
Ok(Err(err)) => {
|
||||
let _ = bus.send(msgs::Error(Arc::new(err))).await;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
println!(
|
||||
"[EXIT] SynchronizeBatchedAsync<{}>",
|
||||
std::any::type_name::<M>()
|
||||
);
|
||||
}
|
||||
|
||||
pub struct SynchronizeBatchedAsync<M: Message> {
|
||||
tx: mpsc::Sender<M>,
|
||||
stats: Arc<SynchronizeBatchedStats>,
|
||||
}
|
||||
|
||||
impl<T, M> ReceiverSubscriberBuilder<M, T> for SynchronizeBatchedAsync<M>
|
||||
impl<M, R, E> SendUntypedReceiver for SynchronizedBatchedAsync<M, R, E>
|
||||
where
|
||||
T: AsyncBatchSynchronizedHandler<M> + 'static,
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
type Entry = SynchronizeBatchedAsyncSubscriber<T, M>;
|
||||
type Config = SynchronizeBatchedConfig;
|
||||
|
||||
fn build(cfg: Self::Config) -> Self::Entry {
|
||||
SynchronizeBatchedAsyncSubscriber {
|
||||
cfg,
|
||||
_m: Default::default(),
|
||||
fn send(&self, m: Action, _bus: &Bus) -> Result<(), Error<Action>> {
|
||||
match self.tx.send(Request::Action(m)) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(mpsc::error::SendError(Request::Action(msg))) => Err(Error::send_closed(msg)),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Message> TypedReceiver<M> for SynchronizeBatchedAsync<M> {
|
||||
fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll<()> {
|
||||
match self.tx.poll_ready(ctx) {
|
||||
Poll::Ready(_) => Poll::Ready(()),
|
||||
Poll::Pending => Poll::Pending,
|
||||
impl<M, R, E> SendTypedReceiver<M> for SynchronizedBatchedAsync<M, R, E>
|
||||
where
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
fn send(&self, mid: u64, m: M, req: bool, _bus: &Bus) -> Result<(), Error<M>> {
|
||||
match self.tx.send(Request::Request(mid, m, req)) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(mpsc::error::SendError(Request::Request(_, msg, _))) => {
|
||||
Err(Error::send_closed(msg))
|
||||
}
|
||||
}
|
||||
|
||||
fn try_send(&self, m: M) -> Result<(), SendError<M>> {
|
||||
match self.tx.try_send(m) {
|
||||
Ok(_) => {
|
||||
self.stats.buffer.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Message> ReceiverTrait for SynchronizeBatchedAsync<M> {
|
||||
fn typed(&self) -> AnyReceiver<'_> {
|
||||
AnyReceiver::new(self)
|
||||
}
|
||||
impl<M, R, E> ReciveTypedReceiver<R, E> for SynchronizedBatchedAsync<M, R, E>
|
||||
where
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
type Stream = Pin<Box<dyn Stream<Item = Event<R, E>> + Send>>;
|
||||
|
||||
fn type_id(&self) -> TypeId {
|
||||
TypeId::of::<Self>()
|
||||
}
|
||||
fn event_stream(&self, _: Bus) -> Self::Stream {
|
||||
let mut rx = self.srx.lock().take().unwrap();
|
||||
|
||||
fn close(&self) {
|
||||
self.tx.close();
|
||||
}
|
||||
|
||||
fn stats(&self) -> ReceiverStats {
|
||||
ReceiverStats {
|
||||
name: std::any::type_name::<M>().into(),
|
||||
fields: vec![
|
||||
("buffer".into(), self.stats.buffer.load(Ordering::SeqCst)),
|
||||
(
|
||||
"buffer_total".into(),
|
||||
self.stats.buffer_total.load(Ordering::SeqCst),
|
||||
),
|
||||
("batch".into(), self.stats.batch.load(Ordering::SeqCst)),
|
||||
(
|
||||
"batch_size".into(),
|
||||
self.stats.batch_size.load(Ordering::SeqCst),
|
||||
),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
fn sync(&self) {
|
||||
self.tx.flush();
|
||||
}
|
||||
|
||||
fn poll_synchronized(&self, _ctx: &mut Context<'_>) -> Poll<()> {
|
||||
Poll::Ready(())
|
||||
Box::pin(futures::stream::poll_fn(move |cx| rx.poll_recv(cx)))
|
||||
}
|
||||
}
|
||||
|
@ -3,31 +3,104 @@ mod sync;
|
||||
|
||||
use std::sync::atomic::AtomicU64;
|
||||
|
||||
pub use sync::{SynchronizeBatchedSync, SynchronizeBatchedSyncSubscriber};
|
||||
|
||||
pub use r#async::{SynchronizeBatchedAsync, SynchronizeBatchedAsyncSubscriber};
|
||||
pub use r#async::SynchronizedBatchedAsync;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
pub use sync::SynchronizedBatchedSync;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SynchronizeBatchedStats {
|
||||
pub struct SynchronizedBatchedStats {
|
||||
pub buffer: AtomicU64,
|
||||
pub buffer_total: AtomicU64,
|
||||
pub batch: AtomicU64,
|
||||
pub batch_size: AtomicU64,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct SynchronizeBatchedConfig {
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct SynchronizedBatchedConfig {
|
||||
pub buffer_size: usize,
|
||||
pub batch_size: usize,
|
||||
pub when_ready: bool,
|
||||
}
|
||||
|
||||
impl Default for SynchronizeBatchedConfig {
|
||||
impl Default for SynchronizedBatchedConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
buffer_size: 4,
|
||||
batch_size: 16,
|
||||
batch_size: 8,
|
||||
when_ready: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! batch_synchronized_poller_macro {
|
||||
($t: tt, $h: tt, $st1: expr, $st2: expr) => {
|
||||
async fn batch_synchronized_poller<$t, M, R>(
|
||||
mut rx: mpsc::UnboundedReceiver<Request<M>>,
|
||||
bus: Bus,
|
||||
ut: Untyped,
|
||||
// stats: Arc<SynchronizedBatchedStats>,
|
||||
cfg: SynchronizedBatchedConfig,
|
||||
stx: mpsc::UnboundedSender<Event<R, $t::Error>>,
|
||||
) where
|
||||
$t: $h<M, Response = R> + 'static,
|
||||
$t::Error: StdSyncSendError + Clone,
|
||||
M: Message,
|
||||
R: Message,
|
||||
{
|
||||
let ut = ut.downcast::<Mutex<T>>().unwrap();
|
||||
|
||||
let mut buffer_mid = Vec::with_capacity(cfg.batch_size);
|
||||
let mut buffer = Vec::with_capacity(cfg.batch_size);
|
||||
|
||||
while let Some(msg) = rx.recv().await {
|
||||
let bus = bus.clone();
|
||||
let ut = ut.clone();
|
||||
let stx = stx.clone();
|
||||
|
||||
match msg {
|
||||
Request::Request(mid, msg, req) => {
|
||||
buffer_mid.push((mid, req));
|
||||
buffer.push(msg);
|
||||
|
||||
if buffer_mid.len() >= cfg.batch_size {
|
||||
let buffer_mid_clone = buffer_mid.drain(..).collect::<Vec<_>>();
|
||||
let buffer_clone = buffer.drain(..).collect();
|
||||
|
||||
#[allow(clippy::redundant_closure_call)]
|
||||
let _ = ($st1)(buffer_mid_clone, buffer_clone, bus, ut, stx);
|
||||
}
|
||||
}
|
||||
Request::Action(Action::Init(..)) => {
|
||||
stx.send(Event::Ready).unwrap();
|
||||
}
|
||||
Request::Action(Action::Close) => {
|
||||
rx.close();
|
||||
}
|
||||
Request::Action(Action::Flush) => {
|
||||
let stx_clone = stx.clone();
|
||||
|
||||
if !buffer_mid.is_empty() {
|
||||
let buffer_mid_clone = buffer_mid.drain(..).collect::<Vec<_>>();
|
||||
let buffer_clone = buffer.drain(..).collect();
|
||||
|
||||
#[allow(clippy::redundant_closure_call)]
|
||||
let _ = ($st1)(buffer_mid_clone, buffer_clone, bus, ut, stx);
|
||||
}
|
||||
|
||||
stx_clone.send(Event::Flushed).unwrap();
|
||||
}
|
||||
|
||||
Request::Action(Action::Sync) => {
|
||||
#[allow(clippy::redundant_closure_call)]
|
||||
let resp = ($st2)(bus.clone(), ut.clone()).await;
|
||||
stx.send(Event::Synchronized(resp.map_err(Error::Other)))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1,213 +1,125 @@
|
||||
use super::{SynchronizeBatchedConfig, SynchronizeBatchedStats};
|
||||
use std::{pin::Pin, sync::Arc};
|
||||
|
||||
use crate::{
|
||||
builder::{ReceiverSubscriber, ReceiverSubscriberBuilder},
|
||||
msgs,
|
||||
receiver::{AnyReceiver, ReceiverTrait, SendError, TypedReceiver},
|
||||
batch_synchronized_poller_macro,
|
||||
builder::ReceiverSubscriberBuilder,
|
||||
error::{Error, StdSyncSendError},
|
||||
receiver::{
|
||||
Action, Event, ReciveTypedReceiver, SendTypedReceiver, SendUntypedReceiver,
|
||||
UntypedPollerCallback,
|
||||
},
|
||||
receivers::Request,
|
||||
BatchSynchronizedHandler, Bus, Message, Untyped,
|
||||
};
|
||||
use crate::{receiver::ReceiverStats, receivers::mpsc};
|
||||
use futures::{Future, StreamExt};
|
||||
use std::{
|
||||
any::TypeId,
|
||||
marker::PhantomData,
|
||||
pin::Pin,
|
||||
sync::{
|
||||
atomic::{AtomicU64, Ordering},
|
||||
Arc,
|
||||
},
|
||||
task::{Context, Poll},
|
||||
};
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
pub struct SynchronizeBatchedSyncSubscriber<T, M>
|
||||
where
|
||||
T: BatchSynchronizedHandler<M> + 'static,
|
||||
M: Message,
|
||||
{
|
||||
cfg: SynchronizeBatchedConfig,
|
||||
_m: PhantomData<(M, T)>,
|
||||
use super::SynchronizedBatchedConfig;
|
||||
use futures::{executor::block_on, Future, Stream};
|
||||
use tokio::sync::{
|
||||
mpsc::{self, UnboundedSender},
|
||||
Mutex,
|
||||
};
|
||||
|
||||
batch_synchronized_poller_macro! {
|
||||
T,
|
||||
BatchSynchronizedHandler,
|
||||
|mids: Vec<_>, msgs, bus, ut: Arc<Mutex<T>>, stx: UnboundedSender<_>| {
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let resp = block_on(ut.lock()).handle(msgs, &bus);
|
||||
|
||||
crate::process_batch_result!(resp, mids, stx);
|
||||
})
|
||||
},
|
||||
|bus, ut: Arc<Mutex<T>>| async move {
|
||||
tokio::task::spawn_blocking(move || block_on(ut.lock()).sync(&bus))
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, M> ReceiverSubscriber<T> for SynchronizeBatchedSyncSubscriber<T, M>
|
||||
pub struct SynchronizedBatchedSync<M, R, E>
|
||||
where
|
||||
T: BatchSynchronizedHandler<M> + 'static,
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
tx: mpsc::UnboundedSender<Request<M>>,
|
||||
srx: parking_lot::Mutex<Option<mpsc::UnboundedReceiver<Event<R, E>>>>,
|
||||
}
|
||||
|
||||
impl<T, M, R> ReceiverSubscriberBuilder<T, M, R, T::Error>
|
||||
for SynchronizedBatchedSync<M, R, T::Error>
|
||||
where
|
||||
T: BatchSynchronizedHandler<M, Response = R> + 'static,
|
||||
T::Error: StdSyncSendError,
|
||||
R: Message,
|
||||
M: Message,
|
||||
{
|
||||
fn subscribe(
|
||||
self,
|
||||
) -> (
|
||||
Arc<dyn ReceiverTrait>,
|
||||
Box<
|
||||
dyn FnOnce(Untyped) -> Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>,
|
||||
>,
|
||||
) {
|
||||
let cfg = self.cfg;
|
||||
let (tx, rx) = mpsc::channel(cfg.buffer_size);
|
||||
let stats = Arc::new(SynchronizeBatchedStats {
|
||||
buffer: AtomicU64::new(0),
|
||||
buffer_total: AtomicU64::new(cfg.buffer_size as _),
|
||||
batch: AtomicU64::new(0),
|
||||
batch_size: AtomicU64::new(cfg.batch_size as _),
|
||||
});
|
||||
type Config = SynchronizedBatchedConfig;
|
||||
|
||||
fn build(cfg: Self::Config) -> (Self, UntypedPollerCallback) {
|
||||
let (stx, srx) = mpsc::unbounded_channel();
|
||||
let (tx, rx) = mpsc::unbounded_channel();
|
||||
|
||||
let arc = Arc::new(SynchronizeBatchedSync::<M> {
|
||||
tx,
|
||||
stats: stats.clone(),
|
||||
});
|
||||
let poller = Box::new(move |ut| {
|
||||
Box::new(move |bus| {
|
||||
Box::pin(buffer_unordered_poller::<T, M>(rx, bus, ut, stats, cfg))
|
||||
Box::pin(batch_synchronized_poller::<T, M, R>(rx, bus, ut, cfg, stx))
|
||||
as Pin<Box<dyn Future<Output = ()> + Send>>
|
||||
}) as Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>
|
||||
});
|
||||
|
||||
(arc, poller)
|
||||
(
|
||||
SynchronizedBatchedSync::<M, R, T::Error> {
|
||||
tx,
|
||||
srx: parking_lot::Mutex::new(Some(srx)),
|
||||
},
|
||||
poller,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async fn buffer_unordered_poller<T, M>(
|
||||
rx: mpsc::Receiver<M>,
|
||||
bus: Bus,
|
||||
ut: Untyped,
|
||||
stats: Arc<SynchronizeBatchedStats>,
|
||||
cfg: SynchronizeBatchedConfig,
|
||||
) where
|
||||
T: BatchSynchronizedHandler<M> + 'static,
|
||||
M: Message,
|
||||
{
|
||||
let ut = ut.downcast::<Mutex<T>>().unwrap();
|
||||
|
||||
let rx = rx
|
||||
.inspect(|_|{
|
||||
stats.buffer.fetch_sub(1, Ordering::Relaxed);
|
||||
stats.batch.fetch_add(1, Ordering::Relaxed);
|
||||
});
|
||||
|
||||
let mut rx = if cfg.when_ready {
|
||||
rx.ready_chunks(cfg.batch_size)
|
||||
.left_stream()
|
||||
} else {
|
||||
rx.chunks(cfg.batch_size)
|
||||
.right_stream()
|
||||
};
|
||||
|
||||
while let Some(msgs) = rx.next().await {
|
||||
stats.batch.fetch_sub(msgs.len() as _, Ordering::Relaxed);
|
||||
|
||||
let bus_clone = bus.clone();
|
||||
let ut = ut.clone();
|
||||
|
||||
let res = tokio::task::spawn_blocking(move || {
|
||||
let mut uut = futures::executor::block_on(ut.lock());
|
||||
|
||||
uut.handle(msgs, &bus_clone)
|
||||
}).await;
|
||||
|
||||
match res {
|
||||
Ok(Err(err)) => {
|
||||
let _ = bus.send(msgs::Error(Arc::new(err))).await;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
let ut = ut.clone();
|
||||
let bus_clone = bus.clone();
|
||||
let res = tokio::task::spawn_blocking(move || {
|
||||
futures::executor::block_on(ut.lock()).sync(&bus_clone)
|
||||
})
|
||||
.await;
|
||||
|
||||
match res {
|
||||
Ok(Err(err)) => {
|
||||
let _ = bus.send(msgs::Error(Arc::new(err))).await;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
println!(
|
||||
"[EXIT] SynchronizeBatchedSync<{}>",
|
||||
std::any::type_name::<M>()
|
||||
);
|
||||
}
|
||||
|
||||
pub struct SynchronizeBatchedSync<M: Message> {
|
||||
tx: mpsc::Sender<M>,
|
||||
stats: Arc<SynchronizeBatchedStats>,
|
||||
}
|
||||
|
||||
impl<T, M> ReceiverSubscriberBuilder<M, T> for SynchronizeBatchedSync<M>
|
||||
impl<M, R, E> SendUntypedReceiver for SynchronizedBatchedSync<M, R, E>
|
||||
where
|
||||
T: BatchSynchronizedHandler<M> + 'static,
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
type Entry = SynchronizeBatchedSyncSubscriber<T, M>;
|
||||
type Config = SynchronizeBatchedConfig;
|
||||
|
||||
fn build(cfg: Self::Config) -> Self::Entry {
|
||||
SynchronizeBatchedSyncSubscriber {
|
||||
cfg,
|
||||
_m: Default::default(),
|
||||
fn send(&self, msg: Action, _bus: &Bus) -> Result<(), Error<Action>> {
|
||||
match self.tx.send(Request::Action(msg)) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(mpsc::error::SendError(Request::Action(msg))) => Err(Error::send_closed(msg)),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Message> TypedReceiver<M> for SynchronizeBatchedSync<M> {
|
||||
fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll<()> {
|
||||
match self.tx.poll_ready(ctx) {
|
||||
Poll::Ready(_) => Poll::Ready(()),
|
||||
Poll::Pending => Poll::Pending,
|
||||
impl<M, R, E> SendTypedReceiver<M> for SynchronizedBatchedSync<M, R, E>
|
||||
where
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
fn send(&self, mid: u64, m: M, req: bool, _bus: &Bus) -> Result<(), Error<M>> {
|
||||
match self.tx.send(Request::Request(mid, m, req)) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(mpsc::error::SendError(Request::Request(_, msg, _))) => {
|
||||
Err(Error::send_closed(msg))
|
||||
}
|
||||
}
|
||||
|
||||
fn try_send(&self, m: M) -> Result<(), SendError<M>> {
|
||||
match self.tx.try_send(m) {
|
||||
Ok(_) => {
|
||||
self.stats.buffer.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Message> ReceiverTrait for SynchronizeBatchedSync<M> {
|
||||
fn typed(&self) -> AnyReceiver<'_> {
|
||||
AnyReceiver::new(self)
|
||||
}
|
||||
impl<M, R, E> ReciveTypedReceiver<R, E> for SynchronizedBatchedSync<M, R, E>
|
||||
where
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
type Stream = Pin<Box<dyn Stream<Item = Event<R, E>> + Send>>;
|
||||
|
||||
fn type_id(&self) -> TypeId {
|
||||
TypeId::of::<Self>()
|
||||
}
|
||||
fn event_stream(&self, _: Bus) -> Self::Stream {
|
||||
let mut rx = self.srx.lock().take().unwrap();
|
||||
|
||||
fn stats(&self) -> ReceiverStats {
|
||||
ReceiverStats {
|
||||
name: std::any::type_name::<M>().into(),
|
||||
fields: vec![
|
||||
("buffer".into(), self.stats.buffer.load(Ordering::SeqCst)),
|
||||
(
|
||||
"buffer_total".into(),
|
||||
self.stats.buffer_total.load(Ordering::SeqCst),
|
||||
),
|
||||
("batch".into(), self.stats.batch.load(Ordering::SeqCst)),
|
||||
(
|
||||
"batch_size".into(),
|
||||
self.stats.batch_size.load(Ordering::SeqCst),
|
||||
),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
fn close(&self) {
|
||||
self.tx.close();
|
||||
}
|
||||
|
||||
fn sync(&self) {
|
||||
self.tx.flush();
|
||||
}
|
||||
|
||||
fn poll_synchronized(&self, _ctx: &mut Context<'_>) -> Poll<()> {
|
||||
Poll::Ready(())
|
||||
Box::pin(futures::stream::poll_fn(move |cx| rx.poll_recv(cx)))
|
||||
}
|
||||
}
|
||||
|
@ -1,186 +1,121 @@
|
||||
use std::{
|
||||
any::TypeId,
|
||||
marker::PhantomData,
|
||||
pin::Pin,
|
||||
sync::{
|
||||
atomic::{AtomicU64, Ordering},
|
||||
Arc,
|
||||
},
|
||||
task::{Context, Poll},
|
||||
};
|
||||
use std::{pin::Pin, sync::Arc};
|
||||
|
||||
use crate::{receiver::ReceiverStats, receivers::mpsc};
|
||||
use futures::{Future, StreamExt};
|
||||
use tokio::sync::Mutex;
|
||||
use crate::{receiver::UntypedPollerCallback, synchronized_poller_macro};
|
||||
use futures::{Future, Stream};
|
||||
|
||||
use super::{SynchronizedConfig, SynchronizedStats};
|
||||
use super::SynchronizedConfig;
|
||||
use crate::{
|
||||
builder::{ReceiverSubscriber, ReceiverSubscriberBuilder},
|
||||
msgs,
|
||||
receiver::{AnyReceiver, ReceiverTrait, SendError, TypedReceiver},
|
||||
builder::ReceiverSubscriberBuilder,
|
||||
error::{Error, StdSyncSendError},
|
||||
receiver::{Action, Event, ReciveTypedReceiver, SendTypedReceiver, SendUntypedReceiver},
|
||||
receivers::Request,
|
||||
AsyncSynchronizedHandler, Bus, Message, Untyped,
|
||||
};
|
||||
use tokio::sync::{
|
||||
mpsc::{self, UnboundedSender},
|
||||
Mutex,
|
||||
};
|
||||
|
||||
pub struct SynchronizedAsyncSubscriber<T, M>
|
||||
where
|
||||
T: AsyncSynchronizedHandler<M> + 'static,
|
||||
M: Message,
|
||||
{
|
||||
cfg: SynchronizedConfig,
|
||||
_m: PhantomData<(T, M)>,
|
||||
synchronized_poller_macro! {
|
||||
T,
|
||||
AsyncSynchronizedHandler,
|
||||
|mid, msg, bus, ut: Arc<Mutex<T>>, stx: UnboundedSender<_>| {
|
||||
tokio::spawn(async move {
|
||||
let resp = ut.lock().await.handle(msg, &bus).await;
|
||||
|
||||
stx.send(Event::Response(mid, resp.map_err(Error::Other)))
|
||||
.unwrap();
|
||||
})
|
||||
},
|
||||
|
||||
|bus, ut: Arc<Mutex<T>>| async move {
|
||||
ut.lock().await.sync(&bus).await
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, M> ReceiverSubscriber<T> for SynchronizedAsyncSubscriber<T, M>
|
||||
pub struct SynchronizedAsync<M, R, E>
|
||||
where
|
||||
T: AsyncSynchronizedHandler<M> + 'static,
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
fn subscribe(
|
||||
self,
|
||||
) -> (
|
||||
Arc<dyn ReceiverTrait>,
|
||||
Box<
|
||||
dyn FnOnce(Untyped) -> Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>,
|
||||
>,
|
||||
) {
|
||||
let cfg = self.cfg;
|
||||
let (tx, rx) = mpsc::channel(cfg.buffer_size);
|
||||
let stats = Arc::new(SynchronizedStats {
|
||||
buffer: AtomicU64::new(0),
|
||||
buffer_total: AtomicU64::new(cfg.buffer_size as _),
|
||||
});
|
||||
tx: mpsc::UnboundedSender<Request<M>>,
|
||||
srx: parking_lot::Mutex<Option<mpsc::UnboundedReceiver<Event<R, E>>>>,
|
||||
}
|
||||
|
||||
let arc = Arc::new(SynchronizedAsync::<M> {
|
||||
tx,
|
||||
stats: stats.clone(),
|
||||
});
|
||||
impl<T, M, R, E> ReceiverSubscriberBuilder<T, M, R, E> for SynchronizedAsync<M, R, E>
|
||||
where
|
||||
T: AsyncSynchronizedHandler<M, Response = R, Error = E> + 'static,
|
||||
R: Message,
|
||||
M: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
type Config = SynchronizedConfig;
|
||||
|
||||
fn build(_cfg: Self::Config) -> (Self, UntypedPollerCallback) {
|
||||
let (stx, srx) = mpsc::unbounded_channel();
|
||||
let (tx, rx) = mpsc::unbounded_channel();
|
||||
|
||||
let poller = Box::new(move |ut| {
|
||||
Box::new(move |bus| {
|
||||
Box::pin(buffer_unordered_poller::<T, M>(rx, bus, ut, stats, cfg))
|
||||
Box::pin(synchronized_poller::<T, M, R>(rx, bus, ut, stx))
|
||||
as Pin<Box<dyn Future<Output = ()> + Send>>
|
||||
}) as Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>
|
||||
});
|
||||
|
||||
(arc, poller)
|
||||
}
|
||||
}
|
||||
|
||||
async fn buffer_unordered_poller<T, M>(
|
||||
rx: mpsc::Receiver<M>,
|
||||
bus: Bus,
|
||||
ut: Untyped,
|
||||
stats: Arc<SynchronizedStats>,
|
||||
_cfg: SynchronizedConfig,
|
||||
) where
|
||||
T: AsyncSynchronizedHandler<M> + 'static,
|
||||
M: Message,
|
||||
{
|
||||
let ut = ut.downcast::<Mutex<T>>().unwrap();
|
||||
let mut x = rx.then(|msg| {
|
||||
let bus = bus.clone();
|
||||
let ut = ut.clone();
|
||||
|
||||
tokio::task::spawn(async move { ut.lock().await.handle(msg, &bus).await })
|
||||
});
|
||||
|
||||
while let Some(err) = x.next().await {
|
||||
stats.buffer.fetch_sub(1, Ordering::Relaxed);
|
||||
|
||||
match err {
|
||||
Ok(Err(err)) => {
|
||||
let _ = bus.send(msgs::Error(Arc::new(err))).await;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
let ut = ut.clone();
|
||||
let bus_clone = bus.clone();
|
||||
let res = tokio::task::spawn(async move { ut.lock().await.sync(&bus_clone).await }).await;
|
||||
|
||||
match res {
|
||||
Ok(Err(err)) => {
|
||||
let _ = bus.send(msgs::Error(Arc::new(err))).await;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
println!("[EXIT] SynchronizedAsync<{}>", std::any::type_name::<M>());
|
||||
}
|
||||
|
||||
pub struct SynchronizedAsync<M: Message> {
|
||||
tx: mpsc::Sender<M>,
|
||||
stats: Arc<SynchronizedStats>,
|
||||
}
|
||||
|
||||
impl<T, M> ReceiverSubscriberBuilder<M, T> for SynchronizedAsync<M>
|
||||
where
|
||||
T: AsyncSynchronizedHandler<M> + 'static,
|
||||
M: Message,
|
||||
{
|
||||
type Entry = SynchronizedAsyncSubscriber<T, M>;
|
||||
type Config = SynchronizedConfig;
|
||||
|
||||
fn build(cfg: Self::Config) -> Self::Entry {
|
||||
SynchronizedAsyncSubscriber {
|
||||
cfg,
|
||||
_m: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Message> TypedReceiver<M> for SynchronizedAsync<M> {
|
||||
fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll<()> {
|
||||
match self.tx.poll_ready(ctx) {
|
||||
Poll::Ready(_) => Poll::Ready(()),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
|
||||
fn try_send(&self, m: M) -> Result<(), SendError<M>> {
|
||||
match self.tx.try_send(m) {
|
||||
Ok(_) => {
|
||||
self.stats.buffer.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Message> ReceiverTrait for SynchronizedAsync<M> {
|
||||
fn typed(&self) -> AnyReceiver<'_> {
|
||||
AnyReceiver::new(self)
|
||||
}
|
||||
|
||||
fn type_id(&self) -> TypeId {
|
||||
TypeId::of::<SynchronizedAsync<M>>()
|
||||
}
|
||||
|
||||
fn stats(&self) -> ReceiverStats {
|
||||
ReceiverStats {
|
||||
name: std::any::type_name::<M>().into(),
|
||||
fields: vec![
|
||||
("buffer".into(), self.stats.buffer.load(Ordering::SeqCst)),
|
||||
(
|
||||
"buffer_total".into(),
|
||||
self.stats.buffer_total.load(Ordering::SeqCst),
|
||||
),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
fn close(&self) {
|
||||
self.tx.close();
|
||||
}
|
||||
|
||||
fn sync(&self) {
|
||||
self.tx.flush();
|
||||
}
|
||||
|
||||
fn poll_synchronized(&self, _ctx: &mut Context<'_>) -> Poll<()> {
|
||||
Poll::Ready(())
|
||||
SynchronizedAsync::<M, R, E> {
|
||||
tx,
|
||||
srx: parking_lot::Mutex::new(Some(srx)),
|
||||
},
|
||||
poller,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<M, R, E> SendUntypedReceiver for SynchronizedAsync<M, R, E>
|
||||
where
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
fn send(&self, m: Action, _bus: &Bus) -> Result<(), Error<Action>> {
|
||||
match self.tx.send(Request::Action(m)) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(mpsc::error::SendError(Request::Action(msg))) => Err(Error::send_closed(msg)),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M, R, E> SendTypedReceiver<M> for SynchronizedAsync<M, R, E>
|
||||
where
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
fn send(&self, mid: u64, m: M, req: bool, _bus: &Bus) -> Result<(), Error<M>> {
|
||||
match self.tx.send(Request::Request(mid, m, req)) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(mpsc::error::SendError(Request::Request(_, msg, _))) => {
|
||||
Err(Error::send_closed(msg))
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M, R, E> ReciveTypedReceiver<R, E> for SynchronizedAsync<M, R, E>
|
||||
where
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
type Stream = Pin<Box<dyn Stream<Item = Event<R, E>> + Send>>;
|
||||
|
||||
fn event_stream(&self, _: Bus) -> Self::Stream {
|
||||
let mut rx = self.srx.lock().take().unwrap();
|
||||
|
||||
Box::pin(futures::stream::poll_fn(move |cx| rx.poll_recv(cx)))
|
||||
}
|
||||
}
|
||||
|
@ -3,9 +3,9 @@ mod sync;
|
||||
|
||||
use std::sync::atomic::AtomicU64;
|
||||
|
||||
pub use sync::{SynchronizedSync, SynchronizedSyncSubscriber};
|
||||
|
||||
pub use r#async::{SynchronizedAsync, SynchronizedAsyncSubscriber};
|
||||
pub use r#async::SynchronizedAsync;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
pub use sync::SynchronizedSync;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SynchronizedStats {
|
||||
@ -13,7 +13,7 @@ pub struct SynchronizedStats {
|
||||
pub buffer_total: AtomicU64,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct SynchronizedConfig {
|
||||
pub buffer_size: usize,
|
||||
}
|
||||
@ -23,3 +23,51 @@ impl Default for SynchronizedConfig {
|
||||
Self { buffer_size: 1 }
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! synchronized_poller_macro {
|
||||
($t: tt, $h: tt, $st1: expr, $st2: expr) => {
|
||||
async fn synchronized_poller<$t, M, R>(
|
||||
mut rx: mpsc::UnboundedReceiver<Request<M>>,
|
||||
bus: Bus,
|
||||
ut: Untyped,
|
||||
stx: mpsc::UnboundedSender<Event<R, $t::Error>>,
|
||||
) where
|
||||
$t: $h<M, Response = R> + 'static,
|
||||
$t::Error: StdSyncSendError,
|
||||
M: Message,
|
||||
R: Message,
|
||||
{
|
||||
let ut = ut.downcast::<Mutex<T>>().unwrap();
|
||||
|
||||
while let Some(msg) = rx.recv().await {
|
||||
match msg {
|
||||
Request::Request(mid, msg, _req) =>
|
||||
{
|
||||
#[allow(clippy::redundant_closure_call)]
|
||||
($st1)(mid, msg, bus.clone(), ut.clone(), stx.clone())
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
Request::Action(Action::Init(..)) => {
|
||||
stx.send(Event::Ready).unwrap();
|
||||
}
|
||||
Request::Action(Action::Close) => {
|
||||
rx.close();
|
||||
}
|
||||
Request::Action(Action::Flush) => {
|
||||
stx.send(Event::Flushed).unwrap();
|
||||
}
|
||||
Request::Action(Action::Sync) => {
|
||||
#[allow(clippy::redundant_closure_call)]
|
||||
let resp = ($st2)(bus.clone(), ut.clone()).await;
|
||||
stx.send(Event::Synchronized(resp.map_err(Error::Other)))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1,190 +1,122 @@
|
||||
use super::{SynchronizedConfig, SynchronizedStats};
|
||||
use crate::{receiver::ReceiverStats, receivers::mpsc};
|
||||
use futures::{executor::block_on, Future, StreamExt};
|
||||
use std::{
|
||||
any::TypeId,
|
||||
marker::PhantomData,
|
||||
pin::Pin,
|
||||
sync::{
|
||||
atomic::{AtomicU64, Ordering},
|
||||
Arc,
|
||||
},
|
||||
task::{Context, Poll},
|
||||
};
|
||||
use tokio::sync::Mutex;
|
||||
use std::{pin::Pin, sync::Arc};
|
||||
|
||||
use crate::{receiver::UntypedPollerCallback, synchronized_poller_macro};
|
||||
use futures::{executor::block_on, Future, Stream};
|
||||
|
||||
use super::SynchronizedConfig;
|
||||
use crate::{
|
||||
builder::{ReceiverSubscriber, ReceiverSubscriberBuilder},
|
||||
msgs,
|
||||
receiver::{AnyReceiver, ReceiverTrait, SendError, TypedReceiver},
|
||||
builder::ReceiverSubscriberBuilder,
|
||||
error::{Error, StdSyncSendError},
|
||||
receiver::{Action, Event, ReciveTypedReceiver, SendTypedReceiver, SendUntypedReceiver},
|
||||
receivers::Request,
|
||||
Bus, Message, SynchronizedHandler, Untyped,
|
||||
};
|
||||
use tokio::sync::{
|
||||
mpsc::{self, UnboundedSender},
|
||||
Mutex,
|
||||
};
|
||||
|
||||
pub struct SynchronizedSyncSubscriber<T, M>
|
||||
where
|
||||
T: SynchronizedHandler<M> + 'static,
|
||||
M: Message,
|
||||
{
|
||||
cfg: SynchronizedConfig,
|
||||
_m: PhantomData<(M, T)>,
|
||||
synchronized_poller_macro! {
|
||||
T,
|
||||
SynchronizedHandler,
|
||||
|mid, msg, bus, ut: Arc<Mutex<T>>, stx: UnboundedSender<_>| {
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let resp = block_on(ut.lock()).handle(msg, &bus);
|
||||
|
||||
stx.send(Event::Response(mid, resp.map_err(Error::Other)))
|
||||
.unwrap();
|
||||
})
|
||||
},
|
||||
|bus, ut: Arc<Mutex<T>>| async move {
|
||||
tokio::task::spawn_blocking(move || block_on(ut.lock()).sync(&bus))
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, M> ReceiverSubscriber<T> for SynchronizedSyncSubscriber<T, M>
|
||||
pub struct SynchronizedSync<M, R, E>
|
||||
where
|
||||
T: SynchronizedHandler<M> + 'static,
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
fn subscribe(
|
||||
self,
|
||||
) -> (
|
||||
Arc<dyn ReceiverTrait>,
|
||||
Box<
|
||||
dyn FnOnce(Untyped) -> Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>,
|
||||
>,
|
||||
) {
|
||||
let cfg = self.cfg;
|
||||
let (tx, rx) = mpsc::channel(cfg.buffer_size);
|
||||
let stats = Arc::new(SynchronizedStats {
|
||||
buffer: AtomicU64::new(0),
|
||||
buffer_total: AtomicU64::new(cfg.buffer_size as _),
|
||||
});
|
||||
tx: mpsc::UnboundedSender<Request<M>>,
|
||||
srx: parking_lot::Mutex<Option<mpsc::UnboundedReceiver<Event<R, E>>>>,
|
||||
}
|
||||
|
||||
impl<T, M, R, E> ReceiverSubscriberBuilder<T, M, R, E> for SynchronizedSync<M, R, E>
|
||||
where
|
||||
T: SynchronizedHandler<M, Response = R, Error = E> + 'static,
|
||||
R: Message,
|
||||
M: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
type Config = SynchronizedConfig;
|
||||
|
||||
fn build(_cfg: Self::Config) -> (Self, UntypedPollerCallback) {
|
||||
let (stx, srx) = mpsc::unbounded_channel();
|
||||
let (tx, rx) = mpsc::unbounded_channel();
|
||||
|
||||
let arc = Arc::new(SynchronizedSync::<M> {
|
||||
tx,
|
||||
stats: stats.clone(),
|
||||
});
|
||||
let poller = Box::new(move |ut| {
|
||||
Box::new(move |bus| {
|
||||
Box::pin(buffer_unordered_poller::<T, M>(rx, bus, ut, stats, cfg))
|
||||
Box::pin(synchronized_poller::<T, M, R>(rx, bus, ut, stx))
|
||||
as Pin<Box<dyn Future<Output = ()> + Send>>
|
||||
}) as Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>
|
||||
});
|
||||
|
||||
(arc, poller)
|
||||
}
|
||||
}
|
||||
|
||||
async fn buffer_unordered_poller<T, M>(
|
||||
rx: mpsc::Receiver<M>,
|
||||
bus: Bus,
|
||||
ut: Untyped,
|
||||
stats: Arc<SynchronizedStats>,
|
||||
_cfg: SynchronizedConfig,
|
||||
) where
|
||||
T: SynchronizedHandler<M> + 'static,
|
||||
M: Message,
|
||||
{
|
||||
let ut = ut.downcast::<Mutex<T>>().unwrap();
|
||||
let mut x = rx.then(|msg| {
|
||||
let ut = ut.clone();
|
||||
let bus = bus.clone();
|
||||
|
||||
tokio::task::spawn_blocking(move || block_on(ut.lock()).handle(msg, &bus))
|
||||
});
|
||||
|
||||
while let Some(err) = x.next().await {
|
||||
stats.buffer.fetch_sub(1, Ordering::Relaxed);
|
||||
|
||||
match err {
|
||||
Ok(Err(err)) => {
|
||||
let _ = bus.send(msgs::Error(Arc::new(err))).await;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
let ut = ut.clone();
|
||||
let bus_clone = bus.clone();
|
||||
let res = tokio::task::spawn_blocking(move || {
|
||||
futures::executor::block_on(ut.lock()).sync(&bus_clone)
|
||||
})
|
||||
.await;
|
||||
|
||||
match res {
|
||||
Ok(Err(err)) => {
|
||||
let _ = bus.send(msgs::Error(Arc::new(err))).await;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
println!(
|
||||
"[EXIT] BufferUnorderedSync<{}>",
|
||||
std::any::type_name::<M>()
|
||||
);
|
||||
}
|
||||
|
||||
pub struct SynchronizedSync<M: Message> {
|
||||
tx: mpsc::Sender<M>,
|
||||
stats: Arc<SynchronizedStats>,
|
||||
}
|
||||
|
||||
impl<T, M> ReceiverSubscriberBuilder<M, T> for SynchronizedSync<M>
|
||||
where
|
||||
T: SynchronizedHandler<M> + 'static,
|
||||
M: Message,
|
||||
{
|
||||
type Entry = SynchronizedSyncSubscriber<T, M>;
|
||||
type Config = SynchronizedConfig;
|
||||
|
||||
fn build(cfg: Self::Config) -> Self::Entry {
|
||||
SynchronizedSyncSubscriber {
|
||||
cfg,
|
||||
_m: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Message> TypedReceiver<M> for SynchronizedSync<M> {
|
||||
fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll<()> {
|
||||
match self.tx.poll_ready(ctx) {
|
||||
Poll::Ready(_) => Poll::Ready(()),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
|
||||
fn try_send(&self, m: M) -> Result<(), SendError<M>> {
|
||||
match self.tx.try_send(m) {
|
||||
Ok(_) => {
|
||||
self.stats.buffer.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Message> ReceiverTrait for SynchronizedSync<M> {
|
||||
fn typed(&self) -> AnyReceiver<'_> {
|
||||
AnyReceiver::new(self)
|
||||
}
|
||||
|
||||
fn type_id(&self) -> TypeId {
|
||||
TypeId::of::<SynchronizedSync<M>>()
|
||||
}
|
||||
|
||||
fn stats(&self) -> ReceiverStats {
|
||||
ReceiverStats {
|
||||
name: std::any::type_name::<M>().into(),
|
||||
fields: vec![
|
||||
("buffer".into(), self.stats.buffer.load(Ordering::SeqCst)),
|
||||
(
|
||||
"buffer_total".into(),
|
||||
self.stats.buffer_total.load(Ordering::SeqCst),
|
||||
),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
fn close(&self) {
|
||||
self.tx.close();
|
||||
}
|
||||
|
||||
fn sync(&self) {
|
||||
self.tx.flush();
|
||||
}
|
||||
|
||||
fn poll_synchronized(&self, _ctx: &mut Context<'_>) -> Poll<()> {
|
||||
Poll::Ready(())
|
||||
SynchronizedSync::<M, R, E> {
|
||||
tx,
|
||||
srx: parking_lot::Mutex::new(Some(srx)),
|
||||
},
|
||||
poller,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<M, R, E> SendUntypedReceiver for SynchronizedSync<M, R, E>
|
||||
where
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
fn send(&self, msg: Action, _bus: &Bus) -> Result<(), Error<Action>> {
|
||||
match self.tx.send(Request::Action(msg)) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(mpsc::error::SendError(Request::Action(msg))) => Err(Error::send_closed(msg)),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M, R, E> SendTypedReceiver<M> for SynchronizedSync<M, R, E>
|
||||
where
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
fn send(&self, mid: u64, m: M, req: bool, _bus: &Bus) -> Result<(), Error<M>> {
|
||||
match self.tx.send(Request::Request(mid, m, req)) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(mpsc::error::SendError(Request::Request(_, msg, _))) => {
|
||||
Err(Error::send_closed(msg))
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M, R, E> ReciveTypedReceiver<R, E> for SynchronizedSync<M, R, E>
|
||||
where
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
{
|
||||
type Stream = Pin<Box<dyn Stream<Item = Event<R, E>> + Send>>;
|
||||
|
||||
fn event_stream(&self, _: Bus) -> Self::Stream {
|
||||
let mut rx = self.srx.lock().take().unwrap();
|
||||
|
||||
Box::pin(futures::stream::poll_fn(move |cx| rx.poll_recv(cx)))
|
||||
}
|
||||
}
|
||||
|
320
src/relay.rs
Normal file
320
src/relay.rs
Normal file
@ -0,0 +1,320 @@
|
||||
use crate::{
|
||||
error::Error,
|
||||
receiver::{
|
||||
Action, AnyReceiver, AnyWrapperRef, BusPollerCallback, PermitDrop, ReceiverTrait,
|
||||
SendUntypedReceiver, TypeTagAccept,
|
||||
},
|
||||
stats::Stats,
|
||||
Bus, Event, Message, Permit, ReciveUntypedReceiver, TypeTag, TypeTagAcceptItem,
|
||||
};
|
||||
use core::sync::atomic::{AtomicBool, AtomicU64, Ordering};
|
||||
use dashmap::DashMap;
|
||||
use futures::{pin_mut, StreamExt};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::{oneshot, Notify};
|
||||
|
||||
pub trait Relay: TypeTagAccept + SendUntypedReceiver + ReciveUntypedReceiver + 'static {}
|
||||
impl<T: TypeTagAccept + SendUntypedReceiver + ReciveUntypedReceiver + 'static> Relay for T {}
|
||||
|
||||
struct SlabCfg;
|
||||
impl sharded_slab::Config for SlabCfg {
|
||||
const RESERVED_BITS: usize = 1;
|
||||
}
|
||||
|
||||
type Slab<T> = sharded_slab::Slab<T, SlabCfg>;
|
||||
|
||||
pub(crate) struct RelayContext {
|
||||
receivers: DashMap<TypeTag, Arc<RelayReceiverContext>>,
|
||||
need_flush: AtomicBool,
|
||||
ready_flag: AtomicBool,
|
||||
idling_flag: AtomicBool,
|
||||
init_sent: AtomicBool,
|
||||
flushed: Notify,
|
||||
synchronized: Notify,
|
||||
closed: Notify,
|
||||
ready: Notify,
|
||||
idle: Notify,
|
||||
}
|
||||
|
||||
pub struct RelayReceiverContext {
|
||||
limit: u64,
|
||||
processing: AtomicU64,
|
||||
response: Arc<Notify>,
|
||||
}
|
||||
|
||||
impl RelayReceiverContext {
|
||||
fn new(limit: u64) -> Self {
|
||||
Self {
|
||||
limit,
|
||||
processing: Default::default(),
|
||||
response: Arc::new(Notify::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PermitDrop for RelayReceiverContext {
|
||||
fn permit_drop(&self) {
|
||||
self.processing.fetch_sub(1, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RelayWrapper<S>
|
||||
where
|
||||
S: 'static,
|
||||
{
|
||||
id: u64,
|
||||
inner: S,
|
||||
context: Arc<RelayContext>,
|
||||
waiters: Slab<oneshot::Sender<Result<Box<dyn Message>, Error>>>,
|
||||
}
|
||||
impl<S> RelayWrapper<S> {
|
||||
pub fn new(id: u64, inner: S) -> Self {
|
||||
Self {
|
||||
id,
|
||||
inner,
|
||||
context: Arc::new(RelayContext {
|
||||
receivers: DashMap::new(),
|
||||
need_flush: AtomicBool::new(false),
|
||||
ready_flag: AtomicBool::new(false),
|
||||
idling_flag: AtomicBool::new(true),
|
||||
init_sent: AtomicBool::new(false),
|
||||
flushed: Notify::new(),
|
||||
synchronized: Notify::new(),
|
||||
closed: Notify::new(),
|
||||
ready: Notify::new(),
|
||||
idle: Notify::new(),
|
||||
}),
|
||||
waiters: sharded_slab::Slab::new_with_config::<SlabCfg>(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> TypeTagAccept for RelayWrapper<S>
|
||||
where
|
||||
S: Relay + Send + Sync + 'static,
|
||||
{
|
||||
fn iter_types(&self) -> Box<dyn Iterator<Item = TypeTagAcceptItem> + '_> {
|
||||
self.inner.iter_types()
|
||||
}
|
||||
|
||||
fn accept_msg(&self, msg: &TypeTag) -> bool {
|
||||
self.inner.accept_msg(msg)
|
||||
}
|
||||
|
||||
fn accept_req(&self, req: &TypeTag, resp: Option<&TypeTag>, err: Option<&TypeTag>) -> bool {
|
||||
self.inner.accept_req(req, resp, err)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> ReceiverTrait for RelayWrapper<S>
|
||||
where
|
||||
S: Relay + Send + Sync + 'static,
|
||||
{
|
||||
fn name(&self) -> &str {
|
||||
std::any::type_name::<Self>()
|
||||
}
|
||||
|
||||
fn typed(&self) -> Option<AnyReceiver<'_>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn wrapper(&self) -> Option<AnyWrapperRef<'_>> {
|
||||
None
|
||||
}
|
||||
fn id(&self) -> u64 {
|
||||
self.id
|
||||
}
|
||||
|
||||
fn send_boxed(
|
||||
&self,
|
||||
mid: u64,
|
||||
boxed_msg: Box<dyn Message>,
|
||||
req: bool,
|
||||
bus: &Bus,
|
||||
) -> Result<(), Error<Box<dyn Message>>> {
|
||||
self.inner.send_msg(mid, boxed_msg, req, bus)
|
||||
}
|
||||
|
||||
fn add_response_listener(
|
||||
&self,
|
||||
listener: oneshot::Sender<Result<Box<dyn Message>, Error>>,
|
||||
) -> Result<u64, Error> {
|
||||
Ok(self
|
||||
.waiters
|
||||
.insert(listener)
|
||||
.ok_or(Error::AddListenerError)? as _)
|
||||
}
|
||||
|
||||
fn stats(&self) -> Stats {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn send_action(&self, bus: &Bus, action: Action) -> Result<(), Error<Action>> {
|
||||
SendUntypedReceiver::send(&self.inner, action, bus)
|
||||
}
|
||||
|
||||
fn close_notify(&self) -> &Notify {
|
||||
&self.context.closed
|
||||
}
|
||||
|
||||
fn sync_notify(&self) -> &Notify {
|
||||
&self.context.synchronized
|
||||
}
|
||||
|
||||
fn flush_notify(&self) -> &Notify {
|
||||
&self.context.flushed
|
||||
}
|
||||
|
||||
fn ready_notify(&self) -> &Notify {
|
||||
&self.context.ready
|
||||
}
|
||||
|
||||
fn idle_notify(&self) -> &Notify {
|
||||
&self.context.idle
|
||||
}
|
||||
|
||||
fn is_init_sent(&self) -> bool {
|
||||
self.context.init_sent.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
fn is_ready(&self) -> bool {
|
||||
self.context.ready_flag.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
fn is_idling(&self) -> bool {
|
||||
self.context.idling_flag.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
fn need_flush(&self) -> bool {
|
||||
self.context.need_flush.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
fn set_need_flush(&self) {
|
||||
self.context.need_flush.store(true, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
fn try_reserve(&self, tt: &TypeTag) -> Option<Permit> {
|
||||
if !self.context.receivers.contains_key(tt) {
|
||||
self.context
|
||||
.receivers
|
||||
.insert(tt.clone(), Arc::new(RelayReceiverContext::new(16)));
|
||||
}
|
||||
|
||||
loop {
|
||||
let context = self.context.receivers.get(tt).unwrap();
|
||||
let count = context.processing.load(Ordering::Relaxed);
|
||||
|
||||
if count < context.limit {
|
||||
let res = context.processing.compare_exchange(
|
||||
count,
|
||||
count + 1,
|
||||
Ordering::SeqCst,
|
||||
Ordering::SeqCst,
|
||||
);
|
||||
if res.is_ok() {
|
||||
break Some(Permit {
|
||||
fuse: false,
|
||||
inner: context.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
// continue
|
||||
} else {
|
||||
break None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn reserve_notify(&self, tt: &TypeTag) -> Arc<Notify> {
|
||||
if !self.context.receivers.contains_key(tt) {
|
||||
self.context
|
||||
.receivers
|
||||
.insert(tt.clone(), Arc::new(RelayReceiverContext::new(16)));
|
||||
}
|
||||
|
||||
self.context.receivers.get(tt).unwrap().response.clone()
|
||||
}
|
||||
|
||||
fn increment_processing(&self, tt: &TypeTag) {
|
||||
self.context
|
||||
.receivers
|
||||
.get(tt)
|
||||
.map(|r| r.processing.fetch_add(1, Ordering::SeqCst));
|
||||
}
|
||||
|
||||
fn start_polling(self: Arc<Self>) -> BusPollerCallback {
|
||||
Box::new(move |bus| {
|
||||
Box::pin(async move {
|
||||
let this = self.clone();
|
||||
let events = this.inner.event_stream(bus);
|
||||
pin_mut!(events);
|
||||
|
||||
loop {
|
||||
let event = if let Some(event) = events.next().await {
|
||||
event
|
||||
} else {
|
||||
self.context.closed.notify_waiters();
|
||||
break;
|
||||
};
|
||||
|
||||
match event {
|
||||
Event::Error(err) => error!("Batch Error: {}", err),
|
||||
Event::Pause => self.context.ready_flag.store(false, Ordering::SeqCst),
|
||||
Event::Ready => {
|
||||
self.context.ready.notify_waiters();
|
||||
self.context.ready_flag.store(true, Ordering::SeqCst)
|
||||
}
|
||||
Event::InitFailed(err) => {
|
||||
error!("Relay init failed: {}", err);
|
||||
|
||||
self.context.ready.notify_waiters();
|
||||
self.context.ready_flag.store(false, Ordering::SeqCst);
|
||||
}
|
||||
Event::Exited => {
|
||||
self.context.closed.notify_waiters();
|
||||
break;
|
||||
}
|
||||
Event::Flushed => {
|
||||
self.context.need_flush.store(false, Ordering::SeqCst);
|
||||
self.context.flushed.notify_one()
|
||||
}
|
||||
Event::Synchronized(_res) => self.context.synchronized.notify_waiters(),
|
||||
Event::Response(mid, resp) => {
|
||||
let tt = if let Ok(bm) = &resp {
|
||||
Some(bm.type_tag())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(chan) = self.waiters.take(mid as _) {
|
||||
if let Err(err) = chan.send(resp) {
|
||||
error!("Response error for mid({}): {:?}", mid, err);
|
||||
}
|
||||
} else {
|
||||
warn!("No waiters for mid({})", mid);
|
||||
};
|
||||
|
||||
if let Some(tt) = tt {
|
||||
if let Some(ctx) = self.context.receivers.get(&tt) {
|
||||
ctx.processing.fetch_sub(1, Ordering::SeqCst);
|
||||
ctx.response.notify_one();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Event::BatchComplete(tt, n) => {
|
||||
if let Some(ctx) = self.context.receivers.get(&tt) {
|
||||
ctx.processing.fetch_sub(n, Ordering::SeqCst);
|
||||
|
||||
for _ in 0..n {
|
||||
ctx.response.notify_one();
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
21
src/stats.rs
Normal file
21
src/stats.rs
Normal file
@ -0,0 +1,21 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub struct Stats {
|
||||
pub msg_type_tag: Cow<'static, str>,
|
||||
|
||||
pub resp_type_tag: Option<Cow<'static, str>>,
|
||||
pub err_type_tag: Option<Cow<'static, str>>,
|
||||
|
||||
pub has_queue: bool,
|
||||
pub queue_capacity: i64,
|
||||
pub queue_size: i64,
|
||||
|
||||
pub has_parallel: bool,
|
||||
pub parallel_capacity: i64,
|
||||
pub parallel_size: i64,
|
||||
|
||||
pub has_batch: bool,
|
||||
pub batch_capacity: i64,
|
||||
pub batch_size: i64,
|
||||
}
|
84
src/type_tag.rs
Normal file
84
src/type_tag.rs
Normal file
@ -0,0 +1,84 @@
|
||||
use parking_lot::RwLock;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::envelop::IntoSharedMessage;
|
||||
use crate::error::Error;
|
||||
use crate::{Message, SharedMessage, TypeTag};
|
||||
|
||||
static TYPE_REGISTRY: TypeRegistry = TypeRegistry::new();
|
||||
|
||||
type MessageDeserializerCallback = Box<
|
||||
dyn Fn(&mut dyn erased_serde::Deserializer<'_>) -> Result<Box<dyn SharedMessage>, Error>
|
||||
+ Send
|
||||
+ Sync,
|
||||
>;
|
||||
|
||||
pub struct MessageTypeDescriptor {
|
||||
de: MessageDeserializerCallback,
|
||||
}
|
||||
|
||||
impl MessageTypeDescriptor {
|
||||
#[inline]
|
||||
pub fn deserialize_boxed(
|
||||
&self,
|
||||
de: &mut dyn erased_serde::Deserializer<'_>,
|
||||
) -> Result<Box<dyn SharedMessage>, Error> {
|
||||
(self.de)(de)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct TypeRegistry {
|
||||
message_types: RwLock<Option<HashMap<TypeTag, MessageTypeDescriptor>>>,
|
||||
}
|
||||
|
||||
impl TypeRegistry {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
message_types: parking_lot::const_rwlock(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deserialize(
|
||||
&self,
|
||||
tt: TypeTag,
|
||||
de: &mut dyn erased_serde::Deserializer<'_>,
|
||||
) -> Result<Box<dyn SharedMessage>, Error<Box<dyn Message>>> {
|
||||
let guard = self.message_types.read();
|
||||
let md = guard
|
||||
.as_ref()
|
||||
.ok_or_else(|| Error::TypeTagNotRegistered(tt.clone()))?
|
||||
.get(&tt)
|
||||
.ok_or(Error::TypeTagNotRegistered(tt))?;
|
||||
|
||||
md.deserialize_boxed(de)
|
||||
.map_err(|err| err.specify::<Box<dyn Message>>())
|
||||
}
|
||||
|
||||
pub fn register<M: Message + serde::Serialize + serde::de::DeserializeOwned>(&self) {
|
||||
println!("insert {}", M::type_tag_());
|
||||
|
||||
self.message_types
|
||||
.write()
|
||||
.get_or_insert_with(HashMap::new)
|
||||
.insert(
|
||||
M::type_tag_(),
|
||||
MessageTypeDescriptor {
|
||||
de: Box::new(move |de| Ok(M::deserialize(de)?.into_shared())),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn deserialize_shared_message(
|
||||
tt: TypeTag,
|
||||
de: &mut dyn erased_serde::Deserializer<'_>,
|
||||
) -> Result<Box<dyn SharedMessage>, Error<Box<dyn Message>>> {
|
||||
TYPE_REGISTRY.deserialize(tt, de)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn register_shared_message<M: Message + serde::Serialize + serde::de::DeserializeOwned>() {
|
||||
TYPE_REGISTRY.register::<M>();
|
||||
}
|
33
src/utils.rs
33
src/utils.rs
@ -1,33 +0,0 @@
|
||||
use core::cmp::{Ord, Ordering};
|
||||
use core::ops::Range;
|
||||
|
||||
pub fn binary_search_range_by_key<'a, T, B, F>(data: &'a [T], item: &B, mut f: F) -> Range<usize>
|
||||
where
|
||||
F: FnMut(&'a T) -> B,
|
||||
B: Ord,
|
||||
{
|
||||
if let Ok(index) = data.binary_search_by_key(item, &mut f) {
|
||||
let mut begin = index;
|
||||
let mut end = index + 1;
|
||||
|
||||
for i in (0..index).rev() {
|
||||
if f(unsafe { data.get_unchecked(i) }).cmp(item) != Ordering::Equal {
|
||||
break;
|
||||
}
|
||||
|
||||
begin = i;
|
||||
}
|
||||
|
||||
for i in end..data.len() {
|
||||
end = i;
|
||||
|
||||
if f(unsafe { data.get_unchecked(i) }).cmp(item) != Ordering::Equal {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
begin..end
|
||||
} else {
|
||||
data.len()..data.len()
|
||||
}
|
||||
}
|
58
tests/test_backpressure.rs
Normal file
58
tests/test_backpressure.rs
Normal file
@ -0,0 +1,58 @@
|
||||
use async_trait::async_trait;
|
||||
use messagebus::{
|
||||
derive::{Error as MbError, Message},
|
||||
error, receivers, AsyncHandler, Bus, Message,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error, MbError)]
|
||||
enum Error {
|
||||
#[error("Error({0})")]
|
||||
Error(anyhow::Error),
|
||||
}
|
||||
|
||||
impl<M: Message> From<error::Error<M>> for Error {
|
||||
fn from(err: error::Error<M>) -> Self {
|
||||
Self::Error(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
struct MsgF32(pub f32);
|
||||
|
||||
struct TmpReceiver;
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<MsgF32> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, _msg: MsgF32, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_backpressure() {
|
||||
let (b, poller) = Bus::build()
|
||||
.register(TmpReceiver)
|
||||
.subscribe_async::<MsgF32>(
|
||||
1,
|
||||
receivers::BufferUnorderedConfig {
|
||||
buffer_size: 1,
|
||||
max_parallel: 1,
|
||||
},
|
||||
)
|
||||
.done()
|
||||
.build();
|
||||
|
||||
b.send(MsgF32(32f32)).await.unwrap();
|
||||
b.send(MsgF32(32f32)).await.unwrap();
|
||||
|
||||
assert!(b.try_send(MsgF32(32f32)).is_err());
|
||||
|
||||
b.flush_all().await;
|
||||
b.close().await;
|
||||
poller.await;
|
||||
}
|
115
tests/test_batch.rs
Normal file
115
tests/test_batch.rs
Normal file
@ -0,0 +1,115 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use messagebus::{
|
||||
derive::{Error as MbError, Message},
|
||||
error,
|
||||
receivers::BufferUnorderedBatchedConfig,
|
||||
AsyncBatchHandler, Bus, Message,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error, Clone, MbError)]
|
||||
enum Error {
|
||||
#[error("Error({0})")]
|
||||
Error(Arc<anyhow::Error>),
|
||||
}
|
||||
|
||||
impl<M: Message> From<error::Error<M>> for Error {
|
||||
fn from(err: error::Error<M>) -> Self {
|
||||
Self::Error(Arc::new(err.into()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[message(clone)]
|
||||
struct MsgI32(i32);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[message(clone)]
|
||||
struct MsgI16(i16);
|
||||
|
||||
struct TmpReceiver {
|
||||
batches: Arc<Mutex<Vec<Vec<i32>>>>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncBatchHandler<MsgI32> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
type InBatch = Vec<MsgI32>;
|
||||
type OutBatch = Vec<()>;
|
||||
|
||||
async fn handle(
|
||||
&self,
|
||||
msg: Vec<MsgI32>,
|
||||
_bus: &Bus,
|
||||
) -> Result<Vec<Self::Response>, Self::Error> {
|
||||
self.batches
|
||||
.lock()
|
||||
.push(msg.into_iter().map(|x| x.0).collect());
|
||||
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_batch() {
|
||||
let batches = Arc::new(Mutex::new(Vec::new()));
|
||||
|
||||
let (b, poller) = Bus::build()
|
||||
.register(TmpReceiver {
|
||||
batches: batches.clone(),
|
||||
})
|
||||
.subscribe_batch_async::<MsgI32>(
|
||||
16,
|
||||
BufferUnorderedBatchedConfig {
|
||||
batch_size: 8,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.done()
|
||||
.build();
|
||||
|
||||
for i in 1..100i32 {
|
||||
b.send(MsgI32(i)).await.unwrap();
|
||||
}
|
||||
|
||||
let mut re = Vec::new();
|
||||
let mut counter = 1i32;
|
||||
for _ in 1..100i32 {
|
||||
let mut v = Vec::new();
|
||||
for _ in 0..8 {
|
||||
if counter >= 100 {
|
||||
break;
|
||||
}
|
||||
|
||||
v.push(counter);
|
||||
|
||||
counter += 1;
|
||||
}
|
||||
|
||||
re.push(v);
|
||||
|
||||
if counter >= 100 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
println!("flush");
|
||||
b.flush_all().await;
|
||||
|
||||
let mut lock = batches.lock();
|
||||
lock.sort_by(|a, b| a[0].cmp(&b[0]));
|
||||
|
||||
assert_eq!(lock.as_slice(), re.as_slice());
|
||||
|
||||
println!("close");
|
||||
b.close().await;
|
||||
|
||||
println!("closed");
|
||||
|
||||
poller.await;
|
||||
println!("[done]");
|
||||
}
|
133
tests/test_concurrency.rs
Normal file
133
tests/test_concurrency.rs
Normal file
@ -0,0 +1,133 @@
|
||||
use std::{sync::atomic::AtomicU32, time::Duration};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use messagebus::{
|
||||
derive::{Error as MbError, Message},
|
||||
error,
|
||||
receivers::BufferUnorderedConfig,
|
||||
AsyncHandler, Bus, Message, Module,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error, MbError)]
|
||||
enum Error {
|
||||
#[error("Error({0})")]
|
||||
Error(anyhow::Error),
|
||||
|
||||
#[error("MyError")]
|
||||
MyError,
|
||||
}
|
||||
|
||||
impl<M: Message> From<error::Error<M>> for Error {
|
||||
fn from(err: error::Error<M>) -> Self {
|
||||
Self::Error(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
struct Req(pub u32);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
struct Resp(pub u32);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
struct GetCount;
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
struct CountResult(pub u32);
|
||||
|
||||
struct TmpReceiver {
|
||||
counter: AtomicU32,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<Req> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, msg: Req, bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
tokio::time::sleep(Duration::from_millis((msg.0 % 20) as _)).await;
|
||||
|
||||
if msg.0 % 128 == 0 {
|
||||
return Err(Error::MyError);
|
||||
} else {
|
||||
bus.send(Resp(msg.0)).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<Resp> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, _msg: Resp, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
self.counter
|
||||
.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<GetCount> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = CountResult;
|
||||
|
||||
async fn handle(&self, _: GetCount, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
Ok(CountResult(
|
||||
self.counter.load(std::sync::atomic::Ordering::SeqCst),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn module() -> Module {
|
||||
Module::new()
|
||||
.register(TmpReceiver {
|
||||
counter: AtomicU32::new(0),
|
||||
})
|
||||
.subscribe_async::<Req>(
|
||||
1024,
|
||||
BufferUnorderedConfig {
|
||||
buffer_size: 1024,
|
||||
max_parallel: 1024,
|
||||
},
|
||||
)
|
||||
.subscribe_async::<Resp>(1024, Default::default())
|
||||
.subscribe_async::<GetCount>(8, Default::default())
|
||||
.done()
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_sync() {
|
||||
let (b, poller) = Bus::build().add_module(module()).build();
|
||||
let cnt = 4u32;
|
||||
for i in 0..cnt {
|
||||
for j in 0..32768 {
|
||||
b.send(Req(i * 128 + j)).await.unwrap();
|
||||
}
|
||||
|
||||
println!("{} sent", i);
|
||||
}
|
||||
|
||||
println!("sent");
|
||||
|
||||
b.flush_all().await;
|
||||
|
||||
println!("flushed");
|
||||
|
||||
assert_eq!(
|
||||
b.request_we::<_, CountResult, Error>(GetCount, Default::default())
|
||||
.await
|
||||
.unwrap()
|
||||
.0,
|
||||
cnt * 32768 - cnt * 256
|
||||
);
|
||||
|
||||
b.close().await;
|
||||
|
||||
println!("closed");
|
||||
|
||||
poller.await;
|
||||
}
|
32
tests/test_derive.rs
Normal file
32
tests/test_derive.rs
Normal file
@ -0,0 +1,32 @@
|
||||
use messagebus::{
|
||||
derive::{Error as MbError, Message},
|
||||
error, Message, TypeTagged,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error, MbError)]
|
||||
enum Error {
|
||||
#[error("Error({0})")]
|
||||
Error(anyhow::Error),
|
||||
}
|
||||
|
||||
impl<M: Message> From<error::Error<M>> for Error {
|
||||
fn from(err: error::Error<M>) -> Self {
|
||||
Self::Error(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[namespace("api")]
|
||||
pub struct Msg<F>(pub F);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[type_tag("api::Query")]
|
||||
pub struct Qqq<F, G, H>(pub F, pub G, pub H);
|
||||
|
||||
fn main() {
|
||||
assert_eq!(
|
||||
Qqq::<Msg<i32>, Msg<()>, u64>::type_tag_(),
|
||||
"api::Query<api::Msg<i32>,api::Msg<()>,u64>"
|
||||
);
|
||||
}
|
71
tests/test_idle.rs
Normal file
71
tests/test_idle.rs
Normal file
@ -0,0 +1,71 @@
|
||||
use async_trait::async_trait;
|
||||
use messagebus::{
|
||||
derive::{Error as MbError, Message},
|
||||
error, receivers, AsyncHandler, Bus, Message,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error, MbError)]
|
||||
enum Error {
|
||||
#[error("Error({0})")]
|
||||
Error(anyhow::Error),
|
||||
}
|
||||
|
||||
impl<M: Message> From<error::Error<M>> for Error {
|
||||
fn from(err: error::Error<M>) -> Self {
|
||||
Self::Error(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
struct MsgF32(pub f32);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
struct MsgF64(pub f64);
|
||||
|
||||
struct TmpReceiver;
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<MsgF64> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, _msg: MsgF64, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
#[async_trait]
|
||||
impl AsyncHandler<MsgF32> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, _msg: MsgF32, bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
bus.send(MsgF64(12.0)).await.unwrap();
|
||||
bus.flush::<MsgF64>().await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_backpressure() {
|
||||
let (b, poller) = Bus::build()
|
||||
.register(TmpReceiver)
|
||||
.subscribe_async::<MsgF32>(
|
||||
1,
|
||||
receivers::BufferUnorderedConfig {
|
||||
buffer_size: 1,
|
||||
max_parallel: 1,
|
||||
},
|
||||
)
|
||||
.done()
|
||||
.build();
|
||||
|
||||
b.send(MsgF32(10.0)).await.unwrap();
|
||||
// b.idle_all().await;
|
||||
b.flush_all().await;
|
||||
b.close().await;
|
||||
poller.await;
|
||||
}
|
204
tests/test_relay.rs
Normal file
204
tests/test_relay.rs
Normal file
@ -0,0 +1,204 @@
|
||||
use std::pin::Pin;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use futures::Stream;
|
||||
use messagebus::{
|
||||
derive::{Error as MbError, Message},
|
||||
error::{self, GenericError},
|
||||
receivers, Action, AsyncHandler, Bus, Event, Message, MessageBounds, ReciveUntypedReceiver,
|
||||
SendUntypedReceiver, TypeTagAccept, TypeTagAcceptItem, TypeTagged,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use thiserror::Error;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
#[derive(Debug, Error, MbError)]
|
||||
enum Error {
|
||||
#[error("Error({0})")]
|
||||
Error(anyhow::Error),
|
||||
}
|
||||
|
||||
impl<M: Message> From<error::Error<M>> for Error {
|
||||
fn from(err: error::Error<M>) -> Self {
|
||||
Self::Error(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
pub struct Msg<F: MessageBounds + Clone>(pub F);
|
||||
|
||||
struct TmpReceiver;
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<Msg<i32>> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, msg: Msg<i32>, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
println!("TmpReceiver::handle {:?}", msg);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
println!("TmpReceiver::sync");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub type TestRelayRxChannelCell =
|
||||
Mutex<Option<mpsc::UnboundedReceiver<Event<Box<dyn Message>, GenericError>>>>;
|
||||
pub type TestRelayRxStream =
|
||||
Pin<Box<dyn Stream<Item = Event<Box<dyn Message>, error::GenericError>> + Send>>;
|
||||
|
||||
pub struct TestRelay {
|
||||
stx: mpsc::UnboundedSender<Event<Box<dyn Message>, GenericError>>,
|
||||
srx: TestRelayRxChannelCell,
|
||||
}
|
||||
|
||||
impl TypeTagAccept for TestRelay {
|
||||
fn accept_req(
|
||||
&self,
|
||||
msg: &messagebus::TypeTag,
|
||||
resp: Option<&messagebus::TypeTag>,
|
||||
_err: Option<&messagebus::TypeTag>,
|
||||
) -> bool {
|
||||
if msg.as_ref() == Msg::<i16>::type_tag_().as_ref() {
|
||||
if let Some(resp) = resp {
|
||||
if resp.as_ref() == Msg::<u8>::type_tag_().as_ref() {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if msg.as_ref() == Msg::<i32>::type_tag_().as_ref() {
|
||||
if let Some(resp) = resp {
|
||||
if resp.as_ref() == Msg::<u64>::type_tag_().as_ref() {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn accept_msg(&self, msg: &messagebus::TypeTag) -> bool {
|
||||
if msg.as_ref() == Msg::<i32>::type_tag_().as_ref() {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn iter_types(&self) -> Box<dyn Iterator<Item = TypeTagAcceptItem>> {
|
||||
Box::new(
|
||||
std::iter::once((Msg::<i32>::type_tag_(), None))
|
||||
.chain(std::iter::once((
|
||||
Msg::<i32>::type_tag_(),
|
||||
Some((Msg::<u64>::type_tag_(), GenericError::type_tag_())),
|
||||
)))
|
||||
.chain(std::iter::once((
|
||||
Msg::<i16>::type_tag_(),
|
||||
Some((Msg::<u8>::type_tag_(), GenericError::type_tag_())),
|
||||
))),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl SendUntypedReceiver for TestRelay {
|
||||
fn send(&self, msg: Action, _bus: &Bus) -> Result<(), error::Error<Action>> {
|
||||
match msg {
|
||||
Action::Init(..) => {
|
||||
self.stx.send(Event::Ready).unwrap();
|
||||
}
|
||||
Action::Close => {
|
||||
self.stx.send(Event::Exited).unwrap();
|
||||
}
|
||||
Action::Flush => {
|
||||
self.stx.send(Event::Flushed).unwrap();
|
||||
}
|
||||
Action::Sync => {
|
||||
self.stx.send(Event::Synchronized(Ok(()))).unwrap();
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
|
||||
println!("TestRelay::send {:?}", msg);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn send_msg(
|
||||
&self,
|
||||
mid: u64,
|
||||
msg: Box<dyn Message>,
|
||||
req: bool,
|
||||
_bus: &Bus,
|
||||
) -> Result<(), error::Error<Box<dyn Message>>> {
|
||||
println!("TestRelay::send_msg [{}] {:?}", mid, msg);
|
||||
if msg.type_tag().as_ref() == Msg::<i16>::type_tag_().as_ref() {
|
||||
self.stx
|
||||
.send(Event::Response(mid, Ok(Box::new(Msg(9u8)))))
|
||||
.unwrap();
|
||||
} else if msg.type_tag().as_ref() == Msg::<i32>::type_tag_().as_ref() {
|
||||
if req {
|
||||
self.stx
|
||||
.send(Event::Response(mid, Ok(Box::new(Msg(22u64)))))
|
||||
.unwrap();
|
||||
} else {
|
||||
self.stx
|
||||
.send(Event::Response(mid, Ok(Box::new(()))))
|
||||
.unwrap();
|
||||
}
|
||||
} else {
|
||||
panic!("unsupported message type {}", msg.type_tag());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl ReciveUntypedReceiver for TestRelay {
|
||||
type Stream = TestRelayRxStream;
|
||||
|
||||
fn event_stream(&self, _: Bus) -> Self::Stream {
|
||||
let mut rx = self.srx.lock().take().unwrap();
|
||||
|
||||
Box::pin(futures::stream::poll_fn(move |cx| rx.poll_recv(cx)))
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_relay() {
|
||||
let (stx, srx) = mpsc::unbounded_channel();
|
||||
let relay = TestRelay {
|
||||
stx,
|
||||
srx: Mutex::new(Some(srx)),
|
||||
};
|
||||
|
||||
let (b, poller) = Bus::build()
|
||||
.register_relay(relay)
|
||||
.register(TmpReceiver)
|
||||
.subscribe_async::<Msg<i32>>(
|
||||
1,
|
||||
receivers::BufferUnorderedConfig {
|
||||
buffer_size: 1,
|
||||
max_parallel: 1,
|
||||
},
|
||||
)
|
||||
.done()
|
||||
.build();
|
||||
|
||||
b.send(Msg(32i32)).await.unwrap();
|
||||
let res1: Msg<u8> = b.request(Msg(12i16), Default::default()).await.unwrap();
|
||||
let res2: Msg<u64> = b.request(Msg(12i32), Default::default()).await.unwrap();
|
||||
|
||||
assert_eq!(res1.0, 9u8);
|
||||
assert_eq!(res2.0, 22u64);
|
||||
|
||||
b.flush_all().await;
|
||||
b.close().await;
|
||||
poller.await;
|
||||
}
|
246
tests/test_req_resp.rs
Normal file
246
tests/test_req_resp.rs
Normal file
@ -0,0 +1,246 @@
|
||||
use core::f32;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use messagebus::{
|
||||
derive::Message,
|
||||
error::{self, StdSyncSendError},
|
||||
AsyncHandler, Bus, Message,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error, messagebus::derive::Error)]
|
||||
enum Error {
|
||||
#[error("Error({0})")]
|
||||
Error(anyhow::Error),
|
||||
}
|
||||
|
||||
impl<M: Message, E: StdSyncSendError> From<error::Error<M, E>> for Error {
|
||||
fn from(err: error::Error<M, E>) -> Self {
|
||||
Self::Error(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[message(clone)]
|
||||
struct MsgF64(pub f64);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[message(clone)]
|
||||
struct MsgF32(pub f32);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[message(clone)]
|
||||
struct MsgI32(pub i32);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[message(clone)]
|
||||
struct MsgU32(pub u32);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[message(clone)]
|
||||
struct MsgU16(pub u16);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[message(clone)]
|
||||
struct MsgI16(pub i16);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[message(clone)]
|
||||
struct MsgU8(pub u8);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[message(clone)]
|
||||
struct MsgI8(pub i8);
|
||||
|
||||
struct TmpReceiver1;
|
||||
struct TmpReceiver2;
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<MsgI32> for TmpReceiver1 {
|
||||
type Error = Error;
|
||||
type Response = MsgF32;
|
||||
|
||||
async fn handle(&self, msg: MsgI32, bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
let resp1 = bus
|
||||
.request::<_, MsgF32>(MsgI16(10i16), Default::default())
|
||||
.await?;
|
||||
let resp2 = bus
|
||||
.request::<_, MsgF32>(MsgU16(20u16), Default::default())
|
||||
.await?;
|
||||
|
||||
Ok(MsgF32(msg.0 as f32 + resp1.0 + resp2.0))
|
||||
}
|
||||
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
println!("TmpReceiver1 i32: sync");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<MsgU32> for TmpReceiver1 {
|
||||
type Error = Error;
|
||||
type Response = MsgF32;
|
||||
|
||||
async fn handle(&self, msg: MsgU32, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
Ok(MsgF32(msg.0 as _))
|
||||
}
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
println!("TmpReceiver1 u32: sync");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<MsgI16> for TmpReceiver1 {
|
||||
type Error = Error;
|
||||
type Response = MsgF32;
|
||||
|
||||
async fn handle(&self, msg: MsgI16, bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
let resp1 = bus
|
||||
.request::<_, MsgF32>(MsgI8(1i8), Default::default())
|
||||
.await?;
|
||||
let resp2 = bus
|
||||
.request::<_, MsgF32>(MsgU8(2u8), Default::default())
|
||||
.await?;
|
||||
|
||||
Ok(MsgF32(msg.0 as f32 + resp1.0 + resp2.0))
|
||||
}
|
||||
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
println!("TmpReceiver i16: sync");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<MsgU16> for TmpReceiver1 {
|
||||
type Error = Error;
|
||||
type Response = MsgF32;
|
||||
|
||||
async fn handle(&self, msg: MsgU16, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
Ok(MsgF32(msg.0 as _))
|
||||
}
|
||||
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
println!("TmpReceiver i16: sync");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<MsgI8> for TmpReceiver1 {
|
||||
type Error = Error;
|
||||
type Response = MsgF32;
|
||||
|
||||
async fn handle(&self, msg: MsgI8, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
Ok(MsgF32(msg.0 as _))
|
||||
}
|
||||
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
println!("TmpReceiver1 i8: sync");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<MsgU8> for TmpReceiver1 {
|
||||
type Error = Error;
|
||||
type Response = MsgF32;
|
||||
|
||||
async fn handle(&self, msg: MsgU8, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
Ok(MsgF32(msg.0 as _))
|
||||
}
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
println!("TmpReceiver1 u8: sync");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<MsgF64> for TmpReceiver2 {
|
||||
type Error = Error;
|
||||
type Response = MsgF64;
|
||||
|
||||
async fn handle(&self, msg: MsgF64, bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
let resp1 = bus
|
||||
.request::<_, MsgF32>(MsgI32(100i32), Default::default())
|
||||
.await?
|
||||
.0 as f64;
|
||||
let resp2 = bus
|
||||
.request::<_, MsgF32>(MsgU32(200u32), Default::default())
|
||||
.await?
|
||||
.0 as f64;
|
||||
let resp3 = bus
|
||||
.request::<_, MsgF32>(MsgF32(300f32), Default::default())
|
||||
.await?
|
||||
.0 as f64;
|
||||
|
||||
Ok(MsgF64(msg.0 + resp1 + resp2 + resp3))
|
||||
}
|
||||
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
println!("TmpReceiver1 f64: sync");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<MsgF32> for TmpReceiver2 {
|
||||
type Error = Error;
|
||||
type Response = MsgF32;
|
||||
|
||||
async fn handle(&self, msg: MsgF32, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
Ok(msg)
|
||||
}
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
println!("TmpReceiver2: f32: sync");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test() {
|
||||
let (b, poller) = Bus::build()
|
||||
.register(TmpReceiver1)
|
||||
.subscribe_async::<MsgI32>(8, Default::default())
|
||||
.subscribe_async::<MsgU32>(8, Default::default())
|
||||
.subscribe_async::<MsgI16>(8, Default::default())
|
||||
.subscribe_async::<MsgU16>(8, Default::default())
|
||||
.subscribe_async::<MsgI8>(8, Default::default())
|
||||
.subscribe_async::<MsgU8>(8, Default::default())
|
||||
.done()
|
||||
.register(TmpReceiver2)
|
||||
.subscribe_async::<MsgF32>(8, Default::default())
|
||||
.subscribe_async::<MsgF64>(8, Default::default())
|
||||
.done()
|
||||
.build();
|
||||
|
||||
let we_res = b
|
||||
.request_we::<_, MsgF64, Error>(MsgF64(1000f64), Default::default())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!((we_res.0 - 1633.0f64).abs() < f64::EPSILON);
|
||||
|
||||
let boxed_res = b
|
||||
.request_boxed(Box::new(MsgF64(1000.)), Default::default())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let val = boxed_res.as_any_ref().downcast_ref::<MsgF64>().unwrap().0;
|
||||
|
||||
assert!((val - 1633.0f64).abs() < f64::EPSILON);
|
||||
|
||||
b.flush_all().await;
|
||||
b.close().await;
|
||||
poller.await;
|
||||
}
|
85
tests/test_serde.rs
Normal file
85
tests/test_serde.rs
Normal file
@ -0,0 +1,85 @@
|
||||
use async_trait::async_trait;
|
||||
use messagebus::{
|
||||
derive::{Error as MbError, Message},
|
||||
error, AsyncHandler, Bus, Message, TypeTag,
|
||||
};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error, MbError)]
|
||||
enum Error {
|
||||
#[error("Error({0})")]
|
||||
Error(anyhow::Error),
|
||||
}
|
||||
|
||||
impl<M: Message> From<error::Error<M>> for Error {
|
||||
fn from(err: error::Error<M>) -> Self {
|
||||
Self::Error(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Message)]
|
||||
#[message(shared, clone)]
|
||||
#[type_tag("Msg")]
|
||||
struct Msg {
|
||||
test1: u32,
|
||||
test2: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Message)]
|
||||
#[message(shared, clone)]
|
||||
#[type_tag("MsgResponse")]
|
||||
struct MsgResponse {
|
||||
test1: u32,
|
||||
test2: String,
|
||||
}
|
||||
|
||||
struct TmpReceiver;
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<Msg> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = MsgResponse;
|
||||
|
||||
async fn handle(&self, msg: Msg, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
Ok(MsgResponse {
|
||||
test1: msg.test1 * 2,
|
||||
test2: msg.test2 + ", World!",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test() {
|
||||
let (b, poller) = Bus::build()
|
||||
.register(TmpReceiver)
|
||||
.subscribe_async::<Msg>(8, Default::default())
|
||||
.done()
|
||||
.build();
|
||||
|
||||
let type_tag: TypeTag = "Msg".into();
|
||||
let message = br#"{"test1":12,"test2":"Hello"}"#;
|
||||
|
||||
let json = &mut serde_json::Deserializer::from_slice(message);
|
||||
let mut de = <dyn erased_serde::Deserializer>::erase(json);
|
||||
|
||||
let val = b
|
||||
.request_deserialize(type_tag, &mut de, Default::default())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut buff: Vec<u8> = Vec::new();
|
||||
let json = &mut serde_json::Serializer::new(&mut buff);
|
||||
let mut ser = <dyn erased_serde::Serializer>::erase(json);
|
||||
val.as_shared_ref()
|
||||
.unwrap()
|
||||
.erased_serialize(&mut ser)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(val.type_tag(), TypeTag::from("MsgResponse"));
|
||||
assert_eq!(buff.as_slice(), br#"{"test1":24,"test2":"Hello, World!"}"#);
|
||||
|
||||
b.flush_all().await;
|
||||
b.close().await;
|
||||
poller.await;
|
||||
}
|
91
tests/test_shared.rs
Normal file
91
tests/test_shared.rs
Normal file
@ -0,0 +1,91 @@
|
||||
use std::sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc,
|
||||
};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use messagebus::{
|
||||
derive::{Error as MbError, Message},
|
||||
error, AsyncHandler, Bus, Message,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error, MbError)]
|
||||
enum Error {
|
||||
#[error("Error({0})")]
|
||||
Error(anyhow::Error),
|
||||
}
|
||||
|
||||
impl<M: Message> From<error::Error<M>> for Error {
|
||||
fn from(err: error::Error<M>) -> Self {
|
||||
Self::Error(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde_derive::Serialize, serde_derive::Deserialize, Message)]
|
||||
#[message(clone, shared)]
|
||||
struct Msg;
|
||||
|
||||
#[derive(Debug, Clone, serde_derive::Serialize, serde_derive::Deserialize, Message)]
|
||||
#[message(clone, shared)]
|
||||
struct SharedMsg<T>(T);
|
||||
|
||||
struct TmpReceiverContext {
|
||||
sync1: AtomicBool,
|
||||
sync2: AtomicBool,
|
||||
}
|
||||
|
||||
struct TmpReceiver {
|
||||
ctx: Arc<TmpReceiverContext>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<SharedMsg<f32>> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(
|
||||
&self,
|
||||
_msg: SharedMsg<f32>,
|
||||
_bus: &Bus,
|
||||
) -> Result<Self::Response, Self::Error> {
|
||||
self.ctx.sync1.store(true, Ordering::Relaxed);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<Msg> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, _msg: Msg, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
self.ctx.sync2.store(false, Ordering::Relaxed);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_shared() {
|
||||
let ctx = Arc::new(TmpReceiverContext {
|
||||
sync1: AtomicBool::new(false),
|
||||
sync2: AtomicBool::new(false),
|
||||
});
|
||||
|
||||
let (b, poller) = Bus::build()
|
||||
.register(TmpReceiver { ctx: ctx.clone() })
|
||||
.subscribe_async::<Msg>(8, Default::default())
|
||||
.subscribe_async::<SharedMsg<f32>>(8, Default::default())
|
||||
.done()
|
||||
.build();
|
||||
|
||||
b.send_one(Msg).await.unwrap();
|
||||
b.send_one(SharedMsg(0.0f32)).await.unwrap();
|
||||
|
||||
b.flush_all().await;
|
||||
b.close().await;
|
||||
poller.await;
|
||||
|
||||
assert!(ctx.sync1.load(Ordering::Relaxed));
|
||||
assert!(!ctx.sync2.load(Ordering::Relaxed));
|
||||
}
|
85
tests/test_sync.rs
Normal file
85
tests/test_sync.rs
Normal file
@ -0,0 +1,85 @@
|
||||
use messagebus::{
|
||||
derive::{Error as MbError, Message},
|
||||
error, Bus, Handler, Message, Module,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error, MbError)]
|
||||
enum Error {
|
||||
#[error("Error({0})")]
|
||||
Error(anyhow::Error),
|
||||
}
|
||||
|
||||
impl<M: Message> From<error::Error<M>> for Error {
|
||||
fn from(err: error::Error<M>) -> Self {
|
||||
Self::Error(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
struct MsgF32(pub f32);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
struct MsgU32(pub u32);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
struct MsgU16(pub u16);
|
||||
|
||||
struct TmpReceiver;
|
||||
|
||||
impl Handler<MsgF32> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
fn handle(&self, msg: MsgF32, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
println!("---> f32 {:?}", msg);
|
||||
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
|
||||
println!("done");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler<MsgU16> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
fn handle(&self, msg: MsgU16, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
println!("---> u16 {:?}", msg);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler<MsgU32> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
fn handle(&self, msg: MsgU32, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
println!("---> u32 {:?}", msg);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn module() -> Module {
|
||||
Module::new()
|
||||
.register(TmpReceiver)
|
||||
.subscribe_sync::<MsgF32>(8, Default::default())
|
||||
.subscribe_sync::<MsgU16>(8, Default::default())
|
||||
.subscribe_sync::<MsgU32>(8, Default::default())
|
||||
.done()
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_sync() {
|
||||
let (b, poller) = Bus::build().add_module(module()).build();
|
||||
|
||||
b.send(MsgF32(32f32)).await.unwrap();
|
||||
b.send(MsgU16(11u16)).await.unwrap();
|
||||
b.send(MsgU32(32u32)).await.unwrap();
|
||||
|
||||
b.flush_and_sync_all(false).await;
|
||||
b.close().await;
|
||||
poller.await;
|
||||
}
|
Loading…
Reference in New Issue
Block a user