代码之家  ›  专栏  ›  技术社区  ›  Sergey

如何在hashmap字段中保存对处理程序的引用

  •  1
  • Sergey  · 技术社区  · 8 年前

    我正在学习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 回复  |  直到 8 年前
        1
  •  1
  •   Francis Gagné    8 年前

    您正在尝试返回 WSHandler 从…起 connection_made 同时还存储对 WS处理程序 WSConnectionFactory 结构。这是不可能的(使用借用的指针),因为通过返回 WS处理程序 ,您无法控制它将发生什么(它可能被移动或删除,这将使指针无效)。当您应该直接存储值时,您也在存储借用的指针。

    WSConnectionFactory(WS连接工厂) 创建 WS处理程序 它处理传入消息并根据任意规则将其发送给其他客户端。

    如果您想向其他客户端发送消息,实际上需要 Sender ,不是 WS处理程序 谢天谢地 发件人 机具 Clone ,通过快速查看代码,克隆 发件人 应该为同一端点提供第二个“句柄”。因此,您应该将 发件人 在您的 HashMap ,不是 WS处理程序 .

    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");
    }