forked from deadvey/button
perf: use async locks
This commit is contained in:
+28
-23
@@ -2,8 +2,8 @@ use std::{
|
|||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fs,
|
fs,
|
||||||
io::Write,
|
io::Write,
|
||||||
sync::{Arc, Mutex, mpsc},
|
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use axum::{
|
use axum::{
|
||||||
@@ -19,7 +19,10 @@ use futures::StreamExt as _;
|
|||||||
use rand::random_bool;
|
use rand::random_bool;
|
||||||
use serde::{Deserialize, Serialize, de};
|
use serde::{Deserialize, Serialize, de};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use tokio::time::{Duration, sleep};
|
use tokio::{
|
||||||
|
sync::{Mutex, mpsc},
|
||||||
|
time::{Duration, sleep},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug, Ord, Eq, PartialEq, PartialOrd, Clone)]
|
#[derive(Deserialize, Serialize, Debug, Ord, Eq, PartialEq, PartialOrd, Clone)]
|
||||||
struct Entry {
|
struct Entry {
|
||||||
@@ -62,24 +65,23 @@ async fn main() {
|
|||||||
let loscores: Arc<Mutex<Vec<Entry>>> = read_file(PATH_LOSCORES);
|
let loscores: Arc<Mutex<Vec<Entry>>> = read_file(PATH_LOSCORES);
|
||||||
let pingscores: Arc<Mutex<HashMap<String, (u64, u32)>>> = read_file(PATH_PINGSCORES);
|
let pingscores: Arc<Mutex<HashMap<String, (u64, u32)>>> = read_file(PATH_PINGSCORES);
|
||||||
|
|
||||||
let (tx, rx) = mpsc::channel::<LeaderboardUpdate>();
|
let (tx, rx) = mpsc::channel::<LeaderboardUpdate>(1024);
|
||||||
|
|
||||||
{
|
{
|
||||||
let (hiscores, loscores, pingscores) =
|
let (hiscores, loscores, pingscores) =
|
||||||
(hiscores.clone(), loscores.clone(), pingscores.clone());
|
(hiscores.clone(), loscores.clone(), pingscores.clone());
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
handle_hiscores(rx, &hiscores, &loscores, &pingscores);
|
handle_hiscores(rx, &hiscores, &loscores, &pingscores).await;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let pingscores = pingscores.clone();
|
let pingscores = pingscores.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
loop
|
|
||||||
// write pingscores every 30s
|
// write pingscores every 30s
|
||||||
{
|
loop {
|
||||||
sleep(Duration::from_millis(30000)).await;
|
sleep(Duration::from_millis(30000)).await;
|
||||||
let pingscores = pingscores.lock().unwrap();
|
let pingscores = pingscores.lock().await;
|
||||||
let file_contents: String = serde_json::to_string(&pingscores.clone()).unwrap();
|
let file_contents: String = serde_json::to_string(&pingscores.clone()).unwrap();
|
||||||
drop(pingscores);
|
drop(pingscores);
|
||||||
let mut file = fs::OpenOptions::new()
|
let mut file = fs::OpenOptions::new()
|
||||||
@@ -119,8 +121,8 @@ async fn leaderboard() -> Html<&'static str> {
|
|||||||
Html(include_str!("../leaderboard.html"))
|
Html(include_str!("../leaderboard.html"))
|
||||||
}
|
}
|
||||||
// receiver: 0 for hiscore, 1 for loscore, 2 for pingscore
|
// receiver: 0 for hiscore, 1 for loscore, 2 for pingscore
|
||||||
fn handle_hiscores(
|
async fn handle_hiscores(
|
||||||
rx: mpsc::Receiver<LeaderboardUpdate>,
|
mut rx: mpsc::Receiver<LeaderboardUpdate>,
|
||||||
hiscores: &Mutex<Vec<Entry>>,
|
hiscores: &Mutex<Vec<Entry>>,
|
||||||
loscores: &Mutex<Vec<Entry>>,
|
loscores: &Mutex<Vec<Entry>>,
|
||||||
pingscores: &Mutex<HashMap<String, (u64, u32)>>,
|
pingscores: &Mutex<HashMap<String, (u64, u32)>>,
|
||||||
@@ -154,7 +156,7 @@ fn handle_hiscores(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Panic galore
|
// Panic galore
|
||||||
let mut hiscores_lock = hiscores.lock().unwrap();
|
let mut hiscores_lock = hiscores.lock().await;
|
||||||
hiscores_lock.sort();
|
hiscores_lock.sort();
|
||||||
hiscores_lock.reverse();
|
hiscores_lock.reverse();
|
||||||
let file_contents: String = serde_json::to_string(&hiscores_lock.clone()).unwrap();
|
let file_contents: String = serde_json::to_string(&hiscores_lock.clone()).unwrap();
|
||||||
@@ -168,24 +170,23 @@ fn handle_hiscores(
|
|||||||
drop(file);
|
drop(file);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let LeaderboardUpdate { name, update } = rx.recv().expect("channel error");
|
let LeaderboardUpdate { name, update } = rx.recv().await.expect("channel error");
|
||||||
|
|
||||||
match update {
|
match update {
|
||||||
LeaderboardUpdateType::Reset { hiscore_pingscore } => {
|
LeaderboardUpdateType::Reset { hiscore_pingscore } => {
|
||||||
// Hiscore
|
// Hiscore
|
||||||
update_scoretable(
|
update_scoretable(
|
||||||
"hiscore",
|
"hiscore",
|
||||||
hiscores.lock().unwrap(),
|
hiscores.lock().await,
|
||||||
&name,
|
&name,
|
||||||
hiscore_pingscore,
|
hiscore_pingscore,
|
||||||
PATH_HISCORES,
|
PATH_HISCORES,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Pingscore
|
// Pingscore
|
||||||
let mut pingscores = pingscores.lock().unwrap();
|
let mut pingscores = pingscores.lock().await;
|
||||||
if hiscore_pingscore > pingscores.get(&*name).unwrap_or(&(0, 0)).1
|
|
||||||
// pb
|
// pb
|
||||||
{
|
if hiscore_pingscore > pingscores.get(&*name).unwrap_or(&(0, 0)).1 {
|
||||||
pingscores.entry(name.to_string()).or_insert((0, 0)).1 = hiscore_pingscore;
|
pingscores.entry(name.to_string()).or_insert((0, 0)).1 = hiscore_pingscore;
|
||||||
println!("{name} new PB: {hiscore_pingscore}");
|
println!("{name} new PB: {hiscore_pingscore}");
|
||||||
};
|
};
|
||||||
@@ -196,7 +197,7 @@ fn handle_hiscores(
|
|||||||
LeaderboardUpdateType::Increment { loscore } => {
|
LeaderboardUpdateType::Increment { loscore } => {
|
||||||
update_scoretable(
|
update_scoretable(
|
||||||
"loscore",
|
"loscore",
|
||||||
loscores.lock().unwrap(),
|
loscores.lock().await,
|
||||||
&name,
|
&name,
|
||||||
loscore,
|
loscore,
|
||||||
PATH_LOSCORES,
|
PATH_LOSCORES,
|
||||||
@@ -229,9 +230,9 @@ async fn handle_socket(
|
|||||||
let mut value: u32 = 0;
|
let mut value: u32 = 0;
|
||||||
|
|
||||||
let msg = {
|
let msg = {
|
||||||
let hiscores = hiscores.lock().unwrap();
|
let hiscores = hiscores.lock().await;
|
||||||
let loscores = loscores.lock().unwrap();
|
let loscores = loscores.lock().await;
|
||||||
let pingscores = pingscores.lock().unwrap();
|
let pingscores = pingscores.lock().await;
|
||||||
json!({ "hiscores": &*hiscores, "loscores": &*loscores, "pingscores": &*pingscores})
|
json!({ "hiscores": &*hiscores, "loscores": &*loscores, "pingscores": &*pingscores})
|
||||||
.to_string()
|
.to_string()
|
||||||
};
|
};
|
||||||
@@ -258,12 +259,14 @@ async fn handle_socket(
|
|||||||
Ok(Message::Text(_)) => {
|
Ok(Message::Text(_)) => {
|
||||||
if random_bool(CHANCE) {
|
if random_bool(CHANCE) {
|
||||||
// reset
|
// reset
|
||||||
let _ = tx.send(LeaderboardUpdate {
|
let _ = tx
|
||||||
|
.send(LeaderboardUpdate {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
update: LeaderboardUpdateType::Reset {
|
update: LeaderboardUpdateType::Reset {
|
||||||
hiscore_pingscore: value,
|
hiscore_pingscore: value,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
.await;
|
||||||
resets += 1;
|
resets += 1;
|
||||||
value = 0
|
value = 0
|
||||||
}
|
}
|
||||||
@@ -271,10 +274,12 @@ async fn handle_socket(
|
|||||||
else {
|
else {
|
||||||
value += 1;
|
value += 1;
|
||||||
if prev == 0 {
|
if prev == 0 {
|
||||||
let _ = tx.send(LeaderboardUpdate {
|
let _ = tx
|
||||||
|
.send(LeaderboardUpdate {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
update: LeaderboardUpdateType::Increment { loscore: resets },
|
update: LeaderboardUpdateType::Increment { loscore: resets },
|
||||||
});
|
})
|
||||||
|
.await;
|
||||||
resets = 0;
|
resets = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user