1

我的意图是通过 WebSockets 接收事件并在main. 这在消息是纯文本 ( String) 时有效,但想法是将文本反序列化为一些结构。

在这个例子中,我只添加了Data,ErrorEvent,但在其他情况下,它可能会有所不同,所以我使用泛型来做到这一点,但我有点迷茫。编译器建议了我尝试过的几件事,但我不知道如何“强制”将消息转换为特定类型(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中看到

4

1 回答 1

2

有一些修复可以让它编译。

让它编译的技巧是使用更高等级的特征边界(HTRB)特征边界而不是声明'static生命周期。

遵循编译器建议并绑定T: serde::Deserialize<'_>特征:

impl<T> StreamHandler<Message, ProtocolError> for MyActor<T>
where
    for<'de> T: serde::Deserialize<'de> + 'static,

然后还使用 HTRB 特征绑定更改与 implDeserialize<'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,
于 2018-10-16T08:15:31.310 回答