Как сохранить ссылку на обработчик в поле 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");
}