changelog ```log 10.24 init 10.27 update 10.30 更新 rust 1.75 版本 ``` 目前能运行起来,并将 plugin 编写简化成和 事件回调 基本相同水平. ## trait plugin 必须实现 PHandle trait, 其返回值类型为 T (可也是 `()` 即无返回值) - `get_name`/ `plug_events` 均为返回 结构体成员, trait 中无法直接约束成员. - `handle_events` 的参数来自使用事件驱动的入参. ```rust pub(crate) trait PHandle { fn get_name(&self) -> &'static str; fn plug_events(&mut self) -> &PlugEvents; fn interested_events(&mut self) -> impl AsRef<[Event]>; fn handle_events<'a>( &'a mut self, packet: Option<&'a Packet<'a>>, // packet as a reference, need 'a lifetime session: Option>>, events: LinkedList, ) -> T; } ``` 在 PHandle trait 基础上,实现了 PHandleExt 提供了默认实现,将 PHandle 包装成了协程实现. - 具体实现在 `src/plugin/plugin.rs` ```rust pub trait PHandleExt { fn init(&mut self); // plugin.init // plugin.handle async fn handle<'a>( &'a mut self, packet: Option<&'a Packet<'a>>, // packet as a reference, need 'a lifetime session: Option>>, ) -> T where Self: 'a, T: 'a; } impl PHandleExt for A where A: PHandle, T: Default, // () already impl Default,so T = '()' is fine {} ``` PHandleExt 的 `int` 和 `handle` - rust 稳定版尚不能在 trait 中定义 async fn. [pull/115822](https://github.com/rust-lang/rust/pull/115822) 已合并进入主线,对应版本是 1.75. ~~这时 handle 应该定义为 async fn.~~ 已在更改并在 1.75 版本测试,上述代码应该能在 1.75 版本稳定版上运行. - ~~这里用了 nightly 一个 feature (type_alias_impl_trait) ,没有 dyn 的开销.~~ 不再定义为 type alias, 直接使用 impl trait. ## plugin 一个示例的 plugin ```rust pub struct ExamplePulgin { plugin_name: &'static str, plug_events: PlugEvents, // ctx can be a local variable or be given to slab for storage. Only references are retained here. // plugin_ctx: Option>>, } impl ExamplePulgin { pub fn new(plugin_name: &'static str) -> ExamplePulgin { ExamplePulgin {plugin_name,plug_events: PlugEvents::new(), } } } impl PHandle<()> for ExamplePulgin { fn get_name(&self) -> &'static str {self.plugin_name} fn plug_events(&mut self) -> &PlugEvents {&(self.plug_events)} fn interested_events(&mut self) -> impl AsRef<[Event]> { [ Event::TCPOpeningEvent, Event::TCPActiveEvent, Event::TCPExpireEvent, Event::TCPClosedEvent, Event::HTTPRequestEvent, ] } fn handle_events<'a>( &'a mut self, packet: Option<&'a crate::packet::packet::Packet<'a>>, // packet as a reference, need 'a lifetime session: Option>>, events: LinkedList, ) { let bind = session.unwrap(); let mut session = bind.try_borrow_mut().unwrap(); session.inc_session_c2s_metrics(0, 0, 1, 1); for event in events { match event {xxx} } } } ``` main 函数 ```rust fn main() { let ex = Executor::new(); ex.block_on(test1); } async fn test1() { println!("test1"); // plug 初始化 let mut plugin1 = ExamplePulgin::new("Plugin1"); let mut plugin2 = ExamplePulgin::new("Plugin2"); plugin1.init(); plugin2.init(); xxx // 其他初始化 while let Some(temp) = stream.next().await { let packet_pacp = temp.unwrap(); let mut packet = Packet::new(&packet_pacp, packet_pacp.len().try_into().unwrap()); let result = packet.handle(); // 解包 xx // 其他处理 let session = match packet.get_inner_most_tuple() { xx } // all plugs, maybe use join!() join!( plugin1.handle(Some(&packet), session.clone()), plugin2.handle(Some(&packet), session.clone()) ); } } ``` plugin 行为 - plugin 发送消息时,直接调用 `self.plug_events.trigger(Event::HTTPRequestEvent);`, 事件传递仅传递 event. - plugin 订阅自己产生的消息时,参数传递使用自身的 plugin_ctx,触发消息时存入 plugin_ctx, 再次进入时读取. - 不同 plugin 之间的依赖关系, 可以通过参数传递 或者使用 [local-sync](https://github.com/monoio-rs/local-sync) channel 进行. ```rust let a = plug.handle().await; b = plug1.handle(a).await; // or let (tx, rx) = channel(); plug.handle(tx).await; plug1.handle(rx).await; // or use join! ``` ## Event 将 event 与 usize 类型做了绑定, 取值范围从 0-127. 使用位图, 就绪的 event 和 plugin 的感兴趣的 event 可以使用两个 u128 的变量表示, 一次位操作就能得到 plugin 感兴趣且已经就绪的 event, 避免逐个查询. - 提供了 u128 到 `list` 的转换函数. - 对于 plugin 感兴趣但未就绪的 event, 注册一次性 waker,等待 event_mgr.dispatch 获取就绪 event 时触发. 将上述过程包装成 协程 提供给 plug 调用, plug 对 event 可以 `.await` 等待所有就绪的 event (有些类似 channel 的作用).