2016-04-23 59 views
1

我正在学习Rust并试图编写websocket服务器。逻辑如下:WSConnectionFactory创建处理传入消息并根据任意规则将其发送到其他客户端的WSHandler。 问题是我不知道如何实现这样的行为。如何在散列表字段中保存对处理程序的引用

限制:我不能更改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

你正试图从connection_made返回WSHandler而在WSConnectionFactory结构也存储在WSHandler参考。这是不可能的(借用指针),因为通过返回WSHandler,你无法控制它会发生什么(它可能被移动或丢弃,这会使指针无效)。当你直接存储值时,你也会存储借用的指针。

WSConnectionFactory创建WSHandler它处理传入消息并根据任意规则将它们发送到其他客户端。

如果你想发送消息给其他客户端,你实际上需要一个Sender而不是WSHandler。幸运的是,Sender执行Clone,并且通过快速查看代码,克隆Sender应该为您提供第二个“处理”到相同的端点。因此,您应该在HashMap中输入Sender,而不是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

感谢您的回答,我错过了克隆是为发件人实施的。 – Sergey

相关问题