Как отправлять события сервера, используя Rust с Actix web и WebSockets? - PullRequest
1 голос
/ 17 октября 2019

Я использую Rust с Actix web и хотел бы использовать WebSockets для событий сервера, главным образом сообщений о состоянии, которые отправляются клиенту. Я придерживался базовой структуры:

struct StatusWS {}

impl Actor for StatusWS {
    type Context = ws::WebsocketContext<Self>;

    fn started(&mut self, ctx: &mut Self::Context) {
        // How to keep track of ctx???
    }
}

Когда клиент подключается, вызывается функция start (), и я могу отправлять оттуда сообщения с помощью ctx.text () и т. Д. Однако мне нужно отслеживатьконтекста, чтобы отправить сообщения позже. Как мне это сделать? Он передается в качестве ссылки, поэтому средство проверки заимствований не позволит мне многое с этим сделать.

1 Ответ

0 голосов
/ 17 октября 2019

Это глубокие воды для меня, но я думаю, что вам нужно impl Обработчик for StatusWS. Затем вы можете использовать Addr , который вы получите в качестве возвращаемого значения, когда вы .start() ваш Actor для отправки сообщений на него. Тогда вы в конечном итоге будете использовать handle метод Handler, который имеет доступ к ctx, и вы можете отправить свое сообщение ws.

Я сам изучаю Rust и Actix, так что это может не произойтибыть, как вы на самом деле это делаете. Дайте мне знать, как это происходит.

[Редактировать] Я понимаю, что мой ответ был довольно унылым, поэтому я привел пример, который может быть полезен для других.

use actix::prelude::*;
use actix_web::{middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer};
use actix_web_actors::ws;
use std::time::Duration;

fn ws_index(
    r: HttpRequest,
    stream: web::Payload,
    data: web::Data<Addr<ServerMonitor>>,
) -> Result<HttpResponse, Error> {
    let (addr, res) = ws::start_with_addr(MyWebSocket {}, &r, stream)?;

    data.get_ref().do_send(RegisterWSClient { addr: addr });

    Ok(res)
}

struct MyWebSocket {}

impl Actor for MyWebSocket {
    type Context = ws::WebsocketContext<Self>;
}

impl StreamHandler<ws::Message, ws::ProtocolError> for MyWebSocket {
    fn handle(&mut self, msg: ws::Message, ctx: &mut Self::Context) {
        println!("WS: {:?}", msg);
        match msg {
            ws::Message::Ping(msg) => {
                ctx.pong(&msg);
            }
            ws::Message::Pong(_) => {}
            ws::Message::Text(text) => ctx.text(text),
            ws::Message::Binary(bin) => ctx.binary(bin),
            ws::Message::Close(_) => {
                ctx.stop();
            }
            ws::Message::Nop => (),
        }
    }
}

impl Handler<ServerEvent> for MyWebSocket {
    type Result = ();

    fn handle(&mut self, msg: ServerEvent, ctx: &mut Self::Context) {
        ctx.text(msg.event);
    }
}

#[derive(Message)]
struct RegisterWSClient {
    addr: Addr<MyWebSocket>,
}

#[derive(Message)]
struct ServerEvent {
    event: String,
}

struct ServerMonitor {
    listeners: Vec<Addr<MyWebSocket>>,
}

impl Actor for ServerMonitor {
    type Context = Context<Self>;

    fn started(&mut self, ctx: &mut Self::Context) {
        ctx.run_interval(Duration::from_secs(5), |act, _| {
            for l in &act.listeners {
                l.do_send(ServerEvent{ event: String::from("Event:") });
            }
        });
    }
}

impl Handler<RegisterWSClient> for ServerMonitor {
    type Result = ();

    fn handle(&mut self, msg: RegisterWSClient, _: &mut Context<Self>) {
        self.listeners.push(msg.addr);
    }
}

fn main() -> std::io::Result<()> {
    std::env::set_var("RUST_LOG", "actix_server=info,actix_web=info");
    env_logger::init();

    let sys = actix_rt::System::new("example");

    let srvmon = ServerMonitor { listeners: vec![] }.start();

    HttpServer::new(move || {
        App::new()
            .data(srvmon.clone())
            .wrap(middleware::Logger::default())
            .service(web::resource("/ws/").route(web::get().to(ws_index)))
    })
    .bind("127.0.0.1:8080")?
    .start();

    sys.run()
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...