1
0
Fork 0
mirror of https://codeberg.org/demostf/sync.git synced 2026-06-03 16:44:07 +02:00
This commit is contained in:
Robin Appelman 2019-06-14 14:01:41 +02:00
commit 1c251412de

View file

@ -5,76 +5,86 @@ use std::rc::Rc;
use std::cell::RefCell; use std::cell::RefCell;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize, PartialEq)]
#[serde(tag = "type")] #[serde(tag = "type")]
#[serde(rename_all = "lowercase")]
enum SyncCommand { enum SyncCommand {
#[serde(rename = "create")] Create { session: String },
CreateCommand { session: String }, Join { session: String },
#[serde(rename = "join")] Tick { session: String, tick: u64 },
JoinCommand { session: String }, Play { session: String, play: bool },
#[serde(rename = "tick")]
TickPacket { session: String, tick: u64 },
#[serde(rename = "play")]
PlayPacket { session: String, play: bool }
} }
struct Session { struct Session {
owner: Token, owner: Token,
clients: HashMap<Token, Sender>, clients: HashMap<Token, Sender>,
tick: u64, tick: u64,
playing: bool playing: bool,
} }
impl Session {
pub fn new(owner: Token) -> Self {
Session {
owner,
clients: HashMap::new(),
playing: false,
tick: 0,
}
}
}
impl Session {
pub fn send_command(&self, command: &SyncCommand) {
let command_text = serde_json::to_string(command).unwrap();
for client in self.clients.values() {
client.send(Message::from(command_text.clone())).ok();
}
}
}
fn handle_command(command: SyncCommand, sessions: &mut HashMap<String, Session>, client: Sender) { fn handle_command(command: SyncCommand, sessions: &mut HashMap<String, Session>, client: Sender) {
match command { match command {
SyncCommand::CreateCommand { session } => { SyncCommand::Create { session } => {
let new_session = Session { sessions.insert(session, Session::new(client.token()));
owner: client.token(),
clients: HashMap::new(),
playing: false,
tick: 0
};
sessions.insert(session, new_session);
} }
SyncCommand::JoinCommand { session: session_name } => { SyncCommand::Join { session: session_name } => {
match sessions.get_mut(&session_name) { match sessions.get_mut(&session_name) {
Some(session) => { Some(session) => {
session.clients.insert(client.token(), client); session.clients.insert(client.token(), client);
send_to_session(session, &SyncCommand::TickPacket { session.send_command(&SyncCommand::Tick {
tick: session.tick, tick: session.tick,
session: session_name.clone() session: session_name.clone(),
}); });
send_to_session(session, &SyncCommand::PlayPacket { session.send_command(&SyncCommand::Play {
play: session.playing, play: session.playing,
session: session_name.clone() session: session_name.clone(),
}); });
} }
None => println!("session {} not found", session_name) None => println!("session {} not found", session_name)
} }
} }
SyncCommand::TickPacket { tick, session: session_name } => { SyncCommand::Tick { tick, session: session_name } => {
match sessions.get_mut(&session_name) { match sessions.get_mut(&session_name) {
Some(session) => { Some(session) => {
if session.owner == client.token() { if session.owner == client.token() {
session.tick = tick; session.tick = tick;
send_to_session(session, &SyncCommand::TickPacket { session.send_command(&SyncCommand::Tick {
tick, tick,
session: session_name session: session_name,
}); });
} }
} }
None => println!("session {} not found", session_name) None => println!("session {} not found", session_name)
} }
} }
SyncCommand::PlayPacket { play, session: session_name } => { SyncCommand::Play { play, session: session_name } => {
match sessions.get_mut(&session_name) { match sessions.get_mut(&session_name) {
Some(session) => { Some(session) => {
if session.owner == client.token() { if session.owner == client.token() {
session.playing = play; session.playing = play;
send_to_session(session, &SyncCommand::PlayPacket { session.send_command(&SyncCommand::Play {
play, play,
session: session_name session: session_name,
}); });
} }
} }
@ -84,14 +94,6 @@ fn handle_command(command: SyncCommand, sessions: &mut HashMap<String, Session>,
} }
} }
fn send_to_session(session: &Session, command: &SyncCommand) {
let command_text = serde_json::to_string(command).unwrap();
for client in session.clients.values() {
client.send(Message::from(command_text.clone())).ok();
}
}
struct Server { struct Server {
out: Sender, out: Sender,
sessions: Rc<RefCell<HashMap<String, Session>>>, sessions: Rc<RefCell<HashMap<String, Session>>>,
@ -99,8 +101,7 @@ struct Server {
impl Handler for Server { impl Handler for Server {
fn on_message(&mut self, msg: Message) -> Result<()> { fn on_message(&mut self, msg: Message) -> Result<()> {
let result: serde_json::Result<SyncCommand> = serde_json::from_str(msg.as_text().unwrap_or_default()); match serde_json::from_str::<SyncCommand>(msg.as_text().unwrap_or_default()) {
match result {
Ok(command) => { Ok(command) => {
handle_command(command, &mut self.sessions.borrow_mut(), self.out.clone()); handle_command(command, &mut self.sessions.borrow_mut(), self.out.clone());
Ok(()) Ok(())
@ -112,12 +113,7 @@ impl Handler for Server {
fn on_close(&mut self, _: CloseCode, _: &str) { fn on_close(&mut self, _: CloseCode, _: &str) {
let mut sessions = self.sessions.borrow_mut(); let mut sessions = self.sessions.borrow_mut();
let token = self.out.token(); let token = self.out.token();
let owned_sessions: Vec<_> = sessions sessions.retain(|_, session| session.owner != token);
.iter()
.filter(|&(_, v)| v.owner == token)
.map(|(k, _)| k.clone())
.collect();
for empty in owned_sessions { sessions.remove(&empty); }
for session in sessions.values_mut() { for session in sessions.values_mut() {
session.clients.remove(&token); session.clients.remove(&token);
@ -130,12 +126,23 @@ impl Handler for Server {
} }
fn main() { fn main() {
let port = std::env::var("PORT").unwrap_or("80".to_string()); let port = std::env::var("PORT").unwrap_or_else(|_| "80".to_string());
let listen_adress = format!("0.0.0.0:{}", port); let listen_address = format!("0.0.0.0:{}", port);
println!("listening on: {:?}", listen_adress); println!("listening on: {:?}", listen_address);
let sessions: Rc<RefCell<HashMap<String, Session>>> = Rc::new(RefCell::new(HashMap::new())); let sessions: Rc<RefCell<HashMap<String, Session>>> = Rc::new(RefCell::new(HashMap::new()));
listen(listen_adress, |out| { Server { out, sessions: sessions.clone() } }).unwrap() listen(listen_address, |out| { Server { out, sessions: sessions.clone() } }).unwrap()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_deserialize() {
let input = "{\"type\": \"create\", \"session\": \"foo\"}";
assert_eq!(SyncCommand::Create { session: "foo".to_string() }, serde_json::from_str(input).unwrap());
}
} }