#pub-sub #event-bus #aop #pubsub #plugin-system

kokoro

Dynamic publish-subscribe pattern framework. Support for dynamic plug-ins and AOP

4 releases

0.0.6 Feb 28, 2024
0.0.5 Feb 19, 2024

#631 in Web programming

Apache-2.0/MIT

49KB
745 lines

Kokoro

docs.rs Crates.io Version Crates.io License

Dynamic publish-subscribe pattern framework.

Support for dynamic plug-ins and AOP

Not yet stable, do not use in production !!


Simple publish/subscribe

use std::fmt::Display;
use kokoro::prelude::*;
fn main() {
    let ctx = channel_ctx();
    // Register a subscriber
    ctx.subscribe(sub_print);
    // Create a publisher
    let _ = ctx.spawn(|ctx, s| {
        // s is a signal that is true when the thread should be terminated
        while !s.is() {
            // Publish the event:Print
            ctx.publish(Print(&"Hello World"));
            std::thread::sleep(std::time::Duration::from_secs(1));
        }
    });
    ctx.run();
    /* Typically, the output will be :
     *  Hello World
     *  ...
    */
}

#[derive(Event)]
// This is a event:Print
struct Print(&'static dyn Display);

// This is a subscriber who subscribes to the event:Print
fn sub_print(print: &Print) {
    println!("{}", print.0);
}

Plug-in system with dynamic capabilities

APP

use kokoro::prelude::*;

fn main() -> Result<()> {
    let ctx = channel_ctx();
    // let dyp = DynamicPlugin::from_path("path to Plugin (Dynamic link library)"); // Also can do it
    // let dyp = DynamicPlugin::try_from(unsafe { libloading::Library::new("path to Plugin (Dynamic link library)") }); // Also can do it
    let dyp = "path to Plugin (Dynamic link library)"; // String or Library or DynamicPlugin
    let config = toml::toml! {
        hello = "I am plugin"
    };
    ctx.plugin_dynamic(dyp, Some(content.into()))?;
    ctx.publish(PhantomEvent);
    ctx.run();
    /* Typically, the output will be :
     *  I am plugin plugin-example
    */
    Ok(())
}

Plugin (Dynamic link library)

use kokoro::prelude::*;
use kokoro::dynamic_plugin::toml::Value;
use serde::Deserialize;

#[derive(DynamicPlugin, Deserialize)]
struct MyPlugin {
    hello: String,
}

impl Plugin for MyPlugin {
    type MODE = MPSC;
    const NAME: &'static str = "plugin-example";
    fn apply(ctx: Context<Self, MPSC>) -> Result<()> {
        ctx.subscribe(sub);
        Ok(())
    }
}

impl Create for MyPlugin {
    fn create(config: Option<Value>) -> Result<Self> {
        if let Some(config) = config {
            let config = MyPlugin::deserialize(config)?;
            Ok(config)
        } else {
            Err(anyhow!("Required Config"))
        }
    }
}

fn sub(ctx: &Context<MyPlugin, MPSC>) {
    println!(
        "{} {}",
        ctx.hello,
        MyPlugin::NAME
    );
}

Star History

Star History Chart

todo list

  • kokoro-default-impl
    • kokoro-plugin-impl
    • kokoro-thread-impl
    • kokoro-service-impl (AOP Support)
  • kokoro-dynamic-plugin-impl
  • plugin config api
  • loader for dynamically and schematically loading plugins.
  • logger for uniform output logging of plugins.
  • k-onfig is used to hint configuration schema.
  • Satori (EventType only) for instant messaging or chatbots

Dependencies

~2.3–8MB
~56K SLoC