#![allow(dead_code)] use sparse::Sparse; use pool::Pool; use trie::Trie; use crate::{ protocol::QRPacket, system::{ filesystem::FileSystem, log::Log, }, util::Chain, }; pub mod connection; use connection::Connection; pub mod user; use user::User; pub mod authentication; use authentication::Authentication; pub mod session; use session::{Session, SessionToken}; pub mod invitation; pub use invitation::{Invitation, InviteToken}; pub mod context; pub struct App { pub filesystem:FileSystem, pub log:Log, pub connections:Pool, pub users:Pool, pub user_id:Sparse, pub user_handle:Trie, pub salts:Sparse<[u8; 16]>, pub auths:Trie, pub sessions:Trie, pub invite_tokens:Trie, pub invites:Pool, pub contests:Vec, pub session_time:Chain, } impl App { pub fn init() -> Result { if let Ok(mut filesystem) = FileSystem::init() { let mut contests = Vec::new(); // Load salts println!("Loading salts.."); let mut salts = Sparse::new(); let salt_count = filesystem.salt_count()?; for id in 0..salt_count { let salt = filesystem.salt_fetch(id as u32).unwrap(); salts.set(id as isize, salt); } // Load handles println!("Loading handles.."); let mut user_handle = Trie::new(); let handle_count = filesystem.handle_count()?; for id in 0..handle_count { let (handle, user_id) = filesystem.handle_fetch(id as u32).unwrap(); user_handle.set(handle.as_bytes(), user_id); } // Load users println!("Loading users.."); let mut users = Pool::new(); let mut user_id = Sparse::new(); let user_count = filesystem.user_count()?; for id in 0..user_count { let user = filesystem.user_fetch(id as u32).unwrap(); // Add user to contests if flag is set. if (user.flags & user::FC_ENABLE) != 0 { match contests.binary_search(&user.id) { Ok(_) => { } Err(pos) => { contests.insert(pos, user.id); } } } let user_local_id = users.add(user); user_id.set(user_local_id as isize, id); } // Load sessions println!("Loading sessions.."); let mut sessions = Trie::new(); let mut times = Vec::<(u64, SessionToken)>::new(); let session_count = filesystem.session_count()?; for id in 0..session_count { let mut session = filesystem.session_fetch(id as u32).unwrap(); times.push((session.time, session.token.clone())); // Load session history if let Ok(history) = filesystem.session_history_fetch(id as u32) { session.game.apply_history(&history).ok(); } sessions.set(&session.token.clone(), session); } // Organize sessions by most recent let mut session_time = Chain::new(); times.sort_by(|(a, _), (b, _)| { if a > b { std::cmp::Ordering::Greater } else { std::cmp::Ordering::Less } }); for (_, token) in times { let id = session_time.add(token); sessions.get_mut(&token).unwrap().chain_id = id; } println!("App data ready."); Ok(Self { filesystem:filesystem, log:Log::new(), connections:Pool::new(), users, user_id, user_handle, salts, auths:Trie::new(), sessions, invite_tokens:Trie::new(), invites:Pool::new(), contests, session_time, }) } else { Err(()) } } pub fn get_user_by_id(&self, id:u32) -> Option<&User> { if let Some(uid) = self.user_id.get(id as isize) { self.users.get(*uid) } else { None } } pub fn get_user_by_id_mut(&mut self, id:u32) -> Option<&mut User> { if let Some(uid) = self.user_id.get(id as isize) { self.users.get_mut(*uid) } else { None } } pub async fn send_response(&mut self, response:QRPacket) { use crate::protocol::*; use tokio_tungstenite::tungstenite::Message; use futures::SinkExt; match response.data { QRPacketData::None => { } _ => { if let Some(conn) = self.connections.get(response.id as usize) { let mut socket = conn.stream.write().await; match response.data { QRPacketData::RHello(response) => { socket.send(Message::Binary( encode_response(CODE_HELLO, response.encode()) )).await.ok(); } QRPacketData::RRegister(response) => { socket.send(Message::Binary( encode_response(CODE_REGISTER, response.encode()) )).await.ok(); } QRPacketData::RAuth(response) => { socket.send(Message::Binary( encode_response(CODE_AUTH, response.encode()) )).await.ok(); } QRPacketData::RAuthResume(response) => { socket.send(Message::Binary( encode_response(CODE_AUTH_RESUME, response.encode()) )).await.ok(); } QRPacketData::RSessionList(response) => { socket.send(Message::Binary( encode_response(CODE_SESSION_LIST, response.encode()) )).await.ok(); } QRPacketData::RSessionView(response) => { socket.send(Message::Binary( encode_response(CODE_SESSION_VIEW, response.encode()) )).await.ok(); } QRPacketData::RGameState(response) => { socket.send(Message::Binary( encode_response(CODE_GAME_STATE, response.encode()) )).await.ok(); } QRPacketData::GameMessage(response) => { socket.send(Message::Binary( encode_response(CODE_GAME_MESSAGE, response.encode()) )).await.ok(); } QRPacketData::RChallengeAnswer(response) => { socket.send(Message::Binary( encode_response(CODE_CHALLENGE_ANSWER, response.encode()) )).await.ok(); } QRPacketData::RChallengeList(response) => { socket.send(Message::Binary( encode_response(CODE_CHALLENGE_LIST, response.encode()) )).await.ok(); } QRPacketData::RUserList(response) => { socket.send(Message::Binary( encode_response(CODE_USER_LIST, response.encode()) )).await.ok(); } QRPacketData::RUserProfile(response) => { socket.send(Message::Binary( encode_response(CODE_USER_PROFILE, response.encode()) )).await.ok(); } QRPacketData::RInviteList(response) => { socket.send(Message::Binary( encode_response(CODE_INVITE_LIST, response.encode()) )).await.ok(); } QRPacketData::RInviteAcquire(response) => { socket.send(Message::Binary( encode_response(CODE_INVITE_ACQUIRE, response.encode()) )).await.ok(); } QRPacketData::TestResult(response) => { socket.send(Message::Binary( encode_response(CODE_TEST_RESULT, response.encode()) )).await.ok(); } _ => { } } } } } } pub async fn send_session_spectators(&mut self, token:SessionToken) { use crate::protocol::*; let mut packets = Vec::new(); if let Some(session) = self.sessions.get_mut(&token) { for (cid, _) in session.get_connections() { packets.push(QRPacket::new( cid, QRPacketData::GameMessage(PacketGameMessage { data: GameMessageData::Online( session.p_dawn.connections.len() > 0, session.p_dusk.connections.len() > 0, session.connections.len() as u32, ), test: false, expected: false, }), )); } } for packet in packets { self.send_response(packet).await; } } pub async fn send_status(&mut self, user_id:u32) { use crate::protocol::*; use tokio_tungstenite::tungstenite::Message; use futures::SinkExt; let mut response = PacketSummaryResponse::new(); if let Some(user) = self.get_user_by_id(user_id).cloned() { // Get challenges response.challenge = if user.challenges.len() < 10 { user.challenges.len() as u16 } else { 10 }; // Get awaiting sessions let mut next_id = self.session_time.begin(); while let Some(id) = next_id { let token = self.session_time.get(id).unwrap(); if let Some(session) = self.sessions.get(token) { // Add to resume if session has user and is user turn. let is_turn_player = (session.p_dawn.user == user_id && (session.game.turn & 1) == 0) || (session.p_dusk.user == user_id && (session.game.turn & 1) == 1); if !session.game.is_complete() && is_turn_player { response.resume += 1; } if response.resume >= 10 { break; } next_id = self.session_time.next(id); } } // Send packet to connections if let Some(end_conn_id) = user.connection { let mut conn_id = end_conn_id; loop { if let Some(conn) = self.connections.get_mut(conn_id as usize) { let mut socket = conn.stream.write().await; socket.send(Message::Binary( encode_response(CODE_SUMMARY, response.encode()) )).await.ok(); conn_id = conn.next; if conn_id == end_conn_id { break; } } else { break; } } } } } } fn encode_response(code:u16, data:Vec) -> Vec { [ crate::util::pack::pack_u16(code), data, ].concat() }