我的意图是通过WebSocket接收事件,并在main
的闭包上使用它们。
当消息为纯文本(String
)时,此方法有效,但想法是将该文本反序列化为某些结构。
在此示例中,我仅添加了Data
,Error
和Event
,但是在其他情况下,它可能有所不同,因此我使用了泛型来做到这一点,但是我有点迷路了。编译器已经提出了我尝试过的一些建议,但是我不知道如何“强制”将消息强制转换为特定类型(在此示例中为Data
,但是EventManager
可能是在其他部分上使用,因此应该是通用的。
我已经附上了这段代码,试图显示我的想法,尽管它没有编译:
events.rs
:
use actix::*;
use actix_web::ws::{Client, Message, ProtocolError};
use futures::Future;
use serde::de;
use serde_json::from_str;
struct MyActor<T> {
manager: EventManager<T>,
}
impl<T: 'static> Actor for MyActor<T> {
type Context = Context<Self>;
}
impl<T: 'static> StreamHandler<Message, ProtocolError> for MyActor<T> {
fn handle(&mut self, msg: Message, _ctx: &mut Context<Self>) {
match msg {
Message::Text(text) => {
debug!("Received {}", text);
for idx in 0..self.manager.events.len() {
let data =
from_str(&text).expect(&format!("Error when deserializing {:?}", text));
(self.manager.events[idx].handler)(data)
}
}
_ => panic!(),
}
}
}
pub struct Event<T> {
handler: Box<Fn(T) + 'static>,
}
pub struct EventManager<T> {
events: Vec<Event<T>>,
}
impl<T: 'static> EventManager<T>
where
T: serde::Deserialize<'static>,
{
pub fn new() -> Self {
Self { events: vec![] }
}
pub fn capture<F>(&mut self, function: F)
where
F: for<'h> Fn(T) + 'static,
{
let event = Event {
handler: Box::new(function),
};
self.events.push(event);
}
pub fn run(self) {
let runner = System::new("example");
debug!("run");
Arbiter::spawn(
Client::new("example")
.connect()
.map(|(reader, _writer)| {
MyActor::create(|ctx| {
MyActor::add_stream(reader, ctx);
MyActor { manager: self }
});
})
.map_err(|err| {}),
);
runner.run();
}
}
main.rs
:
#[macro_use]
extern crate log;
extern crate actix;
extern crate actix_web;
extern crate env_logger;
extern crate futures;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
pub mod events;
use actix::*;
use serde::de;
use serde::de::{Deserialize, Deserializer};
use events::EventManager;
#[derive(Debug, Message, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Data {
Error(Error),
Event(Event),
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Error {
message: String,
code: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Event {
name: String,
content: String,
}
fn main() {
env_logger::init();
let mut client = EventManager::<Data>new();
client.capture(|data| debug!("event: {:?}", data));
client.run();
}
所有代码都可以在https://github.com/foochi/how-deserialize-within-actix
中看到答案 0 :(得分:1)
有一些修复程序可以使其编译。
进行编译的诀窍是使用Higher-Rank Trait Bounds (HTRB)特质范围而不是声明'static
的生存期。
遵循编译器建议并绑定T: serde::Deserialize<'_>
特性:
impl<T> StreamHandler<Message, ProtocolError> for MyActor<T>
where
for<'de> T: serde::Deserialize<'de> + 'static,
然后更改与具有HTRB特性的Deserialize<'static>
关联的EventManager
特性绑定,使其与StreamHandler
实现的要求兼容:
impl<T: 'static> EventManager<T>
where
for<'de> T: serde::Deserialize<'de>,
最后,如果您更正了该行,请使用正确的sintax创建客户端:
let mut client: EventManager<Data> = EventManager::new();
示例代码应编译。
注意:对于capture
,使用较高特质约束来声明Fn
的要求是多余的,只需执行以下操作:
pub fn capture<F>(&mut self, function: F)
where
F: Fn(T) + 'static,