diff --git a/Cargo.lock b/Cargo.lock index 8e94025e..2bc70f89 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -148,7 +148,7 @@ dependencies = [ [[package]] name = "rmp-ipc" -version = "0.4.4" +version = "0.5.0" dependencies = [ "lazy_static", "log", diff --git a/Cargo.toml b/Cargo.toml index d82012b5..894b956e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rmp-ipc" -version = "0.4.4" +version = "0.5.0" authors = ["trivernis "] edition = "2018" readme = "README.md" diff --git a/README.md b/README.md index 415ad5d0..b9939642 100644 --- a/README.md +++ b/README.md @@ -76,21 +76,39 @@ async fn main() { **Server:** ```rust -use rmp_ipc::IPCBuilder; +use rmp_ipc::{IPCBuilder, EventHandler, namespace, command, Event, context::Context}; // create the server +pub struct MyNamespace; + +impl MyNamespace { + async fn ping(_ctx: &Context, _event: Event) -> Result<()> { + println!("My namespace received a ping"); + Ok(()) + } +} + +impl NamespaceProvider for MyNamespace { + fn name() -> String {String::from("my_namespace")} + + fn register(handler: &mut EventHandler) { + handler.on("ping", callback!(Self::ping)) + } +} + #[tokio::main] async fn main() { IPCBuilder::new() .address("127.0.0.1:2020") // register namespace .namespace("mainspace-server") - // register callback (without macro) + // register callback .on("ping", |_ctx, _event| Box::pin(async move { println!("Received ping event."); Ok(()) })) .build() + .add_namespace(namespace!(MyNamespace)) .build_server().await.unwrap(); } ``` diff --git a/src/ipc/context.rs b/src/ipc/context.rs index 4cd10e7f..e625c25d 100644 --- a/src/ipc/context.rs +++ b/src/ipc/context.rs @@ -1,6 +1,6 @@ use crate::error::{Error, Result}; +use crate::event::Event; use crate::ipc::stream_emitter::StreamEmitter; -use crate::Event; use std::collections::HashMap; use std::mem; use std::sync::Arc; @@ -11,11 +11,9 @@ use typemap_rev::TypeMap; /// An object provided to each callback function. /// Currently it only holds the event emitter to emit response events in event callbacks. /// ```rust -/// use rmp_ipc::context::Context; -/// use rmp_ipc::Event; -/// use rmp_ipc::error::Result; +/// use rmp_ipc::prelude::*; /// -/// async fn my_callback(ctx: &Context, _event: Event) -> Result<()> { +/// async fn my_callback(ctx: &Context, _event: Event) -> IPCResult<()> { /// // use the emitter on the context object to emit events /// // inside callbacks /// ctx.emitter.emit("ping", ()).await?; diff --git a/src/ipc/mod.rs b/src/ipc/mod.rs index b48662f0..3a84923c 100644 --- a/src/ipc/mod.rs +++ b/src/ipc/mod.rs @@ -1,8 +1,7 @@ -use crate::context::Context; use crate::error_event::{ErrorEventData, ERROR_EVENT_NAME}; use crate::events::event_handler::EventHandler; use crate::namespaces::namespace::Namespace; -use crate::Event; +use crate::prelude::*; use std::collections::HashMap; use std::sync::Arc; use tokio::net::tcp::OwnedReadHalf; diff --git a/src/ipc/stream_emitter.rs b/src/ipc/stream_emitter.rs index 6da3dfa8..14dff799 100644 --- a/src/ipc/stream_emitter.rs +++ b/src/ipc/stream_emitter.rs @@ -1,6 +1,6 @@ -use crate::context::Context; use crate::error::Result; use crate::events::event::Event; +use crate::ipc::context::Context; use serde::Serialize; use std::sync::Arc; use tokio::io::AsyncWriteExt; diff --git a/src/lib.rs b/src/lib.rs index 9ade86c4..0f4f1895 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,16 +2,33 @@ //! messagepack. All calls are asynchronous and event based. //! Client Example: //! ```no_run -//! use rmp_ipc::{callback, Event, context::Context, IPCBuilder, error::Result}; +//! use rmp_ipc::prelude::*; //! //! /// Callback ping function -//! async fn handle_ping(ctx: &Context, event: Event) -> Result<()> { +//! async fn handle_ping(ctx: &Context, event: Event) -> IPCResult<()> { //! println!("Received ping event."); //! ctx.emitter.emit_response(event.id(), "pong", ()).await?; //! //! Ok(()) //! } //! +//! pub struct MyNamespace; +//! +//! impl MyNamespace { +//! async fn ping(_ctx: &Context, _event: Event) -> IPCResult<()> { +//! println!("My namespace received a ping"); +//! Ok(()) +//! } +//! } +//! +//! impl NamespaceProvider for MyNamespace { +//! fn name() -> String {String::from("my_namespace")} +//! +//! fn register(handler: &mut EventHandler) { +//! handler.on("ping", callback!(Self::ping)) +//! } +//!} +//! //! #[tokio::main] //! async fn main() { //! // create the client @@ -27,6 +44,7 @@ //! Ok(()) //! })) //! .build() +//! .add_namespace(namespace!(MyNamespace)) //! .build_client().await.unwrap(); //! //! // emit an initial event @@ -81,14 +99,29 @@ mod tests; pub mod error; mod events; -mod ipc; +pub mod ipc; mod macros; mod namespaces; pub use events::error_event; -pub use events::event::Event; +pub use events::event; +pub use events::event_handler; pub use ipc::builder::IPCBuilder; -pub use ipc::*; pub use macros::*; pub use namespaces::builder::NamespaceBuilder; -pub use namespaces::namespace::Namespace; +pub use namespaces::namespace; +pub use namespaces::provider_trait; + +pub mod prelude { + pub use crate::error::Error as IPCError; + pub use crate::error::Result as IPCResult; + pub use crate::event::Event; + pub use crate::event_handler::EventHandler; + pub use crate::ipc::context::Context; + pub use crate::ipc::*; + pub use crate::macros::*; + pub use crate::namespace::Namespace; + pub use crate::namespaces::builder::NamespaceBuilder; + pub use crate::namespaces::provider_trait::*; + pub use crate::*; +} diff --git a/src/macros.rs b/src/macros.rs index 90682256..d0600692 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -3,7 +3,17 @@ macro_rules! callback { ($cb:ident) => { |ctx, event| Box::pin($cb(ctx, event)) }; + ($cb:path) => { + |ctx, event| Box::pin($cb(ctx, event)) + }; ($ctx:ident, $event:ident,$cb:expr) => { move |$ctx, $event| Box::pin($cb) }; } + +#[macro_export] +macro_rules! namespace { + ($nsp:path) => { + Namespace::from_provider::<$nsp>() + }; +} diff --git a/src/namespaces/builder.rs b/src/namespaces/builder.rs index 4b3d7fb7..9f9dd214 100644 --- a/src/namespaces/builder.rs +++ b/src/namespaces/builder.rs @@ -1,8 +1,9 @@ -use crate::context::Context; use crate::error::Result; +use crate::event::Event; use crate::events::event_handler::EventHandler; +use crate::ipc::context::Context; use crate::namespaces::namespace::Namespace; -use crate::{Event, IPCBuilder}; +use crate::IPCBuilder; use std::future::Future; use std::pin::Pin; diff --git a/src/namespaces/mod.rs b/src/namespaces/mod.rs index 54853061..639f8b15 100644 --- a/src/namespaces/mod.rs +++ b/src/namespaces/mod.rs @@ -1,2 +1,3 @@ pub mod builder; pub mod namespace; +pub mod provider_trait; diff --git a/src/namespaces/provider_trait.rs b/src/namespaces/provider_trait.rs new file mode 100644 index 00000000..8f86f0cb --- /dev/null +++ b/src/namespaces/provider_trait.rs @@ -0,0 +1,17 @@ +use crate::events::event_handler::EventHandler; +use crate::namespace::Namespace; + +pub trait NamespaceProvider { + fn name() -> String; + fn register(handler: &mut EventHandler); +} + +impl Namespace { + pub fn from_provider() -> Self { + let name = N::name(); + let mut handler = EventHandler::new(); + N::register(&mut handler); + + Self::new(name, handler) + } +} diff --git a/src/tests/ipc_tests.rs b/src/tests/ipc_tests.rs index 4595df31..9cf39ee1 100644 --- a/src/tests/ipc_tests.rs +++ b/src/tests/ipc_tests.rs @@ -1,17 +1,12 @@ use self::super::utils::PingEventData; -use crate::callback; -use crate::context::Context; -use crate::error::Error; -use crate::error::Result; -use crate::events::error_event::ErrorEventData; +use crate::prelude::*; use crate::tests::utils::start_test_server; -use crate::{Event, IPCBuilder}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use std::time::{Duration, SystemTime}; use typemap_rev::TypeMapKey; -async fn handle_ping_event(ctx: &Context, e: Event) -> Result<()> { +async fn handle_ping_event(ctx: &Context, e: Event) -> IPCResult<()> { let mut ping_data = e.data::()?; ping_data.time = SystemTime::now(); ping_data.ttl -= 1; @@ -70,6 +65,25 @@ fn get_builder_with_ping_mainspace(address: &str) -> IPCBuilder { .address(address) } +pub struct TestNamespace; + +impl TestNamespace { + async fn ping(_c: &Context, _e: Event) -> IPCResult<()> { + println!("Ping received"); + Ok(()) + } +} + +impl NamespaceProvider for TestNamespace { + fn name() -> String { + String::from("Test") + } + + fn register(handler: &mut EventHandler) { + handler.on("ping", callback!(Self::ping)) + } +} + #[tokio::test] async fn it_receives_namespaced_events() { let builder = get_builder_with_ping_mainspace("127.0.0.1:8282"); @@ -85,7 +99,11 @@ async fn it_receives_namespaced_events() { while !server_running.load(Ordering::Relaxed) { tokio::time::sleep(Duration::from_millis(10)).await; } - let ctx = builder.build_client().await.unwrap(); + let ctx = builder + .add_namespace(namespace!(TestNamespace)) + .build_client() + .await + .unwrap(); let reply = ctx .emitter .emit_to( @@ -114,12 +132,12 @@ fn get_builder_with_error_handling(error_occurred: Arc, address: &st IPCBuilder::new() .insert::(error_occurred) .on("ping", move |_, _| { - Box::pin(async move { Err(Error::from("ERRROROROROR")) }) + Box::pin(async move { Err(IPCError::from("ERRROROROROR")) }) }) .on( "error", callback!(ctx, event, async move { - let error = event.data::()?; + let error = event.data::()?; assert!(error.message.len() > 0); assert_eq!(error.code, 500); {