向具有多个WebSocket引用的客户端发送消息

向具有多个WebSocket引用的客户端发送消息,websocket,rust,rust-tokio,rust-actix,actix-web,Websocket,Rust,Rust Tokio,Rust Actix,Actix Web,我在这里的问题是在使用actix web时遇到的 不幸的是,如果没有一个有点繁重的代码示例,我无法解释这一点,所以让我从这个开始 struct MyWs { game: Arc<RwLock<Game>>, } impl Actor for MyWs { type Context = ws::WebsocketContext<Self>; } impl StreamHandler<Result<ws::Message, ws::

我在这里的问题是在使用actix web时遇到的

不幸的是,如果没有一个有点繁重的代码示例,我无法解释这一点,所以让我从这个开始

struct MyWs {
    game: Arc<RwLock<Game>>,
}

impl Actor for MyWs {
    type Context = ws::WebsocketContext<Self>;
}

impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for MyWs {
    fn handle(&mut self, msg: Result<ws::Message, ws::ProtocolError>, ctx: &mut Self::Context) {
        match msg {
            Ok(ws::Message::Text(text)) => {
                debug!("Echoing text with {:?}", text);
                self.game.write().unwrap().some_method();
                ctx.text(text)
            },
            _ => (),
        }
    }
}

struct Game {
    websockets: Vec<Arc<RwLock<MyWs>>>,
}

impl Game {
    pub fn new() -> GameWrapper {
        GameWrapper {
            websockets: vec![],
        }
    }

    pub fn add_websocket(&mut self, my_ws: Arc<RwLock<MyWs>>) {
        self.websockets.push(my_ws);
    }

    pub fn some_method(&mut self) {
        // Do something to influence internal state.
        self.push_state();
    }

    pub fn push_state(&self) {
        for w in self.websockets {
            // I'm not sure about this part, idk how to access the
            // WebsocketContext with which I can send stuff back to the client.
            let game_state = get_game_state_or_something();
            w.write().unwrap().ctx.text(self.game_state);
        }
    }
}

struct GameWrapper {
    pub game: Arc<RwLock<Game>>,
}

impl GameWrapper {
    pub fn new(game: Arc<RwLock<Game>>) -> GameWrapper {
        GameWrapper { game }
    }
}

#[actix_rt::main]
async fn main() -> std::io::Result<()> {
    let game = Arc::new(RwLock::new(Game::new()));
    let game_wrapper = RwLock::new(GameWrapper::new(game.clone()));
    let game_wrapper_data = web::Data::new(game_wrapper);
    HttpServer::new(move || {
        App::new()
            .app_data(game_wrapper_data.clone())
            .route("/play_game", web::get().to(play_game))
    })
    .bind(ip_port)?
    .run()
    .await
}

pub async fn play_game(
    req: HttpRequest,
    stream: web::Payload,
    game_wrapper: web::Data<GameWrapper>,
) -> impl Responder {
    let my_ws = MyWs { game: game_wrapper.game.clone() };
    let my_ws = Arc::new(RwLock::new(my_ws));
    let mut game = game_wrapper.game.write().unwrap();
    game.add_websocket(my_ws);
    let resp = ws::start(my_ws, &req, stream);  // This is the problem.
    let resp = match resp {
        Ok(resp) => resp,
        Err(e) => return HttpResponse::from_error(e),
    };
    debug!("Successfully upgraded to websocket");
    resp
}
struct MyWs{
游戏:Arc,
}
MyWs的impl-Actor{
类型Context=ws::WebsocketContext;
}
MyWs的impl StreamHandler{
fn句柄(&mut self,msg:Result,ctx:&mut self::Context){
配味精{
确定(ws::Message::Text(Text))=>{
调试!(“用{:?}回显文本”,文本);
self.game.write().unwrap().some_方法();
ctx.text(text)
},
_ => (),
}
}
}
结构游戏{
WebSocket:Vec

  • 好的,所以我的困境的解决方案是改变我试图解决这个问题的方式,这并不奇怪。我真正需要的不是对websocket的多个引用,而是对持有websocket的每个参与者的引用。我想这就是你要做的,因为Actix是一个参与者框架

    这意味着代码应该如下所示:

    impl Game {
        ...
    
        pub fn register_actor(&mut self, actor: Addr<MyWs>) {
            self.actors.push(actor);
        }
    }
    
    pub async fn play_game(
        req: HttpRequest,
        stream: web::Payload,
        game_wrapper: web::Data<GameWrapper>,
    ) -> impl Responder {
        let my_ws = MyWs { game: game_wrapper.game.clone() };
        let my_ws = Arc::new(RwLock::new(my_ws));
        let mut game = game_wrapper.game.write().unwrap();
        let res = ws::start_with_addr(my_ws, &req, stream);
        let (addr, resp) = match res {
            Ok(res) => res,
            Err(e) => return HttpResponse::from_error(e),
        };
        game_manager.register_actor(handle, addr);
        debug!("Successfully upgraded to websocket");
        resp
    }
    
    impl游戏{
    ...
    发布fn寄存器\u参与者(&mut self,参与者:Addr){
    self.actors.push(actor);
    }
    }
    酒吧异步fn玩游戏(
    请求:HttpRequest,
    流:web::Payload,
    游戏包装器:web::Data,
    )->impl应答器{
    让my_ws=MyWs{game:game_wrapper.game.clone()};
    让my_ws=Arc::new(RwLock::new(my_ws));
    让mut game=game_wrapper.game.write().unwrap();
    让res=ws::用_addr(我的_-ws,&req,流)启动_;
    let(addr,resp)=匹配res{
    Ok(res)=>res,
    Err(e)=>返回HttpResponse::from_error(e),
    };
    游戏经理。注册演员(手柄,地址);
    调试!(“已成功升级到websocket”);
    响应
    }
    
    然后,您可以通过
    Addr
    向参与者发送消息


    我将把这个问题留一段时间,以防其他人对如何更好地完成整个任务有想法。

    我试图突破
    ws::start
    ,但我遇到了一个类似的问题:。您是如何通过Addr发送Websocket消息的?因为Addr是一个actix构造,Addr::send()获取一条actix::Message,而这条actix::Message没有实现。。。