reserved usernames
This commit is contained in:
parent
959d300455
commit
d930583e12
6 changed files with 44 additions and 24 deletions
|
@ -31,7 +31,7 @@ pub fn Auth() -> impl IntoView {
|
|||
})
|
||||
.unwrap(),
|
||||
);
|
||||
set_username.set(input.value());
|
||||
set_username.set("".to_string());
|
||||
input.set_value("");
|
||||
}
|
||||
}
|
||||
|
|
42
readme.md
42
readme.md
|
@ -4,12 +4,13 @@ A game master server for the popular game [Cards Against Humanity](https://www.c
|
|||
|
||||
This started as a problem trying to play games with friends who are all on different platforms. This shall be as cross-platform as it gets. I want it to work on anything that can establish a connection and allow anyone to write any front-end they can dream up whether it be a web page, chat bot, VR, etc. Any clients who share a master server can play together across any platform.
|
||||
|
||||
|
||||
## Test/Dev:
|
||||
|
||||
### Server
|
||||
|
||||
With auto-reload:
|
||||
* [Install cargo-watch](https://github.com/watchexec/cargo-watch?tab=readme-ov-file#install)
|
||||
|
||||
- [Install cargo-watch](https://github.com/watchexec/cargo-watch?tab=readme-ov-file#install)
|
||||
|
||||
Then:
|
||||
|
||||
|
@ -19,14 +20,15 @@ watch -i client -cx run
|
|||
|
||||
or if you're lazy like me just run `./test`
|
||||
|
||||
|
||||
Without auto-reload:
|
||||
|
||||
```sh
|
||||
cargo run
|
||||
```
|
||||
|
||||
### Client
|
||||
* [Install Trunk](https://trunkrs.dev/#install)
|
||||
|
||||
- [Install Trunk](https://trunkrs.dev/#install)
|
||||
|
||||
Then:
|
||||
|
||||
|
@ -37,31 +39,33 @@ trunk serve --open
|
|||
## Build:
|
||||
|
||||
### Client
|
||||
|
||||
```sh
|
||||
trunk build --release
|
||||
```
|
||||
|
||||
### Server
|
||||
|
||||
```sh
|
||||
cargo build
|
||||
```
|
||||
|
||||
----------
|
||||
* The server automatically serves the built client from `/dist` at `0.0.0.0:3030`
|
||||
---
|
||||
|
||||
* Configure any custom clients to connect to `ws://0.0.0.0:3030/websocket`
|
||||
- The server automatically serves the built client from `/dist` at `0.0.0.0:3030`
|
||||
|
||||
- Configure any custom clients to connect to `ws://0.0.0.0:3030/websocket`
|
||||
|
||||
## TODO:
|
||||
* finish game logic
|
||||
* prevent multiple users claiming the same identity and then all losing it - may create a zombie
|
||||
* prevent zombie users after browser crash
|
||||
* figure out proper auth - client's problem?
|
||||
* use db
|
||||
* test bincode and probably move away from json
|
||||
* make typescript sdk
|
||||
* support card text editing
|
||||
* prevent import of cards that have been seen already and edited
|
||||
* handle duplicates
|
||||
* efficiency
|
||||
* make demo clients for multiple platforms and screens
|
||||
|
||||
- finish game logic
|
||||
- prevent zombie users after browser crash
|
||||
- figure out proper auth - client's problem?
|
||||
- use db
|
||||
- test bincode and probably move away from json
|
||||
- make typescript sdk
|
||||
- support card text editing
|
||||
- prevent import of cards that have been seen already and edited
|
||||
- handle duplicates
|
||||
- efficiency
|
||||
- make demo clients for multiple platforms and screens
|
||||
|
|
|
@ -44,7 +44,7 @@ pub async fn on_websocket_connection(stream: WebSocket, state: Arc<AppState>, ad
|
|||
// Subscribe to receive from global broadcast channel
|
||||
let mut rx = state.tx.subscribe();
|
||||
|
||||
// Submit new messages from this client to broadcast
|
||||
// Send messages to this client
|
||||
let mut send_task = tokio::spawn(async move {
|
||||
while let Ok(msg) = rx.recv().await {
|
||||
if sender.send(Message::Text(msg)).await.is_err() {
|
||||
|
@ -53,7 +53,7 @@ pub async fn on_websocket_connection(stream: WebSocket, state: Arc<AppState>, ad
|
|||
}
|
||||
});
|
||||
|
||||
// Pass messages from broadcast down to this client
|
||||
// Receive messages from this client
|
||||
let mut recv_task = tokio::spawn(async move {
|
||||
while let Some(Ok(message)) = receiver.next().await {
|
||||
message_handler(state.clone(), addr, message)
|
||||
|
|
|
@ -132,6 +132,8 @@ fn handle_user_log_in(
|
|||
};
|
||||
|
||||
tracing::debug!("{msg}");
|
||||
} else if state.reserved_names.read().unwrap().contains(&new_name) {
|
||||
tracing::debug!("name is taken");
|
||||
} else {
|
||||
state
|
||||
.online_users
|
||||
|
@ -149,8 +151,16 @@ fn handle_user_log_in(
|
|||
new_name
|
||||
};
|
||||
|
||||
// Reserve name
|
||||
state
|
||||
.reserved_names
|
||||
.write()
|
||||
.unwrap()
|
||||
.insert(new_name.clone());
|
||||
|
||||
tracing::debug!("{msg}");
|
||||
tx.send(to_string::<ChatMessage>(&ChatMessage { text: msg })?)?;
|
||||
tracing::debug!("Name {} reserved.", &new_name);
|
||||
}
|
||||
|
||||
tracing::debug!(
|
||||
|
@ -159,6 +169,9 @@ fn handle_user_log_in(
|
|||
state.offline_users.read().unwrap().len()
|
||||
);
|
||||
tx.send(games_update(state))?;
|
||||
tx.send(chat_meta_update(state))?;
|
||||
|
||||
// send the user their new name
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use rand::prelude::IteratorRandom;
|
|||
use rand::thread_rng;
|
||||
use serde::Deserialize;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
collections::{HashMap, HashSet},
|
||||
fs::{read_to_string, File},
|
||||
io::{BufRead, BufReader},
|
||||
net::SocketAddr,
|
||||
|
@ -339,6 +339,7 @@ pub fn load_names(path: &str) -> Result<Vec<String>> {
|
|||
// Our shared state
|
||||
pub struct AppState {
|
||||
// We require unique usernames. This tracks which usernames have been taken.
|
||||
pub reserved_names: RwLock<HashSet<String>>,
|
||||
pub online_users: RwLock<HashMap<SocketAddr, Arc<RwLock<User>>>>,
|
||||
pub offline_users: RwLock<HashMap<String, Arc<RwLock<User>>>>,
|
||||
// Channel used to send messages to all connected clients.
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use anyhow::{Context, Result};
|
||||
use axum::{routing::get, Router};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
collections::{HashMap, HashSet},
|
||||
net::SocketAddr,
|
||||
sync::{Arc, RwLock},
|
||||
};
|
||||
|
@ -28,6 +28,7 @@ async fn main() -> Result<()> {
|
|||
// Set up application state for use with with_state().
|
||||
// Main Broadcast Channel
|
||||
let (tx, _rx) = broadcast::channel(100);
|
||||
let reserved_names = RwLock::new(HashSet::<String>::new());
|
||||
let online_users = RwLock::new(HashMap::<SocketAddr, Arc<RwLock<User>>>::new());
|
||||
let offline_users = RwLock::new(HashMap::<String, Arc<RwLock<User>>>::new());
|
||||
let (packs, packs_meta) = load_cards_from_json("data/cah-cards-full.json")?;
|
||||
|
@ -36,6 +37,7 @@ async fn main() -> Result<()> {
|
|||
let last_names = load_names("data/last.txt")?;
|
||||
|
||||
let app_state = Arc::new(AppState {
|
||||
reserved_names,
|
||||
online_users,
|
||||
offline_users,
|
||||
tx,
|
||||
|
|
Loading…
Add table
Reference in a new issue