Как сохранить ссылку на обработчик в поле hashmap

Я изучаю Rust и пытаюсь написать сервер websocket. Логика следующая: WSConnectionFactory создает WSHandler, который обрабатывает входящие сообщения и отправляет их другим клиентам в соответствии с произвольными правилами. Проблема в том, что я не знаю, как реализовать такое поведение.

Ограничение: Я не могу изменить сигнатуру черт Фабрики и Обработчика, потому что они предоставляются библиотекой ws-rs.

Вопрос: Как реализовать это с помощью RefCell/Cell?

extern crate rand;
extern crate rustc_serialize;
extern crate ws;
#[macro_use]
extern crate log;
#[macro_use]
extern crate env_logger;

use std::cell::RefCell;
use std::collections::HashMap;
use rand::random;
use ws::{Factory, Sender, Handler, Handshake, Message, CloseCode, WebSocket};
use ws::Result as WSResult;
use ws::util::Token;

struct WSConnectionFactory<'p> {
    handlers: HashMap<&'p u32, RefCell<&'p WSHandler<'p>>>,
}

#[derive(Debug)]
struct WSHandler<'h> {
    uid: &'h u32,
    ws: RefCell<&'h Sender>,
}

impl<'p> Factory for WSConnectionFactory<'p> {
    type Handler = WSHandler<'p>;

    fn connection_made(&mut self, ws: Sender) -> Self::Handler {
        println!("factory.connection_made token={:?}", &ws.token());
        let uid = &random::<u32>();
        let handler = WSHandler {
            uid: uid,
            ws: RefCell::new(&ws),
        };
        self.handlers.insert(uid, RefCell::new(&handler));
        handler
    }
}

impl<'h> Handler for WSHandler<'h> {
    fn on_open(&mut self, _handshake: Handshake) -> WSResult<()> {
        println!("handler.on_open");
        Ok(())
    }
    fn on_message(&mut self, msg: Message) -> WSResult<()> {
        println!("handler.on_message {:?}", msg);
        Ok(())
    }
    fn on_timeout(&mut self, _token: Token) -> WSResult<()> {
        println!("handler.on_timeout {:?}", _token);
        Ok(())
    }
    fn on_close(&mut self, code: CloseCode, reason: &str) {
        println!("handler.on_close code={:?}, reason={:?}", code, reason);
    }
}

fn main() {
    let factory = WSConnectionFactory { handlers: HashMap::new() };
    let ws_socket = WebSocket::new(factory).expect("Can't create WebSocket");
    ws_socket.listen("127.0.0.1:8080").expect("Can't bind to socket");
}

1 ответ

Решение

Вы пытаетесь вернуть WSHandler от connection_made сохраняя при этом ссылку на WSHandler в WSConnectionFactory структура. Это невозможно (с заимствованными указателями), потому что, возвращая WSHandler у вас нет контроля над тем, что с ним будет происходить (его можно переместить или отбросить, что сделает ваш указатель недействительным). Вы также храните заимствованные указатели, когда вы просто должны хранить значения напрямую.

WSConnectionFactory создает WSHandler которые обрабатывают входящие сообщения и отправляют их другим клиентам в соответствии с произвольными правилами.

Если вы хотите отправлять сообщения другим клиентам, вам действительно нужно Sender не WSHandler, К счастью, Sender инвентарь Clone и от быстрого просмотра кода, клонирования Sender должен дать вам второй "дескриптор" к той же конечной точке. Поэтому вы должны положить Sender в вашем HashMap не WSHandler,

extern crate rand;
extern crate rustc_serialize;
extern crate ws;
#[macro_use]
extern crate log;
#[macro_use]
extern crate env_logger;

use std::collections::HashMap;
use rand::random;
use ws::{Factory, Sender, Handler, Handshake, Message, CloseCode, WebSocket};
use ws::Result as WSResult;
use ws::util::Token;

struct WSConnectionFactory {
    handlers: HashMap<u32, Sender>,
}

#[derive(Debug)]
struct WSHandler {
    uid: u32,
    ws: Sender,
}

impl Factory for WSConnectionFactory {
    type Handler = WSHandler;

    fn connection_made(&mut self, ws: Sender) -> Self::Handler {
        println!("factory.connection_made token={:?}", &ws.token());
        let uid = random::<u32>();
        let handler = WSHandler {
            uid: uid,
            ws: ws.clone(),
        };
        self.handlers.insert(uid, ws);
        handler
    }
}

impl Handler for WSHandler {
    fn on_open(&mut self, _handshake: Handshake) -> WSResult<()> {
        println!("handler.on_open");
        Ok(())
    }
    fn on_message(&mut self, msg: Message) -> WSResult<()> {
        println!("handler.on_message {:?}", msg);
        Ok(())
    }
    fn on_timeout(&mut self, _token: Token) -> WSResult<()> {
        println!("handler.on_timeout {:?}", _token);
        Ok(())
    }
    fn on_close(&mut self, code: CloseCode, reason: &str) {
        println!("handler.on_close code={:?}, reason={:?}", code, reason);
    }
}

fn main() {
    let factory = WSConnectionFactory { handlers: HashMap::new() };
    let ws_socket = WebSocket::new(factory).expect("Can't create WebSocket");
    ws_socket.listen("127.0.0.1:8080").expect("Can't bind to socket");
}
Другие вопросы по тегам