2016-04-23 2 views
1

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

Ограничение: Я не могу изменить подпись характеристик Factory и Handler, потому что они предоставлены библиотекой 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"); 
} 
+0

спасибо за ответ, я пропустил, что Clone реализован для Sender. – Sergey

Смежные вопросы