| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 | use std::collections::BTreeMap;use std::time::{Duration, Instant};use std::sync::{Arc};use actix::prelude::*;use actix_web::{web, Error, HttpRequest, HttpResponse};use actix_web_actors::ws;use log::{debug, error};use crate::datasource;use crate::server::protocol::*;use crate::server::gamelobby::{GameLobby};use crate::server::messages::*;const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(5);const CLIENT_TIMEOUT: Duration = Duration::from_secs(10);pub async fn ws_initiate(server: web::Data<Addr<Server>>,                         r: HttpRequest,                         stream: web::Payload) -> Result<HttpResponse, Error> {    let res = ws::start(GameConnection::new(server.as_ref().clone()), &r, stream)?;    Ok(res)}pub struct Server {    pub lobbies: BTreeMap<String, Addr<GameLobby>>,    pub default_data: Arc<dyn datasource::DataSource<String>>}impl Actor for Server {    type Context = Context<Self>;    fn started(&mut self, _ctx: &mut Self::Context) {    }}impl Handler<JoinRequest> for Server {    type Result = ();    fn handle(&mut self, jr: JoinRequest, _ctx: &mut Self::Context) -> Self::Result {        let mb_lobby = self.lobbies.get(&jr.lobby_id);        match mb_lobby {            Some(lobby) => {                let _sent = lobby.do_send(jr);            },            None => {                jr.p.do_send(NoSuchLobby(jr.lobby_id));            }        }    }}impl Handler<CreateLobbyRequest> for Server {    type Result = ();    fn handle(&mut self, clr: CreateLobbyRequest, ctx: &mut Self::Context) -> Self::Result {        let existing_lobby = self.lobbies.get(&clr.lobby_id);        match existing_lobby {            Some(_) => {},            None => {                let lobby = GameLobby::new(clr.lobby_id.clone(), self.default_data.clone(), ctx.address());                let lobby_addr = lobby.start();                self.lobbies.insert(clr.lobby_id.clone(), lobby_addr.clone());                self.handle(JoinRequest {                    lobby_id: clr.lobby_id,                    nick: clr.nick,                    p: clr.p                }, ctx);            }        }    }}impl Handler<LobbyFinished> for Server {    type Result = ();    fn handle(&mut self, lf: LobbyFinished, _ctx: &mut Self::Context) -> Self::Result {        self.lobbies.remove(&lf.0);    }}////// connection to one single client/// pub struct GameConnection {    heartbeat: Instant,    nick: Option<String>,    game_id: Option<String>,    server: Addr<Server>,    game_lobby: Option<Addr<GameLobby>>}impl Actor for GameConnection {    type Context = ws::WebsocketContext<Self>;    fn started(&mut self, ctx: &mut Self::Context) {        self.initiate_heartbeat(ctx);    }}impl Handler<LobbyJoined> for GameConnection {    type Result = ();    fn handle(&mut self, gu: LobbyJoined, _ctx: &mut Self::Context) -> Self::Result {        self.game_lobby = Some(gu.lobby);        self.game_id = Some(gu.game_id);        self.nick = Some(gu.nick);    }}impl Handler<NoSuchLobby> for GameConnection {    type Result = ();    fn handle(&mut self, nsl: NoSuchLobby, ctx: &mut Self::Context) -> Self::Result {        self.send_message(&UpdateMessage::GameNotFound{ game_id: nsl.0 }, ctx);    }}impl Handler<GameAlreadyStartedMsg> for GameConnection {    type Result = ();    fn handle(&mut self, gas: GameAlreadyStartedMsg, ctx: &mut Self::Context) -> Self::Result {        self.send_message(&UpdateMessage::GameAlreadyStarted{ game_id: gas.0 }, ctx);    }}impl Handler<NickAlreadyExistsMsg> for GameConnection {    type Result = ();    fn handle(&mut self, naem: NickAlreadyExistsMsg, ctx: &mut Self::Context) -> Self::Result {        self.send_message(&UpdateMessage::NickAlreadyExists{ game_id: naem.game_id, nick: naem.nick }, ctx);    }}impl Handler<GameUpdate> for GameConnection {    type Result = ();    fn handle(&mut self, gu: GameUpdate, ctx: &mut Self::Context) -> Self::Result {        self.send_message(&UpdateMessage::GameState(gu.game_data), ctx);    }}impl Handler<PlayerListUpdate> for GameConnection {    type Result = ();    fn handle(&mut self, plu: PlayerListUpdate, ctx: &mut Self::Context) -> Self::Result {        self.send_message(&UpdateMessage::PlayerList(plu.player_list), ctx);    }}impl Handler<ResultMsg> for GameConnection {    type Result = ();    fn handle(&mut self, rm: ResultMsg, ctx: &mut Self::Context) -> Self::Result {        self.send_message(&UpdateMessage::RoundResult(rm.results), ctx);    }}impl Handler<StopMsg> for GameConnection {    type Result = ();    fn handle(&mut self, _sm: StopMsg, ctx: &mut Self::Context) -> Self::Result {        self.leave_lobby(ctx);        ctx.stop();    }}impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for GameConnection {    fn handle(        &mut self,        msg: Result<ws::Message, ws::ProtocolError>,        ctx: &mut Self::Context,    ) {        match msg {            Ok(ws::Message::Ping(msg)) => {                self.heartbeat = Instant::now();                ctx.pong(&msg);            }            Ok(ws::Message::Pong(_)) => {                self.heartbeat = Instant::now();            }            Ok(ws::Message::Text(text)) => {                debug!("received client message: {}", text);                self.received_message(&text, ctx);            },            Ok(ws::Message::Binary(bin)) => ctx.binary(bin),            Ok(ws::Message::Close(reason)) => {                self.leave_lobby(ctx);                ctx.close(reason);                ctx.stop();            }            _ => ctx.stop(),        }    }}impl GameConnection {    pub fn new(server_addr: Addr<Server>) -> Self {        GameConnection {            heartbeat: Instant::now(),            nick: None,            game_id: None,            server: server_addr,            game_lobby: None        }    }    pub fn initiate_heartbeat(&self, ctx: &mut <Self as Actor>::Context) {        ctx.run_interval(HEARTBEAT_INTERVAL, |act, ctx| {            if Instant::now().duration_since(act.heartbeat) > CLIENT_TIMEOUT {                ctx.address().do_send(StopMsg);                return;            }            ctx.ping(b"");        });    }    pub fn send_message(&self, m: &UpdateMessage, ctx: &mut <Self as Actor>::Context) {        let txt = serde_json::to_string(m).unwrap();        debug!("sending message to client {}", txt);        ctx.text(txt);    }    pub fn received_message(&mut self, text: &str, ctx: &mut <Self as Actor>::Context) {        let parsed: Result<ClientMessage, _> = serde_json::from_str(text);        if let Ok(msg) = parsed {            match msg {                ClientMessage::CreateGame{game_id, nick} => {                    if nick != "" && game_id != "" {                        self.game_id = Some(game_id.clone());                        self.nick = Some(nick.clone());                        self.server.do_send(CreateLobbyRequest {                            lobby_id: game_id.clone(),                            nick: nick.clone(),                            p: ctx.address()                        });                    }                },                ClientMessage::Join{game_id, nick} => {                    if nick != "" {                        self.server.do_send(JoinRequest{ lobby_id: game_id.clone(), nick: nick.clone(), p: ctx.address() });                        self.game_id = Some(game_id.clone());                        self.nick = Some(nick);                    }                },                ClientMessage::LeaveLobby => {                    self.leave_lobby(ctx);                },                ClientMessage::Ready => {                    if let Some(lobby) = &self.game_lobby {                        if let Some(nick) = &self.nick {                            lobby.do_send(ReadyMsg(nick.clone()));                        }                    }                },                ClientMessage::Unready => {                    if let Some(lobby) = &self.game_lobby {                        if let Some(nick) = &self.nick {                            lobby.do_send(UnreadyMsg(nick.clone()));                        }                    }                },                ClientMessage::Reveal => {                    if let Some(lobby) = &self.game_lobby {                        if let Some(nick) = &self.nick {                            lobby.do_send(RevealMsg(nick.clone()));                        }                    }                },                ClientMessage::SubmitWord{ word } => {                    if let Some(lobby) = &self.game_lobby {                        if let Some(nick) = &self.nick {                            lobby.do_send(SubmitWordMsg{ word: word, nick: nick.clone() });                        }                    }                },                ClientMessage::SubmitGuess{ guesses } => {                    if let Some(lobby) = &self.game_lobby {                        if let Some(nick) = &self.nick {                            lobby.do_send(SubmitGuessMsg{ guesses: guesses, nick: nick.clone() });                        }                    }                }            }        }        else {            error!("error parsing json: {}", text);        }    }    pub fn leave_lobby(&mut self, ctx: &mut <Self as Actor>::Context) {        if let Some(lobby) = &self.game_lobby {            if let Some(nick) = &self.nick {                lobby.do_send(LeaveMsg(nick.clone()));                self.send_message(&UpdateMessage::LeftLobby{ nick: nick.clone() }, ctx);            }        }    }}
 |