dzura/server/src/app/mod.rs
2024-12-17 12:52:41 -08:00

353 lines
12 KiB
Rust

#![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<Connection>,
pub users:Pool<User>,
pub user_id:Sparse<usize>,
pub user_handle:Trie<u32>,
pub salts:Sparse<[u8; 16]>,
pub auths:Trie<Authentication>,
pub sessions:Trie<Session>,
pub invite_tokens:Trie<u32>,
pub invites:Pool<Invitation>,
pub contests:Vec<u32>,
pub session_time:Chain<SessionToken>,
}
impl App {
pub fn init() -> Result<Self, ()>
{
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<u8>) -> Vec<u8>
{
[
crate::util::pack::pack_u16(code),
data,
].concat()
}