2016-04-23 7 views
1

私は錆を学んで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

またWSConnectionFactory構造体のWSHandlerへの参照を格納しながらconnection_madeからWSHandlerを返すようにしようとしています。 WSHandlerを返すことで、何が起こるのかを制御できないため(ポインタを無効にするために移動または削除する可能性があるため)、これは(ポインタを借りて)不可能です。値を直接格納するだけでよい場合は、借用したポインタも格納しています。

WSConnectionFactoryは、着信メッセージを処理し、任意のルールに従って他のクライアントに送信しWSHandler作成します。

他のクライアントにメッセージを送信する場合は、WSHandlerではなく、実際にはSenderが必要です。ありがたいことに、SenderCloneを実装しています。コードをすばやく見て、Senderをクローンすると、同じエンドポイントにもう一度「ハンドル」を付ける必要があります。したがって、SenderHashMapに入れてください。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

回答ありがとうございました。クローンがSenderに実装されていませんでした。 – Sergey

関連する問題