Add a leaderboard with Redis
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
parent
abf902c80e
commit
429fed7893
@ -0,0 +1,62 @@
|
||||
use async_trait::async_trait;
|
||||
use redis::{AsyncCommands, RedisError};
|
||||
use std::env;
|
||||
|
||||
const LEADERBOARD: &str = "leaderboard";
|
||||
type LeaderboardEntry = (String, i32);
|
||||
|
||||
#[async_trait]
|
||||
trait Leaderboard {
|
||||
async fn add_score(&self, player_name: &str, score: i32) -> Result<(), RedisError>;
|
||||
async fn get_highscores(&self) -> Result<Vec<LeaderboardEntry>, RedisError>;
|
||||
}
|
||||
|
||||
struct RedisLeaderboard {
|
||||
client: redis::Client,
|
||||
}
|
||||
|
||||
impl RedisLeaderboard {
|
||||
fn new(client: redis::Client) -> Self {
|
||||
Self { client }
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Leaderboard for RedisLeaderboard {
|
||||
async fn add_score(&self, player_name: &str, score: i32) -> Result<(), RedisError> {
|
||||
let mut con = self.client.get_async_connection().await?;
|
||||
con.zadd(LEADERBOARD, player_name, score).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_highscores(&self) -> Result<Vec<LeaderboardEntry>, RedisError> {
|
||||
let mut con = self.client.get_async_connection().await?;
|
||||
let count: isize = con.zcard(LEADERBOARD).await?;
|
||||
let leaderboard: Vec<LeaderboardEntry> =
|
||||
con.zrange_withscores(LEADERBOARD, 0, count - 1).await?;
|
||||
Ok(leaderboard)
|
||||
}
|
||||
}
|
||||
|
||||
struct InMemoryLeaderboard();
|
||||
|
||||
#[async_trait]
|
||||
impl Leaderboard for InMemoryLeaderboard {
|
||||
async fn add_score(&self, _: &str, _: i32) -> Result<(), RedisError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_highscores(&self) -> Result<Vec<LeaderboardEntry>, RedisError> {
|
||||
Ok(Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
async fn provide_leaderboard() -> Box<dyn Leaderboard> {
|
||||
match env::var("REDIS_HOSTNAME") {
|
||||
Ok(redis_host_name) => match redis::Client::open(format!("redis://{redis_host_name}/")) {
|
||||
Ok(client) => Box::new(RedisLeaderboard::new(client)),
|
||||
Err(_) => Box::new(InMemoryLeaderboard()),
|
||||
},
|
||||
Err(_) => Box::new(InMemoryLeaderboard()),
|
||||
}
|
||||
}
|
Loading…
Reference in new issue