828 lines
36 KiB
Rust
828 lines
36 KiB
Rust
use bus::Bus;
|
|
use crate::{
|
|
app::{
|
|
authentication::Authentication,
|
|
connection::Connection,
|
|
user::{User, UserStatus},
|
|
App,
|
|
session::Session,
|
|
},
|
|
protocol,
|
|
};
|
|
|
|
pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
|
{
|
|
use futures::SinkExt;
|
|
use protocol::*;
|
|
use ring::rand::{SecureRandom, SystemRandom};
|
|
|
|
let rng = SystemRandom::new();
|
|
let argon_config = argon2::Config::default();
|
|
|
|
let mut send_user_status = Vec::<u32>::new();
|
|
|
|
while let Some(packet) = bus.receive_wait() {
|
|
let qr = packet.data;
|
|
|
|
let mut user_id = None;
|
|
let mut session_id = None;
|
|
if let Some(conn) = app.connections.get(qr.id as usize) {
|
|
session_id = conn.session;
|
|
|
|
if let Some(auth_id) = conn.auth {
|
|
if let Some(auth) = app.auths.get(&auth_id) {
|
|
user_id = Some(auth.user);
|
|
}
|
|
}
|
|
}
|
|
|
|
match match qr.data {
|
|
QRPacketData::QConn(request) => {
|
|
let id = app.connections.add(Connection {
|
|
bus: request.bus_id,
|
|
stream: request.stream,
|
|
auth: None,
|
|
session: None,
|
|
|
|
prev:0,
|
|
next:0,
|
|
});
|
|
if let Some(conn) = app.connections.get_mut(id) {
|
|
conn.prev = id as u32;
|
|
conn.next = id as u32;
|
|
}
|
|
|
|
println!("Connect: {}", id);
|
|
|
|
bus.send(
|
|
packet.from,
|
|
QRPacket::new(id as u32, QRPacketData::RConn)
|
|
).ok();
|
|
Some(QRPacket::new(0, QRPacketData::None))
|
|
}
|
|
|
|
QRPacketData::QDisconn => {
|
|
// Uninitialize connection
|
|
if if let Some(conn) = app.connections.get(qr.id as usize).cloned() {
|
|
|
|
// Disassociate session if present
|
|
if let Some(session_token) = conn.session {
|
|
if let Some(session) = app.sessions.get_mut(&session_token) {
|
|
if user_id == Some(session.p_dawn.user) { session.remove_connection(0, qr.id); }
|
|
else if user_id == Some(session.p_dusk.user) { session.remove_connection(1, qr.id); }
|
|
else { session.remove_connection(2, qr.id); }
|
|
}
|
|
}
|
|
|
|
// Remove connection from chain.
|
|
if let Some(auth_id) = conn.auth {
|
|
if let Some(auth) = app.auths.get(&auth_id).cloned() {
|
|
|
|
// Update user connection reference.
|
|
if let Some(user) = app.get_user_by_id_mut(auth.user) {
|
|
if Some(qr.id) == user.connection {
|
|
|
|
// Set connection to next if exists.
|
|
if conn.next != qr.id {
|
|
user.connection = Some(conn.next);
|
|
} else {
|
|
user.connection = None;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Link prev and next connections.
|
|
if conn.next != qr.id {
|
|
if let Some(prev_conn) = app.connections.get_mut(conn.prev as usize) {
|
|
prev_conn.next = conn.next;
|
|
}
|
|
|
|
if let Some(next_conn) = app.connections.get_mut(conn.next as usize) {
|
|
next_conn.prev = conn.prev;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Close socket
|
|
let mut socket = conn.stream.write().await;
|
|
socket.close().await.ok();
|
|
true
|
|
} else { false } {
|
|
app.connections.remove(qr.id as usize).ok();
|
|
|
|
println!("Disconnect: {}", qr.id);
|
|
}
|
|
Some(QRPacket::new(0, QRPacketData::None))
|
|
}
|
|
|
|
QRPacketData::QRegister(request) => {
|
|
let mut response = PacketRegisterResponse::new();
|
|
response.status = STATUS_SERVER_ERROR;
|
|
|
|
println!("Request: Register");
|
|
|
|
let mut is_valid = true;
|
|
if request.code != crate::config::REGISTER_CODE.as_bytes() { response.status = STATUS_BAD_CODE; is_valid = false; }
|
|
if is_valid && request.handle.len() == 0 { response.status = STATUS_BAD_HANDLE; is_valid = false; }
|
|
if is_valid && request.secret.len() == 0 { response.status = STATUS_BAD_SECRET; is_valid = false; }
|
|
|
|
if is_valid {
|
|
let handle = request.handle.to_lowercase();
|
|
let display_name = request.handle.clone();
|
|
|
|
match app.user_handle.get(handle.as_bytes()) {
|
|
None => {
|
|
let mut salt = [0u8; 16];
|
|
match rng.fill(&mut salt) {
|
|
Ok(_) => {
|
|
let salt_id = app.filesystem.salt_create(salt).unwrap();
|
|
app.salts.set(salt_id as isize, salt);
|
|
|
|
if let Ok(secret) = argon2::hash_raw(&request.secret, &salt, &argon_config) {
|
|
let user_id = app.filesystem.user_count().unwrap() as u32;
|
|
|
|
// Register user pool id and handle
|
|
app.filesystem.handle_create(&handle, user_id).ok();
|
|
app.user_handle.set(handle.as_bytes(), user_id);
|
|
|
|
let user_data = User {
|
|
id:user_id,
|
|
flags:0,
|
|
handle:display_name,
|
|
secret,
|
|
na_key:salt_id,
|
|
|
|
connection:Some(qr.id),
|
|
|
|
status:UserStatus::new(),
|
|
challenges:Vec::new(),
|
|
};
|
|
|
|
app.filesystem.user_create(&user_data).ok();
|
|
|
|
// Create user entry
|
|
let user_pos = app.users.add(user_data);
|
|
|
|
app.user_id.set(user_id as isize, user_pos);
|
|
|
|
println!("Registered user '{}' @ {} with id {}", request.handle, user_pos, user_id);
|
|
|
|
// Generate authentication token and secret
|
|
response.status = STATUS_OK;
|
|
rng.fill(&mut response.secret).ok();
|
|
loop {
|
|
rng.fill(&mut response.token).ok();
|
|
|
|
if app.auths.get(&response.token).is_none() {
|
|
app.auths.set(&response.token, Authentication {
|
|
key:response.token,
|
|
secret:response.secret,
|
|
user:user_id,
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Attach authentication to connection
|
|
if let Some(conn) = app.connections.get_mut(qr.id as usize) {
|
|
conn.auth = Some(response.token);
|
|
}
|
|
}
|
|
}
|
|
Err(_) => { println!("error: failed to generate salt.") }
|
|
}
|
|
}
|
|
Some(_) => {
|
|
response.status = STATUS_BAD_HANDLE;
|
|
println!("notice: attempt to register existing handle: '{}'", request.handle);
|
|
}
|
|
}
|
|
}
|
|
|
|
Some(QRPacket::new(qr.id, QRPacketData::RRegister(response)))
|
|
}
|
|
|
|
QRPacketData::QAuth(request) => {
|
|
let mut response = PacketAuthResponse::new();
|
|
response.status = STATUS_ERROR;
|
|
|
|
println!("Request: Auth");
|
|
|
|
let mut is_valid = true;
|
|
if is_valid && request.handle.len() == 0 { response.status = STATUS_BAD_HANDLE; is_valid = false; }
|
|
if is_valid && request.secret.len() == 0 { response.status = STATUS_BAD_SECRET; is_valid = false; }
|
|
|
|
if is_valid {
|
|
|
|
// Get user data from handle
|
|
match app.user_handle.get(request.handle.to_lowercase().as_bytes()).cloned() {
|
|
Some(uid) => {
|
|
if let Some(tuid) = app.user_id.get(uid as isize).cloned() {
|
|
if let Some(user) = app.users.get(tuid).cloned() {
|
|
// Get user salt
|
|
if let Some(salt) = app.salts.get(user.na_key as isize).cloned() {
|
|
|
|
// Verify salted secret against user data
|
|
if argon2::verify_raw(&request.secret.as_bytes(), &salt, &user.secret, &argon_config).unwrap_or(false) {
|
|
println!("Authenticated user '{}' id {}", user.handle, uid);
|
|
|
|
// Generate authentication token and secret
|
|
response.status = STATUS_OK;
|
|
rng.fill(&mut response.secret).ok();
|
|
loop {
|
|
rng.fill(&mut response.token).ok();
|
|
|
|
if app.auths.get(&response.token).is_none() {
|
|
app.auths.set(&response.token, Authentication {
|
|
key:response.token,
|
|
secret:response.secret,
|
|
user:uid,
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Mark send status.
|
|
send_user_status.push(uid);
|
|
|
|
// Attach authentication to connection.
|
|
if let Some(conn) = app.connections.get_mut(qr.id as usize) {
|
|
conn.auth = Some(response.token);
|
|
if let Some(cid) = user.connection {
|
|
conn.prev = cid;
|
|
}
|
|
}
|
|
|
|
// Add connection to chain.
|
|
if let Some(user_cid) = user.connection {
|
|
if let Some(existing) = app.connections.get(user_cid as usize).cloned() {
|
|
if let Some(conn) = app.connections.get_mut(qr.id as usize) {
|
|
conn.next = existing.next;
|
|
}
|
|
}
|
|
} else {
|
|
if let Some(user) = app.users.get_mut(tuid) {
|
|
user.connection = Some(qr.id);
|
|
}
|
|
}
|
|
} else {
|
|
println!("notice: password verification failed.");
|
|
}
|
|
} else {
|
|
println!("error: user salt id '{}' not found.", user.na_key);
|
|
}
|
|
} else {
|
|
println!("error: user with id '{}' not found.", uid);
|
|
}
|
|
} else {
|
|
println!("error: user with id '{}' not found.", uid);
|
|
}
|
|
}
|
|
None => { }
|
|
}
|
|
}
|
|
|
|
Some(QRPacket::new(qr.id, QRPacketData::RAuth(response)))
|
|
}
|
|
|
|
QRPacketData::QAuthResume(request) => {
|
|
println!("Request: Auth Resume");
|
|
|
|
let mut response = PacketAuthResumeResponse::new();
|
|
response.status = STATUS_ERROR;
|
|
|
|
if let Some(auth) = app.auths.get(&request.token).cloned() {
|
|
|
|
// Compare full secret length to reduce time-based attacks.
|
|
let mut valid = true;
|
|
for i in 0..16 {
|
|
valid |= auth.secret[i] == request.secret[i];
|
|
}
|
|
|
|
if valid {
|
|
if if let Some(conn) = app.connections.get_mut(qr.id as usize) {
|
|
conn.auth = Some(request.token);
|
|
response.status = STATUS_OK;
|
|
true
|
|
} else {
|
|
response.status = STATUS_SERVER_ERROR;
|
|
false
|
|
} {
|
|
// Add connection to chain.
|
|
if let Some(user) = app.get_user_by_id(auth.user).cloned() {
|
|
if let Some(user_cid) = user.connection {
|
|
if let Some(existing) = app.connections.get(user_cid as usize).cloned() {
|
|
if let Some(conn) = app.connections.get_mut(qr.id as usize) {
|
|
conn.next = existing.next;
|
|
}
|
|
}
|
|
} else {
|
|
if let Some(user) = app.get_user_by_id_mut(auth.user) {
|
|
user.connection = Some(qr.id);
|
|
}
|
|
}
|
|
|
|
// Mark send user status.
|
|
send_user_status.push(auth.user);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Some(QRPacket::new(qr.id, QRPacketData::RAuthResume(response)))
|
|
}
|
|
|
|
QRPacketData::QAuthRevoke => {
|
|
println!("Request: Auth Revoke");
|
|
|
|
// Remove connection from chain.
|
|
if let Some(conn) = app.connections.get(qr.id as usize).cloned() {
|
|
if let Some(auth_id) = conn.auth {
|
|
if let Some(auth) = app.auths.get(&auth_id).cloned() {
|
|
|
|
// Update user connection reference.
|
|
if let Some(user) = app.get_user_by_id_mut(auth.user) {
|
|
if Some(qr.id) == user.connection {
|
|
|
|
// Set connection to next if exists.
|
|
if conn.next != qr.id {
|
|
user.connection = Some(conn.next);
|
|
} else {
|
|
user.connection = None;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Link prev and next connections.
|
|
if conn.next != qr.id {
|
|
if let Some(prev_conn) = app.connections.get_mut(conn.prev as usize) {
|
|
prev_conn.next = conn.next;
|
|
}
|
|
|
|
if let Some(next_conn) = app.connections.get_mut(conn.next as usize) {
|
|
next_conn.prev = conn.prev;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Remove authentication from connection.
|
|
if let Some(conn) = app.connections.get_mut(qr.id as usize) {
|
|
match conn.auth {
|
|
Some(auth) => {
|
|
println!("Deauthenticated connection: {}", qr.id);
|
|
app.auths.unset(&auth);
|
|
}
|
|
None => { }
|
|
}
|
|
conn.auth = None;
|
|
}
|
|
|
|
Some(QRPacket::new(0, QRPacketData::None))
|
|
}
|
|
|
|
QRPacketData::QSessionList(request) => {
|
|
println!("Request: Session List");
|
|
|
|
let mut response = PacketSessionListResponse::new();
|
|
|
|
let mut count = 0;
|
|
|
|
let mut next_id = app.session_time.begin();
|
|
while let Some(id) = next_id {
|
|
let token = app.session_time.get(id).unwrap();
|
|
if let Some(session) = app.sessions.get(token) {
|
|
|
|
let mut valid = match request.game_state {
|
|
1 => !session.game.is_complete(),
|
|
2 => !session.game.is_complete(),
|
|
3 => session.game.is_complete(),
|
|
_ => true,
|
|
};
|
|
valid &= !request.is_player || Some(session.p_dawn.user) == user_id || Some(session.p_dusk.user) == user_id;
|
|
valid &= !request.is_live || (session.p_dawn.connections.len() > 0 && session.p_dusk.connections.len() > 0);
|
|
|
|
if valid {
|
|
let player :u8 = if user_id.is_some() {
|
|
if Some(session.p_dawn.user) == user_id { 1 }
|
|
else if Some(session.p_dusk.user) == user_id { 2 }
|
|
else { 0 }
|
|
} else { 0 };
|
|
|
|
let is_turn = player != 0 && (session.game.turn & 1) == player as u16 - 1;
|
|
let is_complete = (session.game.is_complete() as u8) * (((session.game.turn & 1) == 0) as u8 + 1);
|
|
|
|
let dawn_handle = if let Some(user) = app.get_user_by_id(session.p_dawn.user) {
|
|
user.handle.clone()
|
|
} else { String::new() };
|
|
|
|
let dusk_handle = if let Some(user) = app.get_user_by_id(session.p_dusk.user) {
|
|
user.handle.clone()
|
|
} else { String::new() };
|
|
|
|
response.records.push(PacketSessionListResponseRecord {
|
|
token:session.token,
|
|
handles:[
|
|
dawn_handle,
|
|
dusk_handle,
|
|
],
|
|
turn:session.game.turn,
|
|
last_move:[0; 3],
|
|
viewers:session.connections.len() as u32,
|
|
player,
|
|
is_turn,
|
|
is_complete,
|
|
});
|
|
|
|
count += 1;
|
|
}
|
|
}
|
|
|
|
if count >= 60 { break; }
|
|
next_id = app.session_time.next(id);
|
|
}
|
|
|
|
Some(QRPacket::new(qr.id, QRPacketData::RSessionList(response)))
|
|
}
|
|
|
|
QRPacketData::QSessionView(request) => {
|
|
println!("Request: Session Join");
|
|
|
|
let mut response = PacketSessionViewResponse::new();
|
|
response.status = STATUS_ERROR;
|
|
response.token = request.token;
|
|
|
|
// Verify that session exists
|
|
if let Some(session) = app.sessions.get_mut(&request.token) {
|
|
|
|
// Join game as player
|
|
if if request.join {
|
|
|
|
// Verify client is authenticated
|
|
if user_id.is_some() {
|
|
// Resume session if user is player
|
|
if Some(session.p_dawn.user) == user_id || Some(session.p_dusk.user) == user_id {
|
|
println!("User resumes session.");
|
|
response.status = STATUS_OK;
|
|
true
|
|
} else { false }
|
|
} else { response.status = STATUS_NOAUTH; false }
|
|
}
|
|
|
|
// Join game as spectator.
|
|
else {
|
|
println!("User spectates session.");
|
|
|
|
response.status = STATUS_OK;
|
|
true
|
|
} {
|
|
// Associate session and connection on join
|
|
if let Some(conn) = app.connections.get_mut(qr.id as usize) {
|
|
conn.session = Some(session.token);
|
|
}
|
|
let mode = if user_id == Some(session.p_dawn.user) {
|
|
0
|
|
} else if user_id == Some(session.p_dusk.user) {
|
|
1
|
|
} else {
|
|
2
|
|
};
|
|
session.add_connection(mode, qr.id);
|
|
}
|
|
}
|
|
|
|
Some(QRPacket::new(qr.id, QRPacketData::RSessionView(response)))
|
|
}
|
|
|
|
// SessionRetire
|
|
QRPacketData::QSessionRetire(request) => {
|
|
use game::history::Play;
|
|
println!("Request: Session Retire");
|
|
|
|
let mut packets = Vec::<QRPacket>::new();
|
|
|
|
let play = Play {
|
|
source: 2,
|
|
from: 0,
|
|
to: 0,
|
|
};
|
|
|
|
if let Some(session) = app.sessions.get_mut(&request.token) {
|
|
if !session.game.is_complete() {
|
|
if (user_id == Some(session.p_dawn.user) && session.game.turn & 1 == 0)
|
|
|| (user_id == Some(session.p_dusk.user) && session.game.turn & 1 == 1) {
|
|
|
|
session.game.process(&play).ok();
|
|
app.filesystem.session_history_push(session.id, play).ok();
|
|
|
|
send_user_status.push(session.p_dawn.user);
|
|
send_user_status.push(session.p_dusk.user);
|
|
|
|
for (cid, _) in session.get_connections() {
|
|
packets.push(QRPacket::new(
|
|
cid,
|
|
QRPacketData::QGamePlay(PacketGamePlay {
|
|
status: STATUS_OK,
|
|
turn: session.game.turn,
|
|
play,
|
|
}),
|
|
));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for packet in packets {
|
|
app.send_response(packet).await;
|
|
}
|
|
|
|
Some(QRPacket::new(0, QRPacketData::None))
|
|
}
|
|
|
|
// SessionLeave
|
|
QRPacketData::QSessionLeave => {
|
|
println!("Request: Session Leave");
|
|
|
|
// Verify that session exists.
|
|
if let Some(session_token) = session_id {
|
|
if let Some(session) = app.sessions.get_mut(&session_token) {
|
|
if user_id == Some(session.p_dawn.user) { session.remove_connection(0, qr.id); }
|
|
else if user_id == Some(session.p_dusk.user) { session.remove_connection(1, qr.id); }
|
|
else { session.remove_connection(2, qr.id); }
|
|
}
|
|
}
|
|
|
|
Some(QRPacket::new(0, QRPacketData::None))
|
|
}
|
|
|
|
// GameState
|
|
QRPacketData::QGameState(request) => {
|
|
let mut response = PacketGameStateResponse::new();
|
|
|
|
println!("Request: Game State");
|
|
|
|
if let Some(session) = app.sessions.get(&request.token) {
|
|
response.status = STATUS_OK;
|
|
response = generate_game_state(&app, &session);
|
|
|
|
if user_id == Some(session.p_dawn.user) { response.player = 0; }
|
|
else if user_id == Some(session.p_dusk.user) { response.player = 1; }
|
|
} else {
|
|
response.status = STATUS_ERROR;
|
|
}
|
|
|
|
Some(QRPacket::new(qr.id, QRPacketData::RGameState(response)))
|
|
}
|
|
|
|
// GamePlay
|
|
QRPacketData::QGamePlay(mut request) => {
|
|
println!("Request: Game Play");
|
|
|
|
request.status = STATUS_ERROR;
|
|
let mut packets = Vec::<QRPacket>::new();
|
|
|
|
if let Some(sid) = session_id {
|
|
if let Some(session) = app.sessions.get_mut(&sid) {
|
|
if !session.game.is_complete() {
|
|
if (user_id == Some(session.p_dawn.user) && session.game.turn & 1 == 0)
|
|
|| (user_id == Some(session.p_dusk.user) && session.game.turn & 1 == 1) {
|
|
|
|
// Check validation of play
|
|
if request.turn == session.game.turn {
|
|
|
|
// Update internal representation
|
|
if session.game.process(&request.play).is_ok() {
|
|
request.status = STATUS_OK;
|
|
|
|
// Save play to game history.
|
|
app.filesystem.session_history_push(session.id, request.play).ok();
|
|
|
|
// Forward play to all clients
|
|
for (cid, _) in session.get_connections() {
|
|
packets.push(QRPacket::new(
|
|
cid,
|
|
QRPacketData::QGamePlay(request.clone())
|
|
));
|
|
}
|
|
|
|
// Send status to players.
|
|
send_user_status.push(session.p_dawn.user);
|
|
send_user_status.push(session.p_dusk.user);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if request.status != STATUS_ERROR {
|
|
for packet in packets {
|
|
app.send_response(packet).await;
|
|
}
|
|
|
|
// Updates will have already been sent, so nothing is needed here.
|
|
Some(QRPacket::new(qr.id, QRPacketData::None))
|
|
} else {
|
|
|
|
// Return error status.
|
|
Some(QRPacket::new(qr.id, QRPacketData::QGamePlay(request)))
|
|
}
|
|
}
|
|
|
|
// Challenge
|
|
QRPacketData::QChallenge(request) => {
|
|
println!("Request: Challenge");
|
|
|
|
if let Some(user_id) = user_id {
|
|
if let Some(chal_id) = app.user_handle.get(request.handle.to_lowercase().as_bytes()).cloned() {
|
|
if let Some(chal_user) = app.get_user_by_id_mut(chal_id) {
|
|
let mut find = false;
|
|
for ch in &chal_user.challenges {
|
|
if *ch == user_id { find = true; }
|
|
}
|
|
if !find {
|
|
chal_user.challenges.push(user_id);
|
|
send_user_status.push(chal_id);
|
|
} else {
|
|
println!("notice: duplicate challenge.");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
None
|
|
}
|
|
|
|
// ChallengeAnswer
|
|
QRPacketData::QChallengeAnswer(request) => {
|
|
println!("Request: Challenge Answer");
|
|
|
|
use crate::app::session::{SessionToken, SessionSecret, Player};
|
|
|
|
let mut response = PacketChallengeAnswerResponse::new();
|
|
response.status = STATUS_ERROR;
|
|
|
|
if let Some(user_id) = user_id {
|
|
if let Some(chal_id) = app.user_handle.get(request.handle.to_lowercase().as_bytes()).copied() {
|
|
|
|
// Check if challenge exists.
|
|
if let Some(user) = app.get_user_by_id_mut(user_id) {
|
|
match user.challenges.binary_search(&chal_id) {
|
|
Ok(pos) => {
|
|
response.status = if request.answer { STATUS_OK } else { STATUS_REJECT };
|
|
user.challenges.remove(pos);
|
|
}
|
|
Err(_) => { }
|
|
}
|
|
}
|
|
|
|
// Create session if response was positive.
|
|
if response.status == STATUS_OK {
|
|
|
|
// Generate session token
|
|
let mut token = SessionToken::default();
|
|
let mut secret = SessionSecret::default();
|
|
loop {
|
|
rng.fill(&mut token).ok();
|
|
if app.sessions.get(&token).is_none() { break; }
|
|
}
|
|
rng.fill(&mut secret).ok();
|
|
|
|
// Add session to latest list.
|
|
let chain_id = app.session_time.add(token);
|
|
|
|
// Choose player seats.
|
|
let time = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap_or_default().as_millis() as u64;
|
|
|
|
// Build session.
|
|
let mut session = Session {
|
|
id:0,
|
|
token,
|
|
secret,
|
|
game:game::Game::new(),
|
|
p_dawn:Player {
|
|
user:if (time & 1) == 0 { user_id } else { chal_id },
|
|
connections:Vec::new(),
|
|
},
|
|
p_dusk:Player {
|
|
user:if (time & 1) == 0 { chal_id } else { user_id },
|
|
connections:Vec::new(),
|
|
},
|
|
connections:Vec::new(),
|
|
time:std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs() as u64,
|
|
chain_id,
|
|
};
|
|
session.game.init();
|
|
|
|
if let Some(conn) = app.connections.get_mut(qr.id as usize) {
|
|
conn.session = Some(session.token);
|
|
}
|
|
|
|
session.id = app.filesystem.session_create(&session).unwrap();
|
|
|
|
app.sessions.set(&token, session);
|
|
app.session_time.set(chain_id, token);
|
|
|
|
response.token = token;
|
|
|
|
send_user_status.push(chal_id);
|
|
}
|
|
|
|
send_user_status.push(user_id);
|
|
}
|
|
}
|
|
|
|
Some(QRPacket::new(qr.id, QRPacketData::RChallengeAnswer(response)))
|
|
}
|
|
|
|
// ChallengeList
|
|
QRPacketData::QChallengeList => {
|
|
println!("Request: Challenge List");
|
|
|
|
let mut response = PacketChallengeListResponse::new();
|
|
response.status = STATUS_NOAUTH;
|
|
|
|
if let Some(user_id) = user_id {
|
|
if let Some(user) = app.get_user_by_id(user_id) {
|
|
response.status = STATUS_OK;
|
|
|
|
for ch_id in &user.challenges {
|
|
if let Some(target) = app.get_user_by_id(*ch_id) {
|
|
response.challenges.push(PacketChallengeListData {
|
|
handle:target.handle.clone(),
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Some(QRPacket::new(qr.id, QRPacketData::RChallengeList(response)))
|
|
}
|
|
|
|
// UserList
|
|
QRPacketData::QUserList => {
|
|
println!("Request: User List");
|
|
|
|
let mut response = PacketUserListResponse::new();
|
|
response.status = STATUS_NOAUTH;
|
|
|
|
if let Some(user_id) = user_id {
|
|
for (_, uid) in app.user_id.pairs() {
|
|
let uid = *uid as u32;
|
|
|
|
if uid != user_id {
|
|
if let Some(user) = app.get_user_by_id(uid) {
|
|
response.records.push(PacketUserListData {
|
|
handle:user.handle.clone(),
|
|
is_online:user.connection.is_some(),
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Some(QRPacket::new(qr.id, QRPacketData::RUserList(response)))
|
|
}
|
|
|
|
_ => { Some(QRPacket::new(0, QRPacketData::None)) }
|
|
} {
|
|
Some(response) => {
|
|
app.send_response(response).await;
|
|
}
|
|
None => { }
|
|
}
|
|
|
|
for user_id in &send_user_status {
|
|
app.send_status(*user_id).await;
|
|
}
|
|
send_user_status.clear();
|
|
}
|
|
}
|
|
|
|
fn generate_game_state(app:&App, session:&Session) -> protocol::PacketGameStateResponse
|
|
{
|
|
use protocol::PacketGameStateResponse;
|
|
|
|
let mut response = PacketGameStateResponse::new();
|
|
|
|
response.token = session.token;
|
|
response.player = 2;
|
|
|
|
// Get Dawn handle
|
|
if let Some(user) = app.get_user_by_id(session.p_dawn.user) {
|
|
response.dawn_handle = user.handle.clone();
|
|
}
|
|
|
|
// Get Dusk handle
|
|
if let Some(user) = app.get_user_by_id(session.p_dusk.user) {
|
|
response.dusk_handle = user.handle.clone();
|
|
}
|
|
|
|
// Get history
|
|
response.history = session.game.history.clone();
|
|
|
|
response
|
|
}
|