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
|
/target
|
||||||
|
/crates/*/target
|
||||||
Cargo.lock
|
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]
|
[package]
|
||||||
name = "messagebus"
|
name = "messagebus"
|
||||||
version = "0.4.6"
|
version = "0.9.13"
|
||||||
authors = ["Andrey Tkachenko <andrey@aidev.ru>"]
|
authors = ["Andrey Tkachenko <andrey@aidev.ru>"]
|
||||||
repository = "https://github.com/andreytkachenko/messagebus.git"
|
repository = "https://github.com/andreytkachenko/messagebus.git"
|
||||||
keywords = ["futures", "async", "tokio", "message", "bus"]
|
keywords = ["futures", "async", "tokio", "message", "bus"]
|
||||||
@ -10,13 +10,34 @@ license = "MIT OR Apache-2.0"
|
|||||||
exclude = [".gitignore", ".cargo/config", ".github/**", "codecov.yml"]
|
exclude = [".gitignore", ".cargo/config", ".github/**", "codecov.yml"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
members = ["crates/remote", "crates/derive"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tokio = { version = "0.2", features = ["parking_lot", "rt-threaded", "sync", "stream", "blocking"] }
|
messagebus_derive = "0.2.5"
|
||||||
parking_lot = "0.11.1"
|
|
||||||
async-trait = "0.1.42"
|
tokio = { version = "1", features = ["parking_lot", "rt-multi-thread", "sync", "time"] }
|
||||||
futures = "0.3.8"
|
parking_lot = "0.11"
|
||||||
anyhow = "1.0.34"
|
async-trait = "0.1"
|
||||||
crossbeam = "0.8.0"
|
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]
|
[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
|
### Basics
|
||||||
1. Can deliver messages between actors using receivers (usually a queue implementations)
|
1. Can deliver messages between actors using receivers (usually a queue implementations)
|
||||||
2. Messages distincts and delivers by TypeId
|
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:
|
4. There are different kind of receivers implemented:
|
||||||
- BufferUnordered Receiver (in sync and async version depending by handler)
|
- BufferUnordered Receiver (sync and async)
|
||||||
- Synchronized (also sync and async) if receiving part needs syncronization
|
- Synchronized (sync and async)
|
||||||
- SynchronizeBuffered (also sync and async)
|
- BatchedBufferUnordered Receiver (sync and async)
|
||||||
here are the implmented handlers definitions:
|
- BatchedSynchronized (sync and async)
|
||||||
```rust
|
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 {
|
pub trait Handler<M: Message>: Send + Sync {
|
||||||
fn handle(&self, msg: M, bus: &Bus) -> anyhow::Result<()>;
|
type Error: StdSyncSendError;
|
||||||
fn sync(&self, _bus: &Bus) -> anyhow::Result<()> {Ok(())}
|
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]
|
#[async_trait]
|
||||||
pub trait AsyncHandler<M: Message>: Send + Sync {
|
pub trait AsyncHandler<M: Message>: Send + Sync {
|
||||||
async fn handle(&self, msg: M, bus: &Bus) -> anyhow::Result<()>;
|
type Error: StdSyncSendError;
|
||||||
async fn sync(&self, _bus: &Bus) -> anyhow::Result<()> {Ok(())}
|
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 {
|
pub trait SynchronizedHandler<M: Message>: Send {
|
||||||
fn handle(&mut self, msg: M, bus: &Bus) -> anyhow::Result<()>;
|
type Error: StdSyncSendError;
|
||||||
fn sync(&mut self, _bus: &Bus) -> anyhow::Result<()> {Ok(())}
|
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]
|
#[async_trait]
|
||||||
pub trait AsyncSynchronizedHandler<M: Message>: Send {
|
pub trait AsyncSynchronizedHandler<M: Message>: Send {
|
||||||
async fn handle(&mut self, msg: M, bus: &Bus) -> anyhow::Result<()>;
|
type Error: StdSyncSendError;
|
||||||
async fn sync(&mut self, _bus: &Bus) -> anyhow::Result<()> {Ok(())}
|
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 {
|
pub trait BatchSynchronizedHandler<M: Message>: Send {
|
||||||
fn handle(&mut self, msg: Vec<M>, bus: &Bus) -> anyhow::Result<()>;
|
type Error: StdSyncSendError + Clone;
|
||||||
fn sync(&mut self, _bus: &Bus) -> anyhow::Result<()> {Ok(())}
|
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]
|
#[async_trait]
|
||||||
pub trait AsyncBatchSynchronizedHandler<M: Message>: Send {
|
pub trait AsyncBatchSynchronizedHandler<M: Message>: Send {
|
||||||
async fn handle(&mut self, msg: Vec<M>, bus: &Bus) -> anyhow::Result<()>;
|
type Error: StdSyncSendError + Clone;
|
||||||
async fn sync(&mut self, _bus: &Bus) -> anyhow::Result<()> {Ok(())}
|
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:
|
6. Implemented handler kinds:
|
||||||
1. No Synchronization needed (Handler is `Send` + `Sync`)
|
1. No Synchronization needed (Handler implements `Send` and `Sync`)
|
||||||
* Not batched operations **(implemented)**
|
* Not batched operations
|
||||||
- sync (spawn_blocking)
|
- sync (spawn_blocking)
|
||||||
- async (spawn)
|
- async (spawn)
|
||||||
* Batched
|
* Batched
|
||||||
- sync (spawn_blocking)
|
- sync (spawn_blocking)
|
||||||
- async (spawn)
|
- async (spawn)
|
||||||
2. Synchronization needed (Handler is `Sync` + `!Send`)
|
2. Synchronization needed (Handler implements only `Send` but not implements `Sync`)
|
||||||
* 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`)
|
|
||||||
* Not batched operations
|
* Not batched operations
|
||||||
- sync (spawn_blocking)
|
- sync (spawn_blocking)
|
||||||
- async (spawn)
|
- async (spawn)
|
||||||
@ -79,16 +130,28 @@ pub trait AsyncBatchSynchronizedHandler<M: Message>: Send {
|
|||||||
- sync (spawn_blocking)
|
- sync (spawn_blocking)
|
||||||
- async (spawn)
|
- 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
|
```rust
|
||||||
use messagebus::{Bus, AsyncHandler, Result as MbusResult, receivers};
|
use messagebus::{error::Error, receivers, AsyncHandler, Bus};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
|
||||||
struct TmpReceiver;
|
struct TmpReceiver;
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl AsyncHandler<i32> for TmpReceiver {
|
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);
|
println!("---> i32 {}", msg);
|
||||||
|
|
||||||
bus.send(2i64).await?;
|
bus.send(2i64).await?;
|
||||||
@ -99,7 +162,10 @@ impl AsyncHandler<i32> for TmpReceiver {
|
|||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl AsyncHandler<i64> for TmpReceiver {
|
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);
|
println!("---> i64 {}", msg);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -110,12 +176,22 @@ impl AsyncHandler<i64> for TmpReceiver {
|
|||||||
async fn main() {
|
async fn main() {
|
||||||
let (b, poller) = Bus::build()
|
let (b, poller) = Bus::build()
|
||||||
.register(TmpReceiver)
|
.register(TmpReceiver)
|
||||||
.subscribe::<i32, receivers::BufferUnorderedAsync<_>>(Default::default())
|
.subscribe::<i32, receivers::BufferUnorderedAsync<_>, _, _>(8, Default::default())
|
||||||
.subscribe::<i64, receivers::BufferUnorderedAsync<_>>(Default::default())
|
.subscribe::<i64, receivers::BufferUnorderedAsync<_>, _, _>(8, Default::default())
|
||||||
.done()
|
.done()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
b.send(1i32).await.unwrap();
|
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 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 TmpReceiver;
|
||||||
struct TmpReceiver2;
|
struct TmpReceiver2;
|
||||||
|
|
||||||
#[async_trait]
|
#[derive(Debug, Clone, Message)]
|
||||||
impl AsyncHandler<f32> for TmpReceiver {
|
#[message(clone)]
|
||||||
async fn handle(&self, msg: f32, bus: &Bus) -> MbusResult {
|
struct MsgF32(f32);
|
||||||
bus.send(1u16).await?;
|
|
||||||
|
|
||||||
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl AsyncHandler<u16> for TmpReceiver {
|
impl AsyncHandler<MsgU16> for TmpReceiver {
|
||||||
async fn handle(&self, msg: u16, bus: &Bus) -> MbusResult {
|
type Error = Error;
|
||||||
bus.send(2u32).await?;
|
type Response = ();
|
||||||
println!("---> u16 {}", msg);
|
|
||||||
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl AsyncHandler<u32> for TmpReceiver {
|
impl AsyncHandler<MsgU32> for TmpReceiver {
|
||||||
async fn handle(&self, msg: u32, bus: &Bus) -> MbusResult {
|
type Error = Error;
|
||||||
bus.send(3i32).await?;
|
type Response = ();
|
||||||
println!("---> u32 {}", msg);
|
|
||||||
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl AsyncHandler<i32> for TmpReceiver {
|
impl AsyncHandler<MsgI32> for TmpReceiver {
|
||||||
async fn handle(&self, msg: i32, bus: &Bus) -> MbusResult {
|
type Error = Error;
|
||||||
bus.send(4i16).await?;
|
type Response = ();
|
||||||
println!("---> i32 {}", msg);
|
|
||||||
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl AsyncHandler<i16> for TmpReceiver {
|
impl AsyncHandler<MsgI16> for TmpReceiver {
|
||||||
async fn handle(&self, msg: i16, _bus: &Bus) -> MbusResult {
|
type Error = Error;
|
||||||
println!("---> i16 {}", msg);
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl AsyncHandler<i32> for TmpReceiver2 {
|
impl AsyncHandler<MsgI32> for TmpReceiver2 {
|
||||||
async fn handle(&self, msg: i32, bus: &Bus) -> MbusResult {
|
type Error = Error;
|
||||||
bus.send(5i16).await?;
|
type Response = ();
|
||||||
println!("---> 2 i32 {}", msg);
|
|
||||||
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Handler<i16> for TmpReceiver2 {
|
impl Handler<MsgI16> for TmpReceiver2 {
|
||||||
fn handle(&self, msg: i16, _bus: &Bus) -> MbusResult {
|
type Error = Error;
|
||||||
println!("---> 2 i16 {}", msg);
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -74,20 +168,32 @@ impl Handler<i16> for TmpReceiver2 {
|
|||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
|
env_logger::init();
|
||||||
|
|
||||||
let (b, poller) = Bus::build()
|
let (b, poller) = Bus::build()
|
||||||
.register(TmpReceiver)
|
.register(TmpReceiver)
|
||||||
.subscribe::<f32, receivers::BufferUnorderedAsync<_>>(Default::default())
|
.subscribe_async::<MsgF32>(8, Default::default())
|
||||||
.subscribe::<u16, receivers::BufferUnorderedAsync<_>>(Default::default())
|
.subscribe_async::<MsgU16>(8, Default::default())
|
||||||
.subscribe::<u32, receivers::BufferUnorderedAsync<_>>(Default::default())
|
.subscribe_async::<MsgU32>(8, Default::default())
|
||||||
.subscribe::<i32, receivers::BufferUnorderedAsync<_>>(Default::default())
|
.subscribe_async::<MsgI32>(8, Default::default())
|
||||||
.subscribe::<i16, receivers::BufferUnorderedAsync<_>>(Default::default())
|
.subscribe_async::<MsgI16>(8, Default::default())
|
||||||
.done()
|
.done()
|
||||||
.register(TmpReceiver2)
|
.register(TmpReceiver2)
|
||||||
.subscribe::<i32, receivers::BufferUnorderedAsync<_>>(Default::default())
|
.subscribe_async::<MsgI32>(8, Default::default())
|
||||||
.subscribe::<i16, receivers::BufferUnorderedSync<_>>(Default::default())
|
.subscribe_sync::<MsgI16>(8, Default::default())
|
||||||
.done()
|
.done()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
b.send(0f32).await.unwrap();
|
b.send(MsgF32(0.)).await.unwrap();
|
||||||
poller.await
|
|
||||||
|
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;
|
struct TmpReceiver;
|
||||||
|
|
||||||
impl Handler<f32> for TmpReceiver {
|
impl Handler<MsgF32> for TmpReceiver {
|
||||||
fn handle(&self, msg: f32, _bus: &Bus) -> MbusResult {
|
type Error = Error;
|
||||||
println!("---> f32 {}", msg);
|
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));
|
std::thread::sleep(std::time::Duration::from_secs(5));
|
||||||
|
|
||||||
@ -14,33 +42,51 @@ impl Handler<f32> for TmpReceiver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Handler<u16> for TmpReceiver {
|
impl Handler<MsgU16> for TmpReceiver {
|
||||||
fn handle(&self, msg: u16, _bus: &Bus) -> MbusResult {
|
type Error = Error;
|
||||||
println!("---> u16 {}", msg);
|
type Response = ();
|
||||||
|
|
||||||
|
fn handle(&self, msg: MsgU16, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||||
|
println!("---> u16 {:?}", msg);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Handler<u32> for TmpReceiver {
|
impl Handler<MsgU32> for TmpReceiver {
|
||||||
fn handle(&self, msg: u32, _bus: &Bus) -> MbusResult {
|
type Error = Error;
|
||||||
println!("---> u32 {}", msg);
|
type Response = ();
|
||||||
|
|
||||||
|
fn handle(&self, msg: MsgU32, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||||
|
println!("---> u32 {:?}", msg);
|
||||||
Ok(())
|
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]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
let (b, poller) = Bus::build()
|
let (b, poller) = Bus::build().add_module(module()).build();
|
||||||
.register(TmpReceiver)
|
|
||||||
.subscribe::<f32, receivers::BufferUnorderedSync<_>>(Default::default())
|
|
||||||
.subscribe::<u16, receivers::BufferUnorderedSync<_>>(Default::default())
|
|
||||||
.subscribe::<u32, receivers::BufferUnorderedSync<_>>(Default::default())
|
|
||||||
.done()
|
|
||||||
.build();
|
|
||||||
|
|
||||||
b.send(32f32).await.unwrap();
|
b.send(MsgF32(32f32)).await.unwrap();
|
||||||
b.send(11u16).await.unwrap();
|
b.send(MsgU16(11u16)).await.unwrap();
|
||||||
b.send(32u32).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 async_trait::async_trait;
|
||||||
use receivers::SynchronizedConfig;
|
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;
|
struct TmpReceiver;
|
||||||
|
|
||||||
impl SynchronizedHandler<f32> for TmpReceiver {
|
impl SynchronizedHandler<MsgF32> for TmpReceiver {
|
||||||
fn handle(&mut self, msg: f32, _bus: &Bus) -> MbusResult {
|
type Error = Error;
|
||||||
println!("---> f32 {}", msg);
|
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");
|
println!("done");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SynchronizedHandler<i16> for TmpReceiver {
|
#[async_trait]
|
||||||
fn handle(&mut self, msg: i16, _bus: &Bus) -> MbusResult {
|
impl AsyncSynchronizedHandler<MsgI16> for TmpReceiver {
|
||||||
println!("---> i16 {}", msg);
|
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");
|
println!("done");
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -29,29 +56,42 @@ impl SynchronizedHandler<i16> for TmpReceiver {
|
|||||||
async fn main() {
|
async fn main() {
|
||||||
let (b, poller) = Bus::build()
|
let (b, poller) = Bus::build()
|
||||||
.register_unsync(TmpReceiver)
|
.register_unsync(TmpReceiver)
|
||||||
.subscribe::<f32, receivers::SynchronizedSync<_>>(SynchronizedConfig { buffer_size: 1 })
|
.subscribe_sync::<MsgF32>(8, Default::default())
|
||||||
.subscribe::<i16, receivers::SynchronizedSync<_>>(Default::default())
|
.subscribe_async::<MsgI16>(8, Default::default())
|
||||||
.done()
|
.done()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
b.send(12.0f32).await.unwrap();
|
b.send(MsgF32(12.0f32)).await.unwrap();
|
||||||
b.send(1i16).await.unwrap();
|
b.send(MsgI16(1i16)).await.unwrap();
|
||||||
b.send(12.0f32).await.unwrap();
|
b.send(MsgF32(12.0f32)).await.unwrap();
|
||||||
b.send(1i16).await.unwrap();
|
b.send(MsgI16(1i16)).await.unwrap();
|
||||||
b.send(12.0f32).await.unwrap();
|
b.send(MsgF32(12.0f32)).await.unwrap();
|
||||||
b.send(1i16).await.unwrap();
|
b.send(MsgI16(1i16)).await.unwrap();
|
||||||
b.send(12.0f32).await.unwrap();
|
b.send(MsgF32(12.0f32)).await.unwrap();
|
||||||
b.send(1i16).await.unwrap();
|
b.send(MsgI16(1i16)).await.unwrap();
|
||||||
b.send(12.0f32).await.unwrap();
|
b.send(MsgF32(12.0f32)).await.unwrap();
|
||||||
b.send(1i16).await.unwrap();
|
b.send(MsgI16(1i16)).await.unwrap();
|
||||||
b.send(12.0f32).await.unwrap();
|
b.send(MsgF32(12.0f32)).await.unwrap();
|
||||||
b.send(1i16).await.unwrap();
|
b.send(MsgI16(1i16)).await.unwrap();
|
||||||
b.send(12.0f32).await.unwrap();
|
b.send(MsgF32(12.0f32)).await.unwrap();
|
||||||
b.send(1i16).await.unwrap();
|
b.send(MsgI16(1i16)).await.unwrap();
|
||||||
b.send(12.0f32).await.unwrap();
|
b.send(MsgF32(12.0f32)).await.unwrap();
|
||||||
b.send(1i16).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;
|
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 futures::{Future, FutureExt};
|
||||||
use receiver::ReceiverTrait;
|
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
receiver::{self, Receiver},
|
error::StdSyncSendError,
|
||||||
Bus, BusInner, Message, Untyped,
|
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> {
|
static RECEVIER_ID_SEQ: AtomicU64 = AtomicU64::new(1);
|
||||||
fn subscribe(
|
|
||||||
self,
|
|
||||||
) -> (
|
|
||||||
Arc<dyn ReceiverTrait>,
|
|
||||||
Box<
|
|
||||||
dyn FnOnce(Untyped) -> Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>,
|
|
||||||
>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ReceiverSubscriberBuilder<M, T: 'static> {
|
pub trait ReceiverSubscriberBuilder<T, M, R, E>:
|
||||||
type Entry: ReceiverSubscriber<T>;
|
SendUntypedReceiver + SendTypedReceiver<M> + ReciveTypedReceiver<R, E>
|
||||||
|
where
|
||||||
|
T: 'static,
|
||||||
|
M: Message,
|
||||||
|
R: Message,
|
||||||
|
E: StdSyncSendError,
|
||||||
|
{
|
||||||
type Config: Default;
|
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 SyncEntry;
|
||||||
pub struct UnsyncEntry;
|
pub struct UnsyncEntry;
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct RegisterEntry<K, T> {
|
pub struct RegisterEntry<K, T, F, P, B> {
|
||||||
item: Untyped,
|
item: Untyped,
|
||||||
builder: BusBuilder,
|
payload: B,
|
||||||
receivers: HashMap<
|
builder: F,
|
||||||
TypeId,
|
poller: P,
|
||||||
Vec<(
|
receivers: HashSet<Receiver>,
|
||||||
Receiver,
|
pollers: Vec<BusPollerCallback>,
|
||||||
Box<
|
|
||||||
dyn FnOnce(
|
|
||||||
Untyped,
|
|
||||||
)
|
|
||||||
-> Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>,
|
|
||||||
>,
|
|
||||||
)>,
|
|
||||||
>,
|
|
||||||
_m: PhantomData<(K, T)>,
|
_m: PhantomData<(K, T)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K, T: 'static> RegisterEntry<K, T> {
|
impl<K, T: 'static, F, P, B> RegisterEntry<K, T, F, P, B>
|
||||||
pub fn done(self) -> BusBuilder {
|
where
|
||||||
let mut builder = self.builder;
|
F: FnMut(&mut B, Receiver),
|
||||||
|
P: FnMut(&mut B, BusPollerCallback),
|
||||||
for (tid, v) in self.receivers {
|
{
|
||||||
for (r, poller) in v {
|
pub fn done(mut self) -> B {
|
||||||
let poller = poller(self.item.clone());
|
for r in self.receivers {
|
||||||
|
(self.builder)(&mut self.payload, r);
|
||||||
builder.add_recevier((tid, r), poller);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
builder
|
for p in self.pollers {
|
||||||
|
(self.poller)(&mut self.payload, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.payload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Send + 'static> RegisterEntry<UnsyncEntry, T> {
|
impl<T, F, P, B> RegisterEntry<UnsyncEntry, T, F, P, B> {
|
||||||
pub fn subscribe<M, R>(mut self, cfg: R::Config) -> Self
|
pub fn subscribe<M, S, R, E>(mut self, queue: u64, cfg: S::Config) -> Self
|
||||||
where
|
where
|
||||||
T: Send + 'static,
|
T: Send + 'static,
|
||||||
M: Message + 'static,
|
M: Message,
|
||||||
R: ReceiverSubscriberBuilder<M, T> + 'static,
|
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);
|
let receiver = Receiver::new::<M, R, E, S>(
|
||||||
self.receivers
|
RECEVIER_ID_SEQ.fetch_add(1, Ordering::Relaxed),
|
||||||
.entry(TypeId::of::<M>())
|
queue,
|
||||||
.or_insert_with(Vec::new)
|
true,
|
||||||
.push((receiver, poller));
|
inner,
|
||||||
|
);
|
||||||
|
|
||||||
|
let poller2 = receiver.start_polling();
|
||||||
|
self.receivers.insert(receiver);
|
||||||
|
self.pollers.push(poller(self.item.clone()));
|
||||||
|
self.pollers.push(poller2);
|
||||||
|
|
||||||
self
|
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> {
|
impl<T, F, P, B> RegisterEntry<SyncEntry, T, F, P, B> {
|
||||||
pub fn subscribe<M, R>(mut self, cfg: R::Config) -> Self
|
pub fn subscribe<M, S, R, E>(mut self, queue: u64, cfg: S::Config) -> Self
|
||||||
where
|
where
|
||||||
T: Send + 'static,
|
T: Send + Sync + 'static,
|
||||||
M: Message + 'static,
|
M: Message,
|
||||||
R: ReceiverSubscriberBuilder<M, T> + 'static,
|
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);
|
let receiver = Receiver::new::<M, R, E, S>(
|
||||||
self.receivers
|
RECEVIER_ID_SEQ.fetch_add(1, Ordering::Relaxed),
|
||||||
.entry(TypeId::of::<M>())
|
queue,
|
||||||
.or_insert_with(Vec::new)
|
true,
|
||||||
.push((receiver, poller));
|
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
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BusBuilder {
|
pub struct BusBuilder {
|
||||||
receivers: Vec<(TypeId, Receiver)>,
|
inner: Module,
|
||||||
pollings: Vec<Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BusBuilder {
|
impl BusBuilder {
|
||||||
pub fn new() -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
receivers: Vec::new(),
|
inner: Module::new(),
|
||||||
pollings: Vec::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 {
|
RegisterEntry {
|
||||||
item: Arc::new(item) as Untyped,
|
item: Arc::new(item) as Untyped,
|
||||||
builder: self,
|
payload: self,
|
||||||
receivers: HashMap::new(),
|
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(),
|
_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 {
|
RegisterEntry {
|
||||||
item: Arc::new(Mutex::new(item)) as Untyped,
|
item: Arc::new(Mutex::new(item)) as Untyped,
|
||||||
builder: self,
|
payload: self,
|
||||||
receivers: HashMap::new(),
|
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(),
|
_m: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_recevier(
|
pub fn add_module(mut self, module: Module) -> Self {
|
||||||
&mut self,
|
self.inner = self.inner.add_module(module);
|
||||||
val: (TypeId, Receiver),
|
|
||||||
poller: Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>,
|
self
|
||||||
) {
|
|
||||||
self.receivers.push(val);
|
|
||||||
self.pollings.push(poller);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self) -> (Bus, impl Future<Output = ()>) {
|
pub fn build(self) -> (Bus, impl Future<Output = ()>) {
|
||||||
let bus = Bus {
|
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());
|
let mut futs = Vec::with_capacity(self.inner.pollings.len() * 2);
|
||||||
for poller in self.pollings {
|
for poller in self.inner.pollings {
|
||||||
futs.push(tokio::task::spawn(poller(bus.clone())));
|
futs.push(tokio::task::spawn(poller(bus.clone())));
|
||||||
}
|
}
|
||||||
|
|
||||||
let poller = futures::future::join_all(futs).map(|_| ()).map(|_| ());
|
let poller = futures::future::join_all(futs).map(|_| ()).map(|_| ());
|
||||||
|
|
||||||
|
bus.init();
|
||||||
|
|
||||||
(bus, poller)
|
(bus, poller)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
524
src/envelop.rs
524
src/envelop.rs
@ -1,102 +1,462 @@
|
|||||||
use core::any::{self, Any};
|
use core::{
|
||||||
use core::fmt;
|
any::{type_name, Any},
|
||||||
// use erased_serde::{Deserializer, Serialize};
|
fmt,
|
||||||
|
};
|
||||||
|
|
||||||
pub trait Message: Any + fmt::Debug/*Serialize + for<'a> Deserializer<'a> + */ + Unpin + Clone + Send + Sync + 'static {}
|
use std::{alloc::Layout, borrow::Cow, sync::Arc};
|
||||||
impl<T: Any + fmt::Debug + Unpin + Clone + Send + Sync> Message for T {}
|
|
||||||
|
|
||||||
trait SafeMessage: Any + fmt::Debug/*+ Serialize + for<'a> Deserializer<'a>*/ + Unpin + Send + Sync + 'static {
|
pub trait MessageBounds: TypeTagged + fmt::Debug + Unpin + Send + Sync + 'static {}
|
||||||
fn type_name(&self) -> &'static str;
|
impl<T: TypeTagged + fmt::Debug + Unpin + Send + Sync + 'static> MessageBounds for T {}
|
||||||
fn clone_boxed(&self) -> Box<dyn SafeMessage>;
|
|
||||||
|
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 {
|
pub trait Message: MessageBounds {
|
||||||
fn type_name(&self) -> &'static str {
|
fn as_any_ref(&self) -> &dyn Any;
|
||||||
any::type_name::<T>()
|
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> {
|
gen_impls!{ $($rest)* }
|
||||||
Box::new(self.clone())
|
};
|
||||||
|
|
||||||
|
($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 {
|
impl<T: TypeTagged> TypeTagged for Box<T> {
|
||||||
// inner: Box<dyn SafeMessage>,
|
fn type_tag_() -> TypeTag {
|
||||||
// }
|
T::type_tag_()
|
||||||
|
}
|
||||||
|
|
||||||
// impl BoxedEnvelop {
|
fn type_tag(&self) -> TypeTag {
|
||||||
// pub fn from_message<M: Message>(m: M) -> Self {
|
T::type_tag(&*self)
|
||||||
// Self {
|
}
|
||||||
// inner: Box::new(m)
|
fn type_name(&self) -> Cow<str> {
|
||||||
// }
|
T::type_name(&*self)
|
||||||
// }
|
}
|
||||||
|
fn type_layout(&self) -> Layout {
|
||||||
// pub fn as_ref(&self) -> Envelop<'_> {
|
Layout::for_value(self)
|
||||||
// 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(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'inner> Envelop<'inner> {
|
impl Message for () {
|
||||||
// pub fn new<T: Message>(inner: &'inner T) -> Self {
|
fn as_any_ref(&self) -> &dyn Any {
|
||||||
// Self { inner }
|
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]
|
fn as_shared_ref(&self) -> Option<&dyn SharedMessage> {
|
||||||
// pub fn downcast_to<T: 'static>(&self) -> Option<&T> {
|
Some(self)
|
||||||
// if self.inner.type_id() == TypeId::of::<T>() {
|
}
|
||||||
// unsafe { Some(&*(self.inner as *const dyn SafeMessage as *const T)) }
|
fn as_shared_mut(&mut self) -> Option<&mut dyn SharedMessage> {
|
||||||
// } else {
|
Some(self)
|
||||||
// None
|
}
|
||||||
// }
|
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]
|
into.replace(());
|
||||||
// pub fn type_id(&self) -> TypeId {
|
true
|
||||||
// self.inner.type_id()
|
}
|
||||||
// }
|
fn try_clone_boxed(&self) -> Option<Box<dyn Message>> {
|
||||||
|
Some(Box::new(()))
|
||||||
|
}
|
||||||
|
|
||||||
// #[inline]
|
fn try_clone(&self) -> Option<Self> {
|
||||||
// pub fn type_name(&self) -> &'static str {
|
Some(())
|
||||||
// self.inner.type_name()
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
// #[inline]
|
|
||||||
// pub fn clone_boxed(&self) -> BoxedEnvelop {
|
|
||||||
// BoxedEnvelop {
|
|
||||||
// inner: self.inner.clone_boxed(),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl<'inner> serde::Serialize for Envelop<'inner> {
|
pub trait IntoBoxedMessage {
|
||||||
// fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
fn into_boxed(self) -> Box<dyn Message>;
|
||||||
// erased_serde::serialize(self.inner, serializer)
|
}
|
||||||
|
|
||||||
|
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 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 {
|
pub trait Handler<M: Message>: Send + Sync {
|
||||||
fn handle(&self, msg: M, bus: &Bus) -> anyhow::Result<()>;
|
type Error: StdSyncSendError;
|
||||||
fn sync(&self, _bus: &Bus) -> anyhow::Result<()> {
|
type Response: Message;
|
||||||
|
|
||||||
|
fn handle(&self, msg: M, bus: &Bus) -> Result<Self::Response, Self::Error>;
|
||||||
|
fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait AsyncHandler<M: Message>: Send + Sync {
|
pub trait AsyncHandler<M: Message>: Send + Sync {
|
||||||
async fn handle(&self, msg: M, bus: &Bus) -> anyhow::Result<()>;
|
type Error: StdSyncSendError;
|
||||||
async fn sync(&self, _bus: &Bus) -> anyhow::Result<()> {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait SynchronizedHandler<M: Message>: Send {
|
pub trait SynchronizedHandler<M: Message>: Send {
|
||||||
fn handle(&mut self, msg: M, bus: &Bus) -> anyhow::Result<()>;
|
type Error: StdSyncSendError;
|
||||||
fn sync(&mut self, _bus: &Bus) -> anyhow::Result<()> {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait AsyncSynchronizedHandler<M: Message>: Send {
|
pub trait AsyncSynchronizedHandler<M: Message>: Send {
|
||||||
async fn handle(&mut self, msg: M, bus: &Bus) -> anyhow::Result<()>;
|
type Error: StdSyncSendError;
|
||||||
async fn sync(&mut self, _bus: &Bus) -> anyhow::Result<()> {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait BatchHandler<M: Message>: Send + Sync {
|
pub trait BatchHandler<M: Message>: Send + Sync {
|
||||||
fn handle(&self, msg: Vec<M>, bus: &Bus) -> anyhow::Result<()>;
|
type Error: StdSyncSendError + Clone;
|
||||||
fn sync(&self, _bus: &Bus) -> anyhow::Result<()> {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait AsyncBatchHandler<M: Message>: Send + Sync {
|
pub trait AsyncBatchHandler<M: Message>: Send + Sync {
|
||||||
async fn handle(&self, msg: Vec<M>, bus: &Bus) -> anyhow::Result<()>;
|
type Error: StdSyncSendError + Clone;
|
||||||
async fn sync(&self, _bus: &Bus) -> anyhow::Result<()> {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait BatchSynchronizedHandler<M: Message>: Send {
|
pub trait BatchSynchronizedHandler<M: Message>: Send {
|
||||||
fn handle(&mut self, msg: Vec<M>, bus: &Bus) -> anyhow::Result<()>;
|
type Error: StdSyncSendError + Clone;
|
||||||
fn sync(&mut self, _bus: &Bus) -> anyhow::Result<()> {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait AsyncBatchSynchronizedHandler<M: Message>: Send {
|
pub trait AsyncBatchSynchronizedHandler<M: Message>: Send {
|
||||||
async fn handle(&mut self, msg: Vec<M>, bus: &Bus) -> anyhow::Result<()>;
|
type Error: StdSyncSendError + Clone;
|
||||||
async fn sync(&mut self, _bus: &Bus) -> anyhow::Result<()> {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait LocalHandler<M: Message> {
|
pub trait LocalHandler<M: Message> {
|
||||||
fn handle(&mut self, msg: Vec<M>, bus: &Bus) -> anyhow::Result<()>;
|
type Error: StdSyncSendError;
|
||||||
fn sync(&mut self, _bus: &Bus) -> anyhow::Result<()> {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait LocalAsyncHandler<M: Message> {
|
pub trait LocalAsyncHandler<M: Message> {
|
||||||
async fn handle(&mut self, msg: Vec<M>, bus: &Bus) -> anyhow::Result<()>;
|
type Error: StdSyncSendError;
|
||||||
async fn sync(&mut self, _bus: &Bus) -> anyhow::Result<()> {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait LocalBatchHandler<M: Message> {
|
pub trait LocalBatchHandler<M: Message> {
|
||||||
fn handle(&mut self, msg: Vec<M>, bus: &Bus) -> anyhow::Result<()>;
|
type Error: StdSyncSendError + Clone;
|
||||||
fn sync(&mut self, _bus: &Bus) -> anyhow::Result<()> {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait LocalAsyncBatchHandler<M: Message> {
|
pub trait LocalAsyncBatchHandler<M: Message> {
|
||||||
async fn handle(&mut self, msg: Vec<M>, bus: &Bus) -> anyhow::Result<()>;
|
type Error: StdSyncSendError + Clone;
|
||||||
async fn sync(&mut self, _bus: &Bus) -> anyhow::Result<()> {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
875
src/lib.rs
875
src/lib.rs
@ -1,108 +1,124 @@
|
|||||||
mod builder;
|
mod builder;
|
||||||
mod envelop;
|
mod envelop;
|
||||||
|
pub mod error;
|
||||||
mod handler;
|
mod handler;
|
||||||
pub mod msgs;
|
|
||||||
mod receiver;
|
mod receiver;
|
||||||
pub mod receivers;
|
pub mod receivers;
|
||||||
|
mod relay;
|
||||||
|
mod stats;
|
||||||
mod trait_object;
|
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;
|
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 handler::*;
|
||||||
pub use receiver::SendError;
|
pub use receiver::{
|
||||||
use receiver::{Receiver, ReceiverStats};
|
Action, Event, EventBoxed, ReciveTypedReceiver, ReciveUntypedReceiver, SendTypedReceiver,
|
||||||
use utils::binary_search_range_by_key;
|
SendUntypedReceiver, TypeTagAccept, TypeTagAcceptItem,
|
||||||
|
|
||||||
use core::any::{Any, TypeId};
|
|
||||||
use std::sync::{
|
|
||||||
atomic::{AtomicBool, Ordering},
|
|
||||||
Arc,
|
|
||||||
};
|
};
|
||||||
|
pub use relay::Relay;
|
||||||
|
pub use type_tag::{deserialize_shared_message, register_shared_message};
|
||||||
pub type Untyped = Arc<dyn Any + Send + Sync>;
|
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 {
|
pub struct BusInner {
|
||||||
receivers: Vec<(TypeId, Receiver)>,
|
receivers: HashSet<Receiver>,
|
||||||
|
lookup: HashMap<LookupQuery, SmallVec<[Receiver; 4]>>,
|
||||||
closed: AtomicBool,
|
closed: AtomicBool,
|
||||||
|
maintain: Mutex<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BusInner {
|
impl BusInner {
|
||||||
pub(crate) fn new(mut receivers: Vec<(TypeId, Receiver)>) -> Self {
|
pub(crate) fn new(receivers: HashSet<Receiver>) -> Self {
|
||||||
receivers.sort_unstable_by_key(|(k, _)| *k);
|
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 {
|
Self {
|
||||||
receivers,
|
receivers,
|
||||||
|
lookup,
|
||||||
closed: AtomicBool::new(false),
|
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)]
|
#[derive(Clone)]
|
||||||
@ -110,17 +126,696 @@ pub struct Bus {
|
|||||||
inner: Arc<BusInner>,
|
inner: Arc<BusInner>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl core::ops::Deref for Bus {
|
|
||||||
type Target = BusInner;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
self.inner.as_ref()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Bus {
|
impl Bus {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn build() -> BusBuilder {
|
pub fn build() -> BusBuilder {
|
||||||
BusBuilder::new()
|
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::{
|
use std::{
|
||||||
any::TypeId,
|
|
||||||
marker::PhantomData,
|
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicU64, Ordering},
|
atomic::{AtomicU64, Ordering},
|
||||||
Arc,
|
Arc,
|
||||||
},
|
},
|
||||||
task::{Context, Poll},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{receiver::ReceiverStats, receivers::mpsc};
|
|
||||||
use futures::{Future, StreamExt};
|
|
||||||
|
|
||||||
use super::{BufferUnorderedConfig, BufferUnorderedStats};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
builder::{ReceiverSubscriber, ReceiverSubscriberBuilder},
|
buffer_unordered_poller_macro,
|
||||||
msgs,
|
builder::ReceiverSubscriberBuilder,
|
||||||
receiver::{AnyReceiver, ReceiverTrait, SendError, TypedReceiver},
|
error::{Error, StdSyncSendError},
|
||||||
|
receiver::{
|
||||||
|
Action, Event, ReciveTypedReceiver, SendTypedReceiver, SendUntypedReceiver,
|
||||||
|
UntypedPollerCallback,
|
||||||
|
},
|
||||||
|
receivers::Request,
|
||||||
AsyncHandler, Bus, Message, Untyped,
|
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
|
where
|
||||||
T: AsyncHandler<M> + 'static,
|
|
||||||
M: Message,
|
M: Message,
|
||||||
|
R: Message,
|
||||||
|
E: StdSyncSendError,
|
||||||
{
|
{
|
||||||
cfg: BufferUnorderedConfig,
|
tx: mpsc::UnboundedSender<Request<M>>,
|
||||||
_m: PhantomData<(T, 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
|
where
|
||||||
T: AsyncHandler<M> + 'static,
|
T: AsyncHandler<M, Response = R, Error = E> + 'static,
|
||||||
|
R: Message,
|
||||||
M: Message,
|
M: Message,
|
||||||
|
E: StdSyncSendError,
|
||||||
{
|
{
|
||||||
fn subscribe(
|
type Config = BufferUnorderedConfig;
|
||||||
self,
|
|
||||||
) -> (
|
fn build(cfg: Self::Config) -> (Self, UntypedPollerCallback) {
|
||||||
Arc<dyn ReceiverTrait>,
|
|
||||||
Box<
|
|
||||||
dyn FnOnce(Untyped) -> Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>,
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
let cfg = self.cfg;
|
|
||||||
let stats = Arc::new(BufferUnorderedStats {
|
let stats = Arc::new(BufferUnorderedStats {
|
||||||
buffer: AtomicU64::new(0),
|
buffer: AtomicU64::new(0),
|
||||||
buffer_total: AtomicU64::new(cfg.buffer_size as _),
|
buffer_total: AtomicU64::new(cfg.buffer_size as _),
|
||||||
@ -50,154 +67,81 @@ where
|
|||||||
parallel_total: AtomicU64::new(cfg.max_parallel as _),
|
parallel_total: AtomicU64::new(cfg.max_parallel as _),
|
||||||
});
|
});
|
||||||
|
|
||||||
let (tx, rx) = mpsc::channel(cfg.buffer_size);
|
let (stx, srx) = mpsc::unbounded_channel();
|
||||||
let arc = Arc::new(BufferUnorderedAsync::<M> {
|
let (tx, rx) = mpsc::unbounded_channel();
|
||||||
tx,
|
let stats_clone = stats.clone();
|
||||||
stats: stats.clone(),
|
|
||||||
});
|
|
||||||
|
|
||||||
let poller = Box::new(move |ut| {
|
let poller = Box::new(move |ut| {
|
||||||
Box::new(move |bus| {
|
Box::new(move |bus| {
|
||||||
Box::pin(buffer_unordered_poller::<T, M>(rx, bus, ut, stats, cfg))
|
Box::pin(buffer_unordered_poller::<T, M, R, E>(
|
||||||
as Pin<Box<dyn Future<Output = ()> + Send>>
|
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>>>
|
}) 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>(
|
impl<M, R, E> SendUntypedReceiver for BufferUnorderedAsync<M, R, E>
|
||||||
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>
|
|
||||||
where
|
where
|
||||||
T: AsyncHandler<M> + 'static,
|
|
||||||
M: Message,
|
M: Message,
|
||||||
|
R: Message,
|
||||||
|
E: StdSyncSendError,
|
||||||
{
|
{
|
||||||
type Entry = BufferUnorderedAsyncSubscriber<T, M>;
|
fn send(&self, m: Action, _bus: &Bus) -> Result<(), Error<Action>> {
|
||||||
type Config = BufferUnorderedConfig;
|
match self.tx.send(Request::Action(m)) {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
fn build(cfg: Self::Config) -> Self::Entry {
|
Err(mpsc::error::SendError(Request::Action(msg))) => Err(Error::send_closed(msg)),
|
||||||
BufferUnorderedAsyncSubscriber {
|
_ => unimplemented!(),
|
||||||
cfg,
|
|
||||||
_m: Default::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Message> TypedReceiver<M> for BufferUnorderedAsync<M> {
|
impl<M, R, E> SendTypedReceiver<M> for BufferUnorderedAsync<M, R, E>
|
||||||
fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll<()> {
|
where
|
||||||
match self.tx.poll_ready(ctx) {
|
M: Message,
|
||||||
Poll::Ready(_) => Poll::Ready(()),
|
R: Message,
|
||||||
Poll::Pending => Poll::Pending,
|
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)) {
|
||||||
fn try_send(&self, m: M) -> Result<(), SendError<M>> {
|
|
||||||
match self.tx.try_send(m) {
|
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
self.stats.buffer.fetch_add(1, Ordering::Relaxed);
|
self.stats.buffer.fetch_add(1, Ordering::Relaxed);
|
||||||
|
|
||||||
Ok(())
|
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> {
|
impl<M, R, E> ReciveTypedReceiver<R, E> for BufferUnorderedAsync<M, R, E>
|
||||||
fn typed(&self) -> AnyReceiver<'_> {
|
where
|
||||||
AnyReceiver::new(self)
|
M: Message,
|
||||||
}
|
R: Message,
|
||||||
|
E: StdSyncSendError,
|
||||||
|
{
|
||||||
|
type Stream = Pin<Box<dyn Stream<Item = Event<R, E>> + Send>>;
|
||||||
|
|
||||||
fn type_id(&self) -> TypeId {
|
fn event_stream(&self, _: Bus) -> Self::Stream {
|
||||||
TypeId::of::<BufferUnorderedAsync<M>>()
|
let mut rx = self.srx.lock().take().unwrap();
|
||||||
}
|
|
||||||
|
|
||||||
fn close(&self) {
|
Box::pin(futures::stream::poll_fn(move |cx| rx.poll_recv(cx)))
|
||||||
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(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,9 @@ mod sync;
|
|||||||
|
|
||||||
use std::sync::atomic::AtomicU64;
|
use std::sync::atomic::AtomicU64;
|
||||||
|
|
||||||
pub use r#async::{BufferUnorderedAsync, BufferUnorderedAsyncSubscriber};
|
pub use r#async::BufferUnorderedAsync;
|
||||||
pub use sync::{BufferUnorderedSync, BufferUnorderedSyncSubscriber};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
pub use sync::BufferUnorderedSync;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BufferUnorderedStats {
|
pub struct BufferUnorderedStats {
|
||||||
@ -14,7 +15,7 @@ pub struct BufferUnorderedStats {
|
|||||||
pub parallel_total: AtomicU64,
|
pub parallel_total: AtomicU64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct BufferUnorderedConfig {
|
pub struct BufferUnorderedConfig {
|
||||||
pub buffer_size: usize,
|
pub buffer_size: usize,
|
||||||
pub max_parallel: 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::{
|
use std::{
|
||||||
any::TypeId,
|
|
||||||
marker::PhantomData,
|
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicU64, Ordering},
|
atomic::{AtomicU64, Ordering},
|
||||||
Arc,
|
Arc,
|
||||||
},
|
},
|
||||||
task::{Context, Poll},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{BufferUnorderedConfig, BufferUnorderedStats};
|
use super::{BufferUnorderedConfig, BufferUnorderedStats};
|
||||||
use crate::{
|
use crate::{
|
||||||
builder::{ReceiverSubscriber, ReceiverSubscriberBuilder},
|
buffer_unordered_poller_macro,
|
||||||
msgs,
|
builder::ReceiverSubscriberBuilder,
|
||||||
receiver::{AnyReceiver, ReceiverTrait, SendError, TypedReceiver},
|
error::{Error, StdSyncSendError},
|
||||||
|
receiver::{
|
||||||
|
Action, Event, ReciveTypedReceiver, SendTypedReceiver, SendUntypedReceiver,
|
||||||
|
UntypedPollerCallback,
|
||||||
|
},
|
||||||
|
receivers::Request,
|
||||||
Bus, Handler, Message, Untyped,
|
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
|
where
|
||||||
T: Handler<M> + 'static,
|
|
||||||
M: Message,
|
M: Message,
|
||||||
|
R: Message,
|
||||||
|
E: StdSyncSendError,
|
||||||
{
|
{
|
||||||
cfg: BufferUnorderedConfig,
|
tx: mpsc::UnboundedSender<Request<M>>,
|
||||||
_m: PhantomData<(M, T)>,
|
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
|
where
|
||||||
T: Handler<M> + 'static,
|
T: Handler<M, Response = R, Error = E> + 'static,
|
||||||
|
R: Message,
|
||||||
M: Message,
|
M: Message,
|
||||||
|
E: StdSyncSendError,
|
||||||
{
|
{
|
||||||
fn subscribe(
|
type Config = BufferUnorderedConfig;
|
||||||
self,
|
|
||||||
) -> (
|
fn build(cfg: Self::Config) -> (Self, UntypedPollerCallback) {
|
||||||
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(BufferUnorderedStats {
|
let stats = Arc::new(BufferUnorderedStats {
|
||||||
buffer: AtomicU64::new(0),
|
buffer: AtomicU64::new(0),
|
||||||
buffer_total: AtomicU64::new(cfg.buffer_size as _),
|
buffer_total: AtomicU64::new(cfg.buffer_size as _),
|
||||||
@ -50,154 +70,81 @@ where
|
|||||||
parallel_total: AtomicU64::new(cfg.max_parallel as _),
|
parallel_total: AtomicU64::new(cfg.max_parallel as _),
|
||||||
});
|
});
|
||||||
|
|
||||||
let arc = Arc::new(BufferUnorderedSync::<M> {
|
let (stx, srx) = mpsc::unbounded_channel();
|
||||||
tx,
|
let (tx, rx) = mpsc::unbounded_channel();
|
||||||
stats: stats.clone(),
|
let stats_clone = stats.clone();
|
||||||
});
|
|
||||||
|
|
||||||
let poller = Box::new(move |ut| {
|
let poller = Box::new(move |ut| {
|
||||||
Box::new(move |bus| {
|
Box::new(move |bus| {
|
||||||
Box::pin(buffer_unordered_poller::<T, M>(rx, bus, ut, stats, cfg))
|
Box::pin(buffer_unordered_poller::<T, M, R, E>(
|
||||||
as Pin<Box<dyn Future<Output = ()> + Send>>
|
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>>>
|
}) 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>(
|
impl<M, R, E> SendUntypedReceiver for BufferUnorderedSync<M, R, E>
|
||||||
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>
|
|
||||||
where
|
where
|
||||||
T: Handler<M> + 'static,
|
|
||||||
M: Message,
|
M: Message,
|
||||||
|
R: Message,
|
||||||
|
E: StdSyncSendError,
|
||||||
{
|
{
|
||||||
type Entry = BufferUnorderedSyncSubscriber<T, M>;
|
fn send(&self, msg: Action, _bus: &Bus) -> Result<(), Error<Action>> {
|
||||||
type Config = BufferUnorderedConfig;
|
match self.tx.send(Request::Action(msg)) {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
fn build(cfg: Self::Config) -> Self::Entry {
|
Err(mpsc::error::SendError(Request::Action(msg))) => Err(Error::send_closed(msg)),
|
||||||
BufferUnorderedSyncSubscriber {
|
_ => unimplemented!(),
|
||||||
cfg,
|
|
||||||
_m: Default::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Message> TypedReceiver<M> for BufferUnorderedSync<M> {
|
impl<M, R, E> SendTypedReceiver<M> for BufferUnorderedSync<M, R, E>
|
||||||
fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll<()> {
|
where
|
||||||
match self.tx.poll_ready(ctx) {
|
M: Message,
|
||||||
Poll::Ready(_) => Poll::Ready(()),
|
R: Message,
|
||||||
Poll::Pending => Poll::Pending,
|
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)) {
|
||||||
fn try_send(&self, m: M) -> Result<(), SendError<M>> {
|
|
||||||
match self.tx.try_send(m) {
|
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
self.stats.buffer.fetch_add(1, Ordering::Relaxed);
|
self.stats.buffer.fetch_add(1, Ordering::Relaxed);
|
||||||
|
|
||||||
Ok(())
|
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> {
|
impl<M, R, E> ReciveTypedReceiver<R, E> for BufferUnorderedSync<M, R, E>
|
||||||
fn typed(&self) -> AnyReceiver<'_> {
|
where
|
||||||
AnyReceiver::new(self)
|
M: Message,
|
||||||
}
|
R: Message,
|
||||||
|
E: StdSyncSendError,
|
||||||
|
{
|
||||||
|
type Stream = Pin<Box<dyn Stream<Item = Event<R, E>> + Send>>;
|
||||||
|
|
||||||
fn type_id(&self) -> TypeId {
|
fn event_stream(&self, _: Bus) -> Self::Stream {
|
||||||
TypeId::of::<BufferUnorderedSync<M>>()
|
let mut rx = self.srx.lock().take().unwrap();
|
||||||
}
|
|
||||||
|
|
||||||
fn stats(&self) -> ReceiverStats {
|
Box::pin(futures::stream::poll_fn(move |cx| rx.poll_recv(cx)))
|
||||||
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(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,48 +1,64 @@
|
|||||||
use std::{
|
use std::{
|
||||||
any::TypeId,
|
|
||||||
marker::PhantomData,
|
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicU64, Ordering},
|
atomic::{AtomicU64, Ordering},
|
||||||
Arc,
|
Arc,
|
||||||
},
|
},
|
||||||
task::{Context, Poll},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{receiver::ReceiverStats, receivers::mpsc};
|
|
||||||
use futures::{Future, StreamExt};
|
|
||||||
|
|
||||||
use super::{BufferUnorderedBatchedConfig, BufferUnorderedBatchedStats};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
builder::{ReceiverSubscriber, ReceiverSubscriberBuilder},
|
buffer_unordered_batch_poller_macro,
|
||||||
msgs,
|
builder::ReceiverSubscriberBuilder,
|
||||||
receiver::{AnyReceiver, ReceiverTrait, SendError, TypedReceiver},
|
error::{Error, StdSyncSendError},
|
||||||
|
receiver::{
|
||||||
|
Action, Event, ReciveTypedReceiver, SendTypedReceiver, SendUntypedReceiver,
|
||||||
|
UntypedPollerCallback,
|
||||||
|
},
|
||||||
|
receivers::Request,
|
||||||
AsyncBatchHandler, Bus, Message, Untyped,
|
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
|
where
|
||||||
T: AsyncBatchHandler<M> + 'static,
|
|
||||||
M: Message,
|
M: Message,
|
||||||
|
R: Message,
|
||||||
|
E: StdSyncSendError,
|
||||||
{
|
{
|
||||||
cfg: BufferUnorderedBatchedConfig,
|
tx: mpsc::UnboundedSender<Request<M>>,
|
||||||
_m: PhantomData<(T, 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
|
where
|
||||||
T: AsyncBatchHandler<M> + 'static,
|
T: AsyncBatchHandler<M, Response = R> + 'static,
|
||||||
|
T::Error: StdSyncSendError + Clone,
|
||||||
|
R: Message,
|
||||||
M: Message,
|
M: Message,
|
||||||
{
|
{
|
||||||
fn subscribe(
|
type Config = BufferUnorderedBatchedConfig;
|
||||||
self,
|
|
||||||
) -> (
|
fn build(cfg: Self::Config) -> (Self, UntypedPollerCallback) {
|
||||||
Arc<dyn ReceiverTrait>,
|
|
||||||
Box<
|
|
||||||
dyn FnOnce(Untyped) -> Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>,
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
let cfg = self.cfg;
|
|
||||||
let stats = Arc::new(BufferUnorderedBatchedStats {
|
let stats = Arc::new(BufferUnorderedBatchedStats {
|
||||||
buffer: AtomicU64::new(0),
|
buffer: AtomicU64::new(0),
|
||||||
buffer_total: AtomicU64::new(cfg.buffer_size as _),
|
buffer_total: AtomicU64::new(cfg.buffer_size as _),
|
||||||
@ -52,173 +68,81 @@ where
|
|||||||
batch_size: AtomicU64::new(cfg.batch_size as _),
|
batch_size: AtomicU64::new(cfg.batch_size as _),
|
||||||
});
|
});
|
||||||
|
|
||||||
let (tx, rx) = mpsc::channel(cfg.buffer_size);
|
let (stx, srx) = mpsc::unbounded_channel();
|
||||||
let arc = Arc::new(BufferUnorderedBatchedAsync::<M> {
|
let (tx, rx) = mpsc::unbounded_channel();
|
||||||
tx,
|
let stats_clone = stats.clone();
|
||||||
stats: stats.clone(),
|
|
||||||
});
|
|
||||||
|
|
||||||
let poller = Box::new(move |ut| {
|
let poller = Box::new(move |ut| {
|
||||||
Box::new(move |bus| {
|
Box::new(move |bus| {
|
||||||
Box::pin(buffer_unordered_poller::<T, M>(rx, bus, ut, stats, cfg))
|
Box::pin(buffer_unordered_batch_poller::<T, M, R>(
|
||||||
as Pin<Box<dyn Future<Output = ()> + Send>>
|
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>>>
|
}) 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>(
|
impl<M, R, E> SendUntypedReceiver for BufferUnorderedBatchedAsync<M, R, E>
|
||||||
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>
|
|
||||||
where
|
where
|
||||||
T: AsyncBatchHandler<M> + 'static,
|
|
||||||
M: Message,
|
M: Message,
|
||||||
|
R: Message,
|
||||||
|
E: StdSyncSendError,
|
||||||
{
|
{
|
||||||
type Entry = BufferUnorderedBatchedAsyncSubscriber<T, M>;
|
fn send(&self, m: Action, _bus: &Bus) -> Result<(), Error<Action>> {
|
||||||
type Config = BufferUnorderedBatchedConfig;
|
match self.tx.send(Request::Action(m)) {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
fn build(cfg: Self::Config) -> Self::Entry {
|
Err(mpsc::error::SendError(Request::Action(msg))) => Err(Error::send_closed(msg)),
|
||||||
BufferUnorderedBatchedAsyncSubscriber {
|
_ => unimplemented!(),
|
||||||
cfg,
|
|
||||||
_m: Default::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Message> TypedReceiver<M> for BufferUnorderedBatchedAsync<M> {
|
impl<M, R, E> SendTypedReceiver<M> for BufferUnorderedBatchedAsync<M, R, E>
|
||||||
fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll<()> {
|
where
|
||||||
match self.tx.poll_ready(ctx) {
|
M: Message,
|
||||||
Poll::Ready(_) => Poll::Ready(()),
|
R: Message,
|
||||||
Poll::Pending => Poll::Pending,
|
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)) {
|
||||||
fn try_send(&self, m: M) -> Result<(), SendError<M>> {
|
|
||||||
match self.tx.try_send(m) {
|
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
self.stats.buffer.fetch_add(1, Ordering::Relaxed);
|
self.stats.buffer.fetch_add(1, Ordering::Relaxed);
|
||||||
|
|
||||||
Ok(())
|
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> {
|
impl<M, R, E> ReciveTypedReceiver<R, E> for BufferUnorderedBatchedAsync<M, R, E>
|
||||||
fn typed(&self) -> AnyReceiver<'_> {
|
where
|
||||||
AnyReceiver::new(self)
|
M: Message,
|
||||||
}
|
R: Message,
|
||||||
|
E: StdSyncSendError,
|
||||||
|
{
|
||||||
|
type Stream = Pin<Box<dyn Stream<Item = Event<R, E>> + Send>>;
|
||||||
|
|
||||||
fn type_id(&self) -> TypeId {
|
fn event_stream(&self, _: Bus) -> Self::Stream {
|
||||||
TypeId::of::<BufferUnorderedBatchedAsync<M>>()
|
let mut rx = self.srx.lock().take().unwrap();
|
||||||
}
|
|
||||||
|
|
||||||
fn close(&self) {
|
Box::pin(futures::stream::poll_fn(move |cx| rx.poll_recv(cx)))
|
||||||
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(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,9 @@ mod sync;
|
|||||||
|
|
||||||
use std::sync::atomic::AtomicU64;
|
use std::sync::atomic::AtomicU64;
|
||||||
|
|
||||||
pub use r#async::{BufferUnorderedBatchedAsync, BufferUnorderedBatchedAsyncSubscriber};
|
pub use r#async::BufferUnorderedBatchedAsync;
|
||||||
pub use sync::{BufferUnorderedBatchedSync, BufferUnorderedBatchedSyncSubscriber};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
pub use sync::BufferUnorderedBatchedSync;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BufferUnorderedBatchedStats {
|
pub struct BufferUnorderedBatchedStats {
|
||||||
@ -16,7 +17,7 @@ pub struct BufferUnorderedBatchedStats {
|
|||||||
pub batch_size: AtomicU64,
|
pub batch_size: AtomicU64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct BufferUnorderedBatchedConfig {
|
pub struct BufferUnorderedBatchedConfig {
|
||||||
pub buffer_size: usize,
|
pub buffer_size: usize,
|
||||||
pub max_parallel: 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::{
|
use std::{
|
||||||
any::TypeId,
|
|
||||||
marker::PhantomData,
|
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicU64, Ordering},
|
atomic::{AtomicU64, Ordering},
|
||||||
Arc,
|
Arc,
|
||||||
},
|
},
|
||||||
task::{Context, Poll},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{BufferUnorderedBatchedConfig, BufferUnorderedBatchedStats};
|
use super::{BufferUnorderedBatchedConfig, BufferUnorderedBatchedStats};
|
||||||
use crate::{
|
use crate::{
|
||||||
builder::{ReceiverSubscriber, ReceiverSubscriberBuilder},
|
buffer_unordered_batch_poller_macro,
|
||||||
msgs,
|
builder::ReceiverSubscriberBuilder,
|
||||||
receiver::{AnyReceiver, ReceiverTrait, SendError, TypedReceiver},
|
error::{Error, StdSyncSendError},
|
||||||
Bus, BatchHandler, Message, Untyped,
|
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
|
where
|
||||||
T: BatchHandler<M> + 'static,
|
|
||||||
M: Message,
|
M: Message,
|
||||||
|
R: Message,
|
||||||
|
E: StdSyncSendError,
|
||||||
{
|
{
|
||||||
cfg: BufferUnorderedBatchedConfig,
|
tx: mpsc::UnboundedSender<Request<M>>,
|
||||||
_m: PhantomData<(M, T)>,
|
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
|
where
|
||||||
T: BatchHandler<M> + 'static,
|
T: BatchHandler<M, Response = R> + 'static,
|
||||||
|
T::Error: StdSyncSendError,
|
||||||
|
R: Message,
|
||||||
M: Message,
|
M: Message,
|
||||||
{
|
{
|
||||||
fn subscribe(
|
type Config = BufferUnorderedBatchedConfig;
|
||||||
self,
|
|
||||||
) -> (
|
fn build(cfg: Self::Config) -> (Self, UntypedPollerCallback) {
|
||||||
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(BufferUnorderedBatchedStats {
|
let stats = Arc::new(BufferUnorderedBatchedStats {
|
||||||
buffer: AtomicU64::new(0),
|
buffer: AtomicU64::new(0),
|
||||||
buffer_total: AtomicU64::new(cfg.buffer_size as _),
|
buffer_total: AtomicU64::new(cfg.buffer_size as _),
|
||||||
@ -52,172 +74,81 @@ where
|
|||||||
batch_size: AtomicU64::new(cfg.batch_size as _),
|
batch_size: AtomicU64::new(cfg.batch_size as _),
|
||||||
});
|
});
|
||||||
|
|
||||||
let arc = Arc::new(BufferUnorderedBatchedSync::<M> {
|
let (stx, srx) = mpsc::unbounded_channel();
|
||||||
tx,
|
let (tx, rx) = mpsc::unbounded_channel();
|
||||||
stats: stats.clone(),
|
let stats_clone = stats.clone();
|
||||||
});
|
|
||||||
|
|
||||||
let poller = Box::new(move |ut| {
|
let poller = Box::new(move |ut| {
|
||||||
Box::new(move |bus| {
|
Box::new(move |bus| {
|
||||||
Box::pin(buffer_unordered_poller::<T, M>(rx, bus, ut, stats, cfg))
|
Box::pin(buffer_unordered_batch_poller::<T, M, R>(
|
||||||
as Pin<Box<dyn Future<Output = ()> + Send>>
|
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>>>
|
}) 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>(
|
impl<M, R, E> SendUntypedReceiver for BufferUnorderedBatchedSync<M, R, E>
|
||||||
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>
|
|
||||||
where
|
where
|
||||||
T: BatchHandler<M> + 'static,
|
|
||||||
M: Message,
|
M: Message,
|
||||||
|
R: Message,
|
||||||
|
E: StdSyncSendError,
|
||||||
{
|
{
|
||||||
type Entry = BufferUnorderedBatchedSyncSubscriber<T, M>;
|
fn send(&self, msg: Action, _bus: &Bus) -> Result<(), Error<Action>> {
|
||||||
type Config = BufferUnorderedBatchedConfig;
|
match self.tx.send(Request::Action(msg)) {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
fn build(cfg: Self::Config) -> Self::Entry {
|
Err(mpsc::error::SendError(Request::Action(msg))) => Err(Error::send_closed(msg)),
|
||||||
BufferUnorderedBatchedSyncSubscriber {
|
_ => unimplemented!(),
|
||||||
cfg,
|
|
||||||
_m: Default::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Message> TypedReceiver<M> for BufferUnorderedBatchedSync<M> {
|
impl<M, R, E> SendTypedReceiver<M> for BufferUnorderedBatchedSync<M, R, E>
|
||||||
fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll<()> {
|
where
|
||||||
match self.tx.poll_ready(ctx) {
|
M: Message,
|
||||||
Poll::Ready(_) => Poll::Ready(()),
|
R: Message,
|
||||||
Poll::Pending => Poll::Pending,
|
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)) {
|
||||||
fn try_send(&self, m: M) -> Result<(), SendError<M>> {
|
|
||||||
match self.tx.try_send(m) {
|
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
self.stats.buffer.fetch_add(1, Ordering::Relaxed);
|
self.stats.buffer.fetch_add(1, Ordering::Relaxed);
|
||||||
|
|
||||||
Ok(())
|
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> {
|
impl<M, R, E> ReciveTypedReceiver<R, E> for BufferUnorderedBatchedSync<M, R, E>
|
||||||
fn typed(&self) -> AnyReceiver<'_> {
|
where
|
||||||
AnyReceiver::new(self)
|
M: Message,
|
||||||
}
|
R: Message,
|
||||||
|
E: StdSyncSendError,
|
||||||
|
{
|
||||||
|
type Stream = Pin<Box<dyn Stream<Item = Event<R, E>> + Send>>;
|
||||||
|
|
||||||
fn type_id(&self) -> TypeId {
|
fn event_stream(&self, _: Bus) -> Self::Stream {
|
||||||
TypeId::of::<BufferUnorderedBatchedSync<M>>()
|
let mut rx = self.srx.lock().take().unwrap();
|
||||||
}
|
|
||||||
|
|
||||||
fn stats(&self) -> ReceiverStats {
|
Box::pin(futures::stream::poll_fn(move |cx| rx.poll_recv(cx)))
|
||||||
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(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,56 @@
|
|||||||
mod buffer_unordered;
|
mod buffer_unordered;
|
||||||
mod buffer_unordered_batched;
|
mod buffer_unordered_batched;
|
||||||
mod mpsc_futures;
|
// mod producer;
|
||||||
mod synchronize_batched;
|
mod synchronize_batched;
|
||||||
mod synchronized;
|
mod synchronized;
|
||||||
|
|
||||||
mod mpsc {
|
pub use buffer_unordered::{BufferUnorderedAsync, BufferUnorderedConfig, BufferUnorderedSync};
|
||||||
pub use super::mpsc_futures::*;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub use buffer_unordered::{
|
|
||||||
BufferUnorderedAsync, BufferUnorderedAsyncSubscriber, BufferUnorderedConfig,
|
|
||||||
BufferUnorderedSync, BufferUnorderedSyncSubscriber,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub use buffer_unordered_batched::{
|
pub use buffer_unordered_batched::{
|
||||||
BufferUnorderedBatchedAsync, BufferUnorderedBatchedAsyncSubscriber, BufferUnorderedBatchedConfig,
|
BufferUnorderedBatchedAsync, BufferUnorderedBatchedConfig, BufferUnorderedBatchedSync,
|
||||||
BufferUnorderedBatchedSync, BufferUnorderedBatchedSyncSubscriber,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub use synchronized::{
|
|
||||||
SynchronizedAsync, SynchronizedAsyncSubscriber, SynchronizedConfig, SynchronizedSync,
|
|
||||||
SynchronizedSyncSubscriber,
|
|
||||||
};
|
};
|
||||||
|
pub use synchronized::{SynchronizedAsync, SynchronizedConfig, SynchronizedSync};
|
||||||
|
|
||||||
pub use synchronize_batched::{
|
pub use synchronize_batched::{
|
||||||
SynchronizeBatchedAsync, SynchronizeBatchedAsyncSubscriber, SynchronizeBatchedConfig,
|
SynchronizedBatchedAsync, SynchronizedBatchedConfig, SynchronizedBatchedSync,
|
||||||
SynchronizeBatchedSync, SynchronizeBatchedSyncSubscriber,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 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::{
|
use std::{pin::Pin, sync::Arc};
|
||||||
any::TypeId,
|
|
||||||
marker::PhantomData,
|
|
||||||
pin::Pin,
|
|
||||||
sync::{
|
|
||||||
atomic::{AtomicU64, Ordering},
|
|
||||||
Arc,
|
|
||||||
},
|
|
||||||
task::{Context, Poll},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{receiver::ReceiverStats, receivers::mpsc};
|
use super::SynchronizedBatchedConfig;
|
||||||
use futures::{Future, StreamExt};
|
|
||||||
use tokio::sync::Mutex;
|
|
||||||
|
|
||||||
use super::{SynchronizeBatchedConfig, SynchronizeBatchedStats};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
builder::{ReceiverSubscriber, ReceiverSubscriberBuilder},
|
batch_synchronized_poller_macro,
|
||||||
msgs,
|
builder::ReceiverSubscriberBuilder,
|
||||||
receiver::{AnyReceiver, ReceiverTrait, SendError, TypedReceiver},
|
error::{Error, StdSyncSendError},
|
||||||
|
receiver::{
|
||||||
|
Action, Event, ReciveTypedReceiver, SendTypedReceiver, SendUntypedReceiver,
|
||||||
|
UntypedPollerCallback,
|
||||||
|
},
|
||||||
|
receivers::Request,
|
||||||
AsyncBatchSynchronizedHandler, Bus, Message, Untyped,
|
AsyncBatchSynchronizedHandler, Bus, Message, Untyped,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct SynchronizeBatchedAsyncSubscriber<T, M>
|
use futures::{Future, Stream};
|
||||||
where
|
use tokio::sync::{
|
||||||
T: AsyncBatchSynchronizedHandler<M> + 'static,
|
mpsc::{self, UnboundedSender},
|
||||||
M: Message,
|
Mutex,
|
||||||
{
|
};
|
||||||
cfg: SynchronizeBatchedConfig,
|
|
||||||
_m: PhantomData<(T, M)>,
|
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
|
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,
|
M: Message,
|
||||||
{
|
{
|
||||||
fn subscribe(
|
type Config = SynchronizedBatchedConfig;
|
||||||
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 _),
|
|
||||||
});
|
|
||||||
|
|
||||||
let arc = Arc::new(SynchronizeBatchedAsync::<M> {
|
fn build(cfg: Self::Config) -> (Self, UntypedPollerCallback) {
|
||||||
tx,
|
let (stx, srx) = mpsc::unbounded_channel();
|
||||||
stats: stats.clone(),
|
let (tx, rx) = mpsc::unbounded_channel();
|
||||||
});
|
|
||||||
|
|
||||||
let poller = Box::new(move |ut| {
|
let poller = Box::new(move |ut| {
|
||||||
Box::new(move |bus| {
|
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 Pin<Box<dyn Future<Output = ()> + Send>>
|
||||||
}) as Box<dyn FnOnce(Bus) -> 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>(
|
impl<M, R, E> SendUntypedReceiver for SynchronizedBatchedAsync<M, R, E>
|
||||||
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>
|
|
||||||
where
|
where
|
||||||
T: AsyncBatchSynchronizedHandler<M> + 'static,
|
|
||||||
M: Message,
|
M: Message,
|
||||||
|
R: Message,
|
||||||
|
E: StdSyncSendError,
|
||||||
{
|
{
|
||||||
type Entry = SynchronizeBatchedAsyncSubscriber<T, M>;
|
fn send(&self, m: Action, _bus: &Bus) -> Result<(), Error<Action>> {
|
||||||
type Config = SynchronizeBatchedConfig;
|
match self.tx.send(Request::Action(m)) {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
fn build(cfg: Self::Config) -> Self::Entry {
|
Err(mpsc::error::SendError(Request::Action(msg))) => Err(Error::send_closed(msg)),
|
||||||
SynchronizeBatchedAsyncSubscriber {
|
_ => unimplemented!(),
|
||||||
cfg,
|
|
||||||
_m: Default::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Message> TypedReceiver<M> for SynchronizeBatchedAsync<M> {
|
impl<M, R, E> SendTypedReceiver<M> for SynchronizedBatchedAsync<M, R, E>
|
||||||
fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll<()> {
|
where
|
||||||
match self.tx.poll_ready(ctx) {
|
M: Message,
|
||||||
Poll::Ready(_) => Poll::Ready(()),
|
R: Message,
|
||||||
Poll::Pending => Poll::Pending,
|
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!(),
|
||||||
|
|
||||||
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 SynchronizeBatchedAsync<M> {
|
impl<M, R, E> ReciveTypedReceiver<R, E> for SynchronizedBatchedAsync<M, R, E>
|
||||||
fn typed(&self) -> AnyReceiver<'_> {
|
where
|
||||||
AnyReceiver::new(self)
|
M: Message,
|
||||||
}
|
R: Message,
|
||||||
|
E: StdSyncSendError,
|
||||||
|
{
|
||||||
|
type Stream = Pin<Box<dyn Stream<Item = Event<R, E>> + Send>>;
|
||||||
|
|
||||||
fn type_id(&self) -> TypeId {
|
fn event_stream(&self, _: Bus) -> Self::Stream {
|
||||||
TypeId::of::<Self>()
|
let mut rx = self.srx.lock().take().unwrap();
|
||||||
}
|
|
||||||
|
|
||||||
fn close(&self) {
|
Box::pin(futures::stream::poll_fn(move |cx| rx.poll_recv(cx)))
|
||||||
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(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,31 +3,104 @@ mod sync;
|
|||||||
|
|
||||||
use std::sync::atomic::AtomicU64;
|
use std::sync::atomic::AtomicU64;
|
||||||
|
|
||||||
pub use sync::{SynchronizeBatchedSync, SynchronizeBatchedSyncSubscriber};
|
pub use r#async::SynchronizedBatchedAsync;
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
pub use r#async::{SynchronizeBatchedAsync, SynchronizeBatchedAsyncSubscriber};
|
pub use sync::SynchronizedBatchedSync;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SynchronizeBatchedStats {
|
pub struct SynchronizedBatchedStats {
|
||||||
pub buffer: AtomicU64,
|
pub buffer: AtomicU64,
|
||||||
pub buffer_total: AtomicU64,
|
pub buffer_total: AtomicU64,
|
||||||
pub batch: AtomicU64,
|
pub batch: AtomicU64,
|
||||||
pub batch_size: AtomicU64,
|
pub batch_size: AtomicU64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct SynchronizeBatchedConfig {
|
pub struct SynchronizedBatchedConfig {
|
||||||
pub buffer_size: usize,
|
pub buffer_size: usize,
|
||||||
pub batch_size: usize,
|
pub batch_size: usize,
|
||||||
pub when_ready: bool,
|
pub when_ready: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for SynchronizeBatchedConfig {
|
impl Default for SynchronizedBatchedConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
buffer_size: 4,
|
buffer_size: 4,
|
||||||
batch_size: 16,
|
batch_size: 8,
|
||||||
when_ready: false,
|
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::{
|
use crate::{
|
||||||
builder::{ReceiverSubscriber, ReceiverSubscriberBuilder},
|
batch_synchronized_poller_macro,
|
||||||
msgs,
|
builder::ReceiverSubscriberBuilder,
|
||||||
receiver::{AnyReceiver, ReceiverTrait, SendError, TypedReceiver},
|
error::{Error, StdSyncSendError},
|
||||||
|
receiver::{
|
||||||
|
Action, Event, ReciveTypedReceiver, SendTypedReceiver, SendUntypedReceiver,
|
||||||
|
UntypedPollerCallback,
|
||||||
|
},
|
||||||
|
receivers::Request,
|
||||||
BatchSynchronizedHandler, Bus, Message, Untyped,
|
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>
|
use super::SynchronizedBatchedConfig;
|
||||||
where
|
use futures::{executor::block_on, Future, Stream};
|
||||||
T: BatchSynchronizedHandler<M> + 'static,
|
use tokio::sync::{
|
||||||
M: Message,
|
mpsc::{self, UnboundedSender},
|
||||||
{
|
Mutex,
|
||||||
cfg: SynchronizeBatchedConfig,
|
};
|
||||||
_m: PhantomData<(M, T)>,
|
|
||||||
|
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
|
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,
|
M: Message,
|
||||||
{
|
{
|
||||||
fn subscribe(
|
type Config = SynchronizedBatchedConfig;
|
||||||
self,
|
|
||||||
) -> (
|
fn build(cfg: Self::Config) -> (Self, UntypedPollerCallback) {
|
||||||
Arc<dyn ReceiverTrait>,
|
let (stx, srx) = mpsc::unbounded_channel();
|
||||||
Box<
|
let (tx, rx) = mpsc::unbounded_channel();
|
||||||
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 _),
|
|
||||||
});
|
|
||||||
|
|
||||||
let arc = Arc::new(SynchronizeBatchedSync::<M> {
|
|
||||||
tx,
|
|
||||||
stats: stats.clone(),
|
|
||||||
});
|
|
||||||
let poller = Box::new(move |ut| {
|
let poller = Box::new(move |ut| {
|
||||||
Box::new(move |bus| {
|
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 Pin<Box<dyn Future<Output = ()> + Send>>
|
||||||
}) as Box<dyn FnOnce(Bus) -> 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>(
|
impl<M, R, E> SendUntypedReceiver for SynchronizedBatchedSync<M, R, E>
|
||||||
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>
|
|
||||||
where
|
where
|
||||||
T: BatchSynchronizedHandler<M> + 'static,
|
|
||||||
M: Message,
|
M: Message,
|
||||||
|
R: Message,
|
||||||
|
E: StdSyncSendError,
|
||||||
{
|
{
|
||||||
type Entry = SynchronizeBatchedSyncSubscriber<T, M>;
|
fn send(&self, msg: Action, _bus: &Bus) -> Result<(), Error<Action>> {
|
||||||
type Config = SynchronizeBatchedConfig;
|
match self.tx.send(Request::Action(msg)) {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
fn build(cfg: Self::Config) -> Self::Entry {
|
Err(mpsc::error::SendError(Request::Action(msg))) => Err(Error::send_closed(msg)),
|
||||||
SynchronizeBatchedSyncSubscriber {
|
_ => unimplemented!(),
|
||||||
cfg,
|
|
||||||
_m: Default::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Message> TypedReceiver<M> for SynchronizeBatchedSync<M> {
|
impl<M, R, E> SendTypedReceiver<M> for SynchronizedBatchedSync<M, R, E>
|
||||||
fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll<()> {
|
where
|
||||||
match self.tx.poll_ready(ctx) {
|
M: Message,
|
||||||
Poll::Ready(_) => Poll::Ready(()),
|
R: Message,
|
||||||
Poll::Pending => Poll::Pending,
|
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!(),
|
||||||
|
|
||||||
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 SynchronizeBatchedSync<M> {
|
impl<M, R, E> ReciveTypedReceiver<R, E> for SynchronizedBatchedSync<M, R, E>
|
||||||
fn typed(&self) -> AnyReceiver<'_> {
|
where
|
||||||
AnyReceiver::new(self)
|
M: Message,
|
||||||
}
|
R: Message,
|
||||||
|
E: StdSyncSendError,
|
||||||
|
{
|
||||||
|
type Stream = Pin<Box<dyn Stream<Item = Event<R, E>> + Send>>;
|
||||||
|
|
||||||
fn type_id(&self) -> TypeId {
|
fn event_stream(&self, _: Bus) -> Self::Stream {
|
||||||
TypeId::of::<Self>()
|
let mut rx = self.srx.lock().take().unwrap();
|
||||||
}
|
|
||||||
|
|
||||||
fn stats(&self) -> ReceiverStats {
|
Box::pin(futures::stream::poll_fn(move |cx| rx.poll_recv(cx)))
|
||||||
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(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,186 +1,121 @@
|
|||||||
use std::{
|
use std::{pin::Pin, sync::Arc};
|
||||||
any::TypeId,
|
|
||||||
marker::PhantomData,
|
|
||||||
pin::Pin,
|
|
||||||
sync::{
|
|
||||||
atomic::{AtomicU64, Ordering},
|
|
||||||
Arc,
|
|
||||||
},
|
|
||||||
task::{Context, Poll},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{receiver::ReceiverStats, receivers::mpsc};
|
use crate::{receiver::UntypedPollerCallback, synchronized_poller_macro};
|
||||||
use futures::{Future, StreamExt};
|
use futures::{Future, Stream};
|
||||||
use tokio::sync::Mutex;
|
|
||||||
|
|
||||||
use super::{SynchronizedConfig, SynchronizedStats};
|
use super::SynchronizedConfig;
|
||||||
use crate::{
|
use crate::{
|
||||||
builder::{ReceiverSubscriber, ReceiverSubscriberBuilder},
|
builder::ReceiverSubscriberBuilder,
|
||||||
msgs,
|
error::{Error, StdSyncSendError},
|
||||||
receiver::{AnyReceiver, ReceiverTrait, SendError, TypedReceiver},
|
receiver::{Action, Event, ReciveTypedReceiver, SendTypedReceiver, SendUntypedReceiver},
|
||||||
|
receivers::Request,
|
||||||
AsyncSynchronizedHandler, Bus, Message, Untyped,
|
AsyncSynchronizedHandler, Bus, Message, Untyped,
|
||||||
};
|
};
|
||||||
|
use tokio::sync::{
|
||||||
|
mpsc::{self, UnboundedSender},
|
||||||
|
Mutex,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct SynchronizedAsyncSubscriber<T, M>
|
synchronized_poller_macro! {
|
||||||
where
|
T,
|
||||||
T: AsyncSynchronizedHandler<M> + 'static,
|
AsyncSynchronizedHandler,
|
||||||
M: Message,
|
|mid, msg, bus, ut: Arc<Mutex<T>>, stx: UnboundedSender<_>| {
|
||||||
{
|
tokio::spawn(async move {
|
||||||
cfg: SynchronizedConfig,
|
let resp = ut.lock().await.handle(msg, &bus).await;
|
||||||
_m: PhantomData<(T, M)>,
|
|
||||||
|
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
|
where
|
||||||
T: AsyncSynchronizedHandler<M> + 'static,
|
|
||||||
M: Message,
|
M: Message,
|
||||||
|
R: Message,
|
||||||
|
E: StdSyncSendError,
|
||||||
{
|
{
|
||||||
fn subscribe(
|
tx: mpsc::UnboundedSender<Request<M>>,
|
||||||
self,
|
srx: parking_lot::Mutex<Option<mpsc::UnboundedReceiver<Event<R, E>>>>,
|
||||||
) -> (
|
}
|
||||||
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 _),
|
|
||||||
});
|
|
||||||
|
|
||||||
let arc = Arc::new(SynchronizedAsync::<M> {
|
impl<T, M, R, E> ReceiverSubscriberBuilder<T, M, R, E> for SynchronizedAsync<M, R, E>
|
||||||
tx,
|
where
|
||||||
stats: stats.clone(),
|
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| {
|
let poller = Box::new(move |ut| {
|
||||||
Box::new(move |bus| {
|
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 Pin<Box<dyn Future<Output = ()> + Send>>
|
||||||
}) as Box<dyn FnOnce(Bus) -> 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(),
|
SynchronizedAsync::<M, R, E> {
|
||||||
self.stats.buffer_total.load(Ordering::SeqCst),
|
tx,
|
||||||
),
|
srx: parking_lot::Mutex::new(Some(srx)),
|
||||||
],
|
},
|
||||||
}
|
poller,
|
||||||
}
|
)
|
||||||
|
}
|
||||||
fn close(&self) {
|
}
|
||||||
self.tx.close();
|
|
||||||
}
|
impl<M, R, E> SendUntypedReceiver for SynchronizedAsync<M, R, E>
|
||||||
|
where
|
||||||
fn sync(&self) {
|
M: Message,
|
||||||
self.tx.flush();
|
R: Message,
|
||||||
}
|
E: StdSyncSendError,
|
||||||
|
{
|
||||||
fn poll_synchronized(&self, _ctx: &mut Context<'_>) -> Poll<()> {
|
fn send(&self, m: Action, _bus: &Bus) -> Result<(), Error<Action>> {
|
||||||
Poll::Ready(())
|
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;
|
use std::sync::atomic::AtomicU64;
|
||||||
|
|
||||||
pub use sync::{SynchronizedSync, SynchronizedSyncSubscriber};
|
pub use r#async::SynchronizedAsync;
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
pub use r#async::{SynchronizedAsync, SynchronizedAsyncSubscriber};
|
pub use sync::SynchronizedSync;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SynchronizedStats {
|
pub struct SynchronizedStats {
|
||||||
@ -13,7 +13,7 @@ pub struct SynchronizedStats {
|
|||||||
pub buffer_total: AtomicU64,
|
pub buffer_total: AtomicU64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct SynchronizedConfig {
|
pub struct SynchronizedConfig {
|
||||||
pub buffer_size: usize,
|
pub buffer_size: usize,
|
||||||
}
|
}
|
||||||
@ -23,3 +23,51 @@ impl Default for SynchronizedConfig {
|
|||||||
Self { buffer_size: 1 }
|
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 std::{pin::Pin, sync::Arc};
|
||||||
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 crate::{receiver::UntypedPollerCallback, synchronized_poller_macro};
|
||||||
|
use futures::{executor::block_on, Future, Stream};
|
||||||
|
|
||||||
|
use super::SynchronizedConfig;
|
||||||
use crate::{
|
use crate::{
|
||||||
builder::{ReceiverSubscriber, ReceiverSubscriberBuilder},
|
builder::ReceiverSubscriberBuilder,
|
||||||
msgs,
|
error::{Error, StdSyncSendError},
|
||||||
receiver::{AnyReceiver, ReceiverTrait, SendError, TypedReceiver},
|
receiver::{Action, Event, ReciveTypedReceiver, SendTypedReceiver, SendUntypedReceiver},
|
||||||
|
receivers::Request,
|
||||||
Bus, Message, SynchronizedHandler, Untyped,
|
Bus, Message, SynchronizedHandler, Untyped,
|
||||||
};
|
};
|
||||||
|
use tokio::sync::{
|
||||||
|
mpsc::{self, UnboundedSender},
|
||||||
|
Mutex,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct SynchronizedSyncSubscriber<T, M>
|
synchronized_poller_macro! {
|
||||||
where
|
T,
|
||||||
T: SynchronizedHandler<M> + 'static,
|
SynchronizedHandler,
|
||||||
M: Message,
|
|mid, msg, bus, ut: Arc<Mutex<T>>, stx: UnboundedSender<_>| {
|
||||||
{
|
tokio::task::spawn_blocking(move || {
|
||||||
cfg: SynchronizedConfig,
|
let resp = block_on(ut.lock()).handle(msg, &bus);
|
||||||
_m: PhantomData<(M, T)>,
|
|
||||||
|
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
|
where
|
||||||
T: SynchronizedHandler<M> + 'static,
|
|
||||||
M: Message,
|
M: Message,
|
||||||
|
R: Message,
|
||||||
|
E: StdSyncSendError,
|
||||||
{
|
{
|
||||||
fn subscribe(
|
tx: mpsc::UnboundedSender<Request<M>>,
|
||||||
self,
|
srx: parking_lot::Mutex<Option<mpsc::UnboundedReceiver<Event<R, E>>>>,
|
||||||
) -> (
|
}
|
||||||
Arc<dyn ReceiverTrait>,
|
|
||||||
Box<
|
impl<T, M, R, E> ReceiverSubscriberBuilder<T, M, R, E> for SynchronizedSync<M, R, E>
|
||||||
dyn FnOnce(Untyped) -> Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>,
|
where
|
||||||
>,
|
T: SynchronizedHandler<M, Response = R, Error = E> + 'static,
|
||||||
) {
|
R: Message,
|
||||||
let cfg = self.cfg;
|
M: Message,
|
||||||
let (tx, rx) = mpsc::channel(cfg.buffer_size);
|
E: StdSyncSendError,
|
||||||
let stats = Arc::new(SynchronizedStats {
|
{
|
||||||
buffer: AtomicU64::new(0),
|
type Config = SynchronizedConfig;
|
||||||
buffer_total: AtomicU64::new(cfg.buffer_size as _),
|
|
||||||
});
|
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| {
|
let poller = Box::new(move |ut| {
|
||||||
Box::new(move |bus| {
|
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 Pin<Box<dyn Future<Output = ()> + Send>>
|
||||||
}) as Box<dyn FnOnce(Bus) -> 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(),
|
SynchronizedSync::<M, R, E> {
|
||||||
self.stats.buffer_total.load(Ordering::SeqCst),
|
tx,
|
||||||
),
|
srx: parking_lot::Mutex::new(Some(srx)),
|
||||||
],
|
},
|
||||||
}
|
poller,
|
||||||
}
|
)
|
||||||
|
}
|
||||||
fn close(&self) {
|
}
|
||||||
self.tx.close();
|
|
||||||
}
|
impl<M, R, E> SendUntypedReceiver for SynchronizedSync<M, R, E>
|
||||||
|
where
|
||||||
fn sync(&self) {
|
M: Message,
|
||||||
self.tx.flush();
|
R: Message,
|
||||||
}
|
E: StdSyncSendError,
|
||||||
|
{
|
||||||
fn poll_synchronized(&self, _ctx: &mut Context<'_>) -> Poll<()> {
|
fn send(&self, msg: Action, _bus: &Bus) -> Result<(), Error<Action>> {
|
||||||
Poll::Ready(())
|
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