From 27d6ba4248dce846c3be11f7d885a808523aa6a5 Mon Sep 17 00:00:00 2001 From: Geoffrey Allott Date: Sat, 27 Feb 2021 13:38:48 +0000 Subject: [PATCH] store ids in game list and settings in separate structure --- src/server.rs | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/server.rs b/src/server.rs index 36e9ed7..42bb1fa 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use std::convert::TryFrom; -use futures::{channel::mpsc::{Receiver, Sender, channel}, SinkExt}; +use futures::{channel::mpsc::{Receiver, Sender, channel}, SinkExt, future::try_join_all}; use redis::{AsyncCommands, ErrorKind, FromRedisValue, Msg, RedisError, RedisResult, RedisWrite, Script, ToRedisArgs, Value, aio::MultiplexedConnection}; use serde::{Serialize, Deserialize}; @@ -47,12 +47,12 @@ impl TryFrom for ClientInterest { type Error = ClientInterestFromMsgError; fn try_from(msg: Msg) -> Result { let channel_name = msg.get_channel_name(); - if channel_name == "__keyspace@0__:games" { + if channel_name == "__keyspace@0__:game:list" { Ok(ClientInterest::GameList) } else if let Some(username) = channel_name.strip_prefix("__keyspace@0__:user:") { username.parse().map_err(ClientInterestFromMsgError::UsernameParseError) .map(|username| ClientInterest::User{username}) - } else if let Some(Ok(id)) = channel_name.strip_prefix("__keyspace@0__:game:").map(str::parse) { + } else if let Some(Ok(id)) = channel_name.strip_prefix("__keyspace@0__:game:").and_then(|str| str.strip_suffix(":actions")).map(str::parse) { Ok(ClientInterest::Game{id}) } else { Err(ClientInterestFromMsgError::InvalidChannelName{channel_name: channel_name.to_string()}) @@ -65,8 +65,8 @@ impl ToRedisArgs for ClientInterest { where W: ?Sized + RedisWrite { match self { - ClientInterest::GameList => out.write_arg(b"__keyspace@0__:games"), - ClientInterest::Game{id} => out.write_arg_fmt(format!("__keyspace@0__:game:{}", id)), + ClientInterest::GameList => out.write_arg(b"__keyspace@0__:game:list"), + ClientInterest::Game{id} => out.write_arg_fmt(format!("__keyspace@0__:game:{}:actions", id)), ClientInterest::User{username} => out.write_arg_fmt(format!("__keyspace@0__:user:{}", username)), } } @@ -113,8 +113,12 @@ fn user_key(username: Username) -> String { format!("user:{}", username) } -fn game_key(id: u32) -> String { - format!("game:{}", id) +fn game_settings_key(id: u32) -> String { + format!("game:{}:settings", id) +} + +fn game_actions_key(id: u32) -> String { + format!("game:{}:actions", id) } impl ServerState { @@ -149,28 +153,36 @@ impl ServerState { } pub async fn create_game(&mut self, settings: GameSettings) -> RedisResult { - self.redis.rpush("games", AsJson(settings)).await.map(|i: u32| i - 1) + let id = self.redis.incr("game:next_id", 1u32).await?; + let key = game_settings_key(id); + let () = self.redis.set(key, AsJson(settings)).await?; + let () = self.redis.rpush("game:list", id).await?; + Ok(id) } pub async fn game_list(&mut self, from: usize) -> RedisResult> { debug!("game_list(from: {})", from); - let games: Vec> = self.redis.lrange("games", from as isize, -1).await?; - Ok(games.into_iter().map(AsJson::get).enumerate().map(|(id, settings)| GameSummary::new((from + id) as u32, settings)).collect()) + let games: Vec = self.redis.lrange("game:list", from as isize, -1).await?; + let mut summaries = Vec::new(); + for id in games { + summaries.push(self.game_summary(id).await?); + } + Ok(summaries) } pub async fn game_state(&mut self, id: u32, from: usize) -> RedisResult> { - let key = game_key(id); + let key = game_actions_key(id); let actions: Vec> = self.redis.lrange(&key, from as isize, -1).await?; Ok(actions.into_iter().map(AsJson::get).collect()) } pub async fn game_summary(&mut self, id: u32) -> RedisResult { - let settings = self.redis.lindex("games", id as isize).await.map(AsJson::get)?; - Ok(GameSummary::new(id, settings)) + let key = game_settings_key(id); + self.redis.get(key).await.map(AsJson::get).map(|settings| GameSummary::new(id, settings)) } pub async fn take_action(&mut self, id: u32, len: usize, action: &ValidatedUserAction) -> RedisResult { - let key = game_key(id); + let key = game_actions_key(id); debug!("take_action: EVAL {{TAKE_ACTION_LUA_SCRIPT}} 1 {} {} {:?}", key, len, action); self.take_action_script.key(key).arg(len).arg(AsJson(action)).invoke_async(&mut self.redis).await } -- 2.34.1