server.rs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. use std::collections::BTreeMap;
  2. use std::collections::BTreeSet;
  3. use std::time::{Duration, Instant};
  4. use std::sync::{Mutex, RwLock, Arc};
  5. use actix::dev::{MessageResponse, ResponseChannel};
  6. use actix::prelude::*;
  7. use actix_web::{web, Error, HttpRequest, HttpResponse};
  8. use actix_web_actors::ws;
  9. use rand::thread_rng;
  10. use rand::seq::SliceRandom;
  11. use crate::game;
  12. use crate::websocket;
  13. use crate::websocket::*;
  14. const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(5);
  15. const CLIENT_TIMEOUT: Duration = Duration::from_secs(10);
  16. #[derive(Message)]
  17. #[rtype(result = "Answer")]
  18. struct JoinRequest{ lobby_id: String, nick: String, p: Addr<GameConnection> }
  19. #[derive(Message)]
  20. #[rtype(result = "Answer")]
  21. struct CreateLobbyRequest{ lobby_id: String, p: Addr<GameConnection> }
  22. #[derive(Message)]
  23. #[rtype(result = "()")]
  24. struct SubmitWordMsg{ word: String, nick: String }
  25. #[derive(Message)]
  26. #[rtype(result = "Result<game::Game, ()>")]
  27. struct GetGame;
  28. #[derive(Message)]
  29. #[rtype(result = "()")]
  30. struct LobbyJoined(Addr<GameLobby>);
  31. #[derive(Message)]
  32. #[rtype(result = "()")]
  33. struct GameUpdate{ game_data: GameData }
  34. enum Answer {
  35. LobbyJoined(Addr<GameLobby>),
  36. LobbyCreated(Addr<GameLobby>),
  37. LobbyAlreadyExists,
  38. NoSuchLobby,
  39. }
  40. impl<A, M> MessageResponse<A, M> for Answer
  41. where
  42. A: Actor,
  43. M: Message<Result = Answer>,
  44. {
  45. fn handle<R: ResponseChannel<M>>(self, _: &mut A::Context, tx: Option<R>) {
  46. if let Some(tx) = tx {
  47. tx.send(self);
  48. }
  49. }
  50. }
  51. impl<A, M> MessageResponse<A, M> for game::Game
  52. where
  53. A: Actor,
  54. M: Message<Result = game::Game>,
  55. {
  56. fn handle<R: ResponseChannel<M>>(self, _: &mut A::Context, tx: Option<R>) {
  57. if let Some(tx) = tx {
  58. tx.send(self);
  59. }
  60. }
  61. }
  62. pub struct Server {
  63. pub lobbies: BTreeMap<String, Addr<GameLobby>>,
  64. }
  65. impl Actor for Server {
  66. type Context = Context<Self>;
  67. fn started(&mut self, ctx: &mut Self::Context) {
  68. }
  69. }
  70. impl Handler<JoinRequest> for Server {
  71. type Result = Answer;
  72. fn handle(&mut self, jr: JoinRequest, ctx: &mut Self::Context) -> Self::Result {
  73. let mb_lobby = self.lobbies.get(&jr.lobby_id);
  74. match mb_lobby {
  75. Some(lobby) => {
  76. let _sent = lobby.do_send(jr);
  77. Answer::LobbyJoined(lobby.clone())
  78. },
  79. None => Answer::NoSuchLobby
  80. }
  81. }
  82. }
  83. impl Handler<CreateLobbyRequest> for Server {
  84. type Result = Answer;
  85. fn handle(&mut self, clr: CreateLobbyRequest, ctx: &mut Self::Context) -> Self::Result {
  86. let existing_lobby = self.lobbies.get(&clr.lobby_id);
  87. match existing_lobby {
  88. Some(_) => Answer::LobbyAlreadyExists,
  89. None => {
  90. let lobby = GameLobby::new(clr.lobby_id.clone());
  91. let lobby_addr = lobby.start();
  92. self.lobbies.insert(clr.lobby_id.clone(), lobby_addr.clone());
  93. Answer::LobbyCreated(lobby_addr)
  94. }
  95. }
  96. }
  97. }
  98. pub struct GameLobby {
  99. connected_players: BTreeMap<String, Addr<GameConnection>>,
  100. game_id: String,
  101. game: game::Game,
  102. }
  103. impl Actor for GameLobby {
  104. type Context = Context<Self>;
  105. fn started(&mut self, ctx: &mut Self::Context) {
  106. self.game.new_round();
  107. }
  108. }
  109. impl Handler<JoinRequest> for GameLobby {
  110. type Result = Answer;
  111. fn handle(&mut self, jr: JoinRequest, ctx: &mut Self::Context) -> Self::Result {
  112. jr.p.do_send(LobbyJoined(ctx.address()));
  113. self.connected_players.insert(jr.nick.clone(), jr.p);
  114. self.game.player_join(jr.nick);
  115. self.send_game_to_all();
  116. Answer::LobbyJoined(ctx.address())
  117. }
  118. }
  119. impl Handler<GetGame> for GameLobby {
  120. type Result = Result<game::Game, ()>;
  121. fn handle(&mut self, gg: GetGame, ctx: &mut Self::Context) -> Self::Result {
  122. Ok(self.game.clone())
  123. }
  124. }
  125. impl Handler<SubmitWordMsg> for GameLobby {
  126. type Result = ();
  127. fn handle(&mut self, swm: SubmitWordMsg, ctx: &mut Self::Context) -> Self::Result {
  128. self.game.submit_creation(&swm.nick, swm.word);
  129. if self.game.all_submitted() {
  130. self.game.next_state();
  131. self.send_game_to_all();
  132. }
  133. }
  134. }
  135. impl GameLobby {
  136. pub fn new(gi: String) -> Self {
  137. GameLobby {
  138. connected_players: BTreeMap::new(),
  139. game_id: gi,
  140. game: game::Game::new()
  141. }
  142. }
  143. pub fn send_game_to_all(&self) {
  144. for (nick, player) in &self.connected_players {
  145. let game_state = self.create_opaque_message(nick);
  146. player.do_send(GameUpdate{ game_data: game_state });
  147. }
  148. }
  149. pub fn create_opaque_message(&self, nick: &str) -> GameData {
  150. GameData {
  151. players: self.game.players.iter().map(|p| websocket::PlayerData{ nick: p.nick.clone(), points: 0 }).collect::<Vec<_>>(),
  152. state_data: match self.game.state {
  153. game::GameState::Creating => {
  154. GameStateData::Creating{
  155. question: "Ein Gerät um Elche zu häuten".to_owned(),
  156. available_chars: vec!['a', 'b', 'c']
  157. }
  158. },
  159. game::GameState::Guessing => {
  160. self.create_guessing()
  161. },
  162. }
  163. }
  164. }
  165. pub fn create_guessing(&self) -> GameStateData {
  166. let chars = self.game.round.exercises.iter()
  167. .map(|x| x.letters.clone())
  168. .collect::<Vec<_>>();
  169. let words_with_chars = self.game.players.iter()
  170. .map(|p| p.submitted_word.clone().unwrap_or("".to_owned()))
  171. .zip(chars)
  172. .collect::<Vec<_>>();
  173. let mut questions = self.game.round.exercises.iter()
  174. .map(|x| x.question.clone())
  175. .collect::<Vec<_>>();
  176. questions.shuffle(&mut thread_rng());
  177. GameStateData::Guessing {
  178. submitted_words: words_with_chars,
  179. questions: questions
  180. }
  181. }
  182. }
  183. ///
  184. /// connection to one single client
  185. ///
  186. pub struct GameConnection {
  187. heartbeat: Instant,
  188. nick: Option<String>,
  189. game_id: Option<String>,
  190. server: Addr<Server>,
  191. game_lobby: Option<Addr<GameLobby>>
  192. }
  193. impl Actor for GameConnection {
  194. type Context = ws::WebsocketContext<Self>;
  195. fn started(&mut self, ctx: &mut Self::Context) {
  196. self.initiate_heartbeat(ctx);
  197. }
  198. }
  199. impl Handler<LobbyJoined> for GameConnection {
  200. type Result = ();
  201. fn handle(&mut self, gu: LobbyJoined, ctx: &mut Self::Context) -> Self::Result {
  202. self.game_lobby = Some(gu.0);
  203. }
  204. }
  205. impl Handler<GameUpdate> for GameConnection {
  206. type Result = ();
  207. fn handle(&mut self, gu: GameUpdate, ctx: &mut Self::Context) -> Self::Result {
  208. self.send_message(&UpdateMessage::GameState(gu.game_data), ctx);
  209. }
  210. }
  211. impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for GameConnection {
  212. fn handle(
  213. &mut self,
  214. msg: Result<ws::Message, ws::ProtocolError>,
  215. ctx: &mut Self::Context,
  216. ) {
  217. match msg {
  218. Ok(ws::Message::Ping(msg)) => {
  219. self.heartbeat = Instant::now();
  220. ctx.pong(&msg);
  221. }
  222. Ok(ws::Message::Pong(_)) => {
  223. self.heartbeat = Instant::now();
  224. }
  225. Ok(ws::Message::Text(text)) => {
  226. println!("hmmm: {:?}", text);
  227. self.received_message(&text, ctx);
  228. },
  229. Ok(ws::Message::Binary(bin)) => ctx.binary(bin),
  230. Ok(ws::Message::Close(reason)) => {
  231. ctx.close(reason);
  232. ctx.stop();
  233. }
  234. _ => ctx.stop(),
  235. }
  236. }
  237. }
  238. impl GameConnection {
  239. pub fn new(server_addr: Addr<Server>) -> Self {
  240. GameConnection {
  241. heartbeat: Instant::now(),
  242. nick: None,
  243. game_id: None,
  244. server: server_addr,
  245. game_lobby: None
  246. }
  247. }
  248. pub fn initiate_heartbeat(&self, ctx: &mut <Self as Actor>::Context) {
  249. ctx.run_interval(HEARTBEAT_INTERVAL, |act, ctx| {
  250. if Instant::now().duration_since(act.heartbeat) > CLIENT_TIMEOUT {
  251. //println!("Websocket Client heartbeat failed, disconnecting!");
  252. ctx.stop();
  253. return;
  254. }
  255. ctx.ping(b"");
  256. });
  257. }
  258. pub fn send_message(&self, m: &UpdateMessage, ctx: &mut <Self as Actor>::Context) {
  259. let txt = serde_json::to_string(m).unwrap();
  260. println!("{:?}", txt);
  261. ctx.text(txt);
  262. }
  263. pub fn received_message(&mut self, text: &str, ctx: &mut <Self as Actor>::Context) {
  264. let parsed: Result<ClientMessage, _> = serde_json::from_str(text);
  265. if let Ok(msg) = parsed {
  266. match msg {
  267. ClientMessage::CreateGame{game_id, nick} => {
  268. self.game_id = Some(game_id.clone());
  269. self.nick = Some(nick);
  270. self.server.do_send(CreateLobbyRequest{ lobby_id: game_id.clone(), p: ctx.address() });
  271. },
  272. ClientMessage::Join{game_id, nick} => {
  273. self.server.do_send(JoinRequest{ lobby_id: game_id.clone(), nick: nick.clone(), p: ctx.address() });
  274. self.game_id = Some(game_id.clone());
  275. self.nick = Some(nick);
  276. },
  277. ClientMessage::SubmitWord{ word } => {
  278. match &self.game_lobby {
  279. Some(lobby) => {
  280. if let Some(nick) = &self.nick {
  281. lobby.do_send(SubmitWordMsg{ word: word, nick: nick.clone() });
  282. }
  283. },
  284. None => {
  285. }
  286. }
  287. },
  288. ClientMessage::SubmitGuess{ guesses } => {
  289. }
  290. }
  291. }
  292. else {
  293. println!("error parsing json");
  294. }
  295. }
  296. }