1
0
mirror of https://git.ngram.ca/OpenJam/rc-servers synced 2026-08-23 23:08:52 +00:00

Update to work with polariton v0.2

This commit is contained in:
NGnius (Graham)
2025-03-08 17:16:02 -05:00
parent f004ca8565
commit be37f8913a
83 changed files with 428 additions and 1202 deletions

44
Cargo.lock generated
View File

@@ -106,12 +106,6 @@ dependencies = [
"num-traits 0.2.19", "num-traits 0.2.19",
] ]
[[package]]
name = "array-init"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc"
[[package]] [[package]]
name = "async-stream" name = "async-stream"
version = "0.3.6" version = "0.3.6"
@@ -213,30 +207,6 @@ version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72" checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72"
[[package]]
name = "binrw"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d4bca59c20d6f40c2cc0802afbe1e788b89096f61bdf7aeea6bf00f10c2909b"
dependencies = [
"array-init",
"binrw_derive",
"bytemuck",
]
[[package]]
name = "binrw_derive"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8ba42866ce5bced2645bfa15e97eef2c62d2bdb530510538de8dd3d04efff3c"
dependencies = [
"either",
"owo-colors",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.3.2" version = "1.3.2"
@@ -1451,12 +1421,6 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "owo-colors"
version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.12.3" version = "0.12.3"
@@ -1533,9 +1497,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]] [[package]]
name = "polariton" name = "polariton"
version = "0.1.0" version = "0.2.0"
dependencies = [ dependencies = [
"binrw", "tokio",
] ]
[[package]] [[package]]
@@ -1552,10 +1516,11 @@ dependencies = [
[[package]] [[package]]
name = "polariton_server" name = "polariton_server"
version = "0.1.0" version = "0.2.0"
dependencies = [ dependencies = [
"log", "log",
"polariton", "polariton",
"tokio",
] ]
[[package]] [[package]]
@@ -1800,6 +1765,7 @@ dependencies = [
"log", "log",
"polariton", "polariton",
"polariton_auth", "polariton_auth",
"polariton_server",
"tokio", "tokio",
] ]

View File

@@ -19,5 +19,5 @@ libfj = { version = "0.7.5", path = "../libfj" }
log = "0.4" log = "0.4"
env_logger = "0.11" env_logger = "0.11"
clap = { version = "4.5", features = [ "derive" ] } clap = { version = "4.5", features = [ "derive" ] }
polariton = { version = "0.1", path = "../polariton" } polariton = { version = "0.2", path = "../polariton", features = [ "tokio-async" ] }
polariton_server = { version = "0.1", path = "../polariton/server" } polariton_server = { version = "0.2", path = "../polariton/server", features = [ "tokio-async" ] }

View File

@@ -1,5 +1,3 @@
use std::sync::Arc;
use polariton::packet::{Packet, Message, StandardMessage, Data, Cryptographer}; use polariton::packet::{Packet, Message, StandardMessage, Data, Cryptographer};
use polariton::operation::{Typed, ParameterTable, OperationResponse}; use polariton::operation::{Typed, ParameterTable, OperationResponse};
@@ -54,7 +52,7 @@ impl <'a> Handshake<Start<'a>> {
flags: 0, flags: 0,
data: Data::InitAck , data: Data::InitAck ,
}), }),
packet.header.channel, true, None).unwrap() packet.header.channel, true, &Default::default()).unwrap()
}); });
} }
} }
@@ -77,7 +75,7 @@ pub enum EncryptError {
impl Handshake<Connected> { impl Handshake<Connected> {
const PUBLIC_KEY_PARAM_KEY: u8 = 1; const PUBLIC_KEY_PARAM_KEY: u8 = 1;
pub fn encrypt<'a>(self, packet: &'a Packet) -> Result<HandshakeAnd<Encrypted, (Packet, Box<Arc<dyn Cryptographer>>)>, HandshakeAnd<Connected, EncryptError>> { pub fn encrypt<'a>(self, packet: &'a Packet) -> Result<HandshakeAnd<Encrypted, (Packet, crate::encryption::CryptoImpl)>, HandshakeAnd<Connected, EncryptError>> {
if let Packet::Packet(packet) = &packet { if let Packet::Packet(packet) = &packet {
if let Message::Standard(conn) = &packet.message { if let Message::Standard(conn) = &packet.message {
if let Data::InternalOpReq(req) = &conn.data { if let Data::InternalOpReq(req) = &conn.data {
@@ -96,13 +94,13 @@ impl Handshake<Connected> {
return_code: 0, return_code: 0,
message: Typed::Null, message: Typed::Null,
params: ParameterTable::from_dict(response_params) }) params: ParameterTable::from_dict(response_params) })
}), 0, true, None).unwrap(); }), 0, true, &Default::default()).unwrap();
let new_self = Handshake::<Encrypted> { let new_self = Handshake::<Encrypted> {
state: Encrypted, state: Encrypted,
}; };
return Ok(HandshakeAnd { return Ok(HandshakeAnd {
handshake: new_self, handshake: new_self,
extra: (resp_packet, Box::new(Arc::new(keys.enc))), extra: (resp_packet, keys.enc),
}); });
} else { } else {
return Err(HandshakeAnd { return Err(HandshakeAnd {
@@ -155,7 +153,7 @@ impl <T: AuthProvider<E>, E> Handshake<Auth<T, E>> {
const AUTH_REQUEST_CODE: u8 = 230; const AUTH_REQUEST_CODE: u8 = 230;
const USER_ID_KEY: u8 = 225; const USER_ID_KEY: u8 = 225;
const NICKNAME_KEY: u8 = 225; const NICKNAME_KEY: u8 = 225;
pub fn authenticate<'a>(mut self, packet: &'a Packet, crypto: Box<Arc<dyn Cryptographer>>) -> Result<Packet, HandshakeAnd<Auth<T, E>, AuthError<E>>> { pub fn authenticate<'a>(mut self, packet: &'a Packet, crypto: &dyn Cryptographer) -> Result<Packet, HandshakeAnd<Auth<T, E>, AuthError<E>>> {
if let Packet::Packet(packet) = &packet { if let Packet::Packet(packet) = &packet {
if let Message::Standard(conn) = &packet.message { if let Message::Standard(conn) = &packet.message {
if let Data::OpReq(req) = &conn.data { if let Data::OpReq(req) = &conn.data {
@@ -174,6 +172,8 @@ impl <T: AuthProvider<E>, E> Handshake<Auth<T, E>> {
params_resp.insert(Self::USER_ID_KEY, user_id.to_owned()); params_resp.insert(Self::USER_ID_KEY, user_id.to_owned());
params_resp.insert(Self::NICKNAME_KEY, user_id.to_owned()); params_resp.insert(Self::NICKNAME_KEY, user_id.to_owned());
} }
let serdes_ctx = Default::default();
let serdes_ctx = polariton::packet::SerdesContext::new(&serdes_ctx, crypto);
return Ok(Packet::from_message( return Ok(Packet::from_message(
Message::Standard( Message::Standard(
StandardMessage { StandardMessage {
@@ -185,7 +185,7 @@ impl <T: AuthProvider<E>, E> Handshake<Auth<T, E>> {
params: params_resp.into(), params: params_resp.into(),
}) })
}.encrypt(conn.is_encrypted()) }.encrypt(conn.is_encrypted())
), packet.header.channel, true, Some(crypto)).unwrap()); ), packet.header.channel, true, &serdes_ctx).unwrap());
} }
} }
} }

View File

@@ -1,4 +1,5 @@
mod encryption; mod encryption;
pub use encryption::CryptoImpl;
mod handshake; mod handshake;
pub use handshake::{Handshake, AuthProvider, AuthError}; pub use handshake::{Handshake, AuthProvider, AuthError};

View File

@@ -1,14 +1,10 @@
mod cli; mod cli;
mod state; mod state;
use std::num::NonZero;
use std::sync::Arc;
use polariton_auth::Handshake; use polariton_auth::Handshake;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net; use tokio::net;
use polariton::packet::{Cryptographer, Data, Message, Packet, Ping, StandardMessage, StandardPacket}; use polariton::packet::{Data, Message, Packet, StandardMessage};
use polariton::operation::{OperationResponse, Typed}; use polariton::operation::{OperationResponse, Typed};
#[tokio::main] #[tokio::main]
@@ -28,21 +24,20 @@ async fn main() -> std::io::Result<()> {
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
loop { loop {
let (socket, address) = listener.accept().await?; let (socket, address) = listener.accept().await?;
tokio::spawn(process_socket(socket, address, NonZero::new(args.retries), op_handler.clone(), redirect_static, room_name_static)); tokio::spawn(process_socket(socket, address, op_handler.clone(), redirect_static, room_name_static));
} }
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
let (socket, address) = listener.accept().await?; let (socket, address) = listener.accept().await?;
process_socket(socket, address, NonZero::new(args.retries), redirect_static, room_name_static).await; process_socket(socket, address, redirect_static, room_name_static).await;
Ok(()) Ok(())
} }
} }
async fn process_socket(mut socket: net::TcpStream, address: std::net::SocketAddr, retries: Option<NonZero<usize>>, redirect_url: &str, lobby_name: &str) { async fn process_socket(mut socket: net::TcpStream, address: std::net::SocketAddr, redirect_url: &str, lobby_name: &str) {
log::debug!("Accepting connection from address {}", address); log::debug!("Accepting connection from address {}", address);
let mut buf = Vec::new(); let enc = match do_connect_handshake(&mut socket, lobby_name, redirect_url).await {
let enc = match do_connect_handshake(&mut buf, &mut socket, retries, lobby_name, redirect_url).await {
Some(x) => x, Some(x) => x,
None => { None => {
log::error!("Failed to do connect handshake with {}", address); log::error!("Failed to do connect handshake with {}", address);
@@ -50,10 +45,10 @@ async fn process_socket(mut socket: net::TcpStream, address: std::net::SocketAdd
} }
}; };
let sock_state = state::State::new(enc); let sock_state = state::State::new(enc);
while let Ok(packet) = receive_packet(&mut buf, &mut socket, retries, sock_state.binrw_args()).await { while let Ok(packet) = polariton_server::utils::receive_packet_async(&mut socket, &sock_state.serdes_ctx()).await {
match packet { match packet {
Packet::Ping(ping) => { Packet::Ping(ping) => {
handle_ping(ping, &mut buf, &mut socket).await; polariton_server::utils::handle_ping_async(ping, &mut socket, &sock_state.serdes_ctx()).await.unwrap_or_default();
}, },
Packet::Packet(packet) => log::warn!("Not handling packet {:?}", packet), Packet::Packet(packet) => log::warn!("Not handling packet {:?}", packet),
} }
@@ -61,91 +56,6 @@ async fn process_socket(mut socket: net::TcpStream, address: std::net::SocketAdd
log::debug!("Goodbye connection from address {}", address); log::debug!("Goodbye connection from address {}", address);
} }
async fn handle_ping(ping: Ping, buf: &mut Vec<u8>, socket: &mut net::TcpStream) {
buf.clear();
let resp = Packet::Ping(polariton_auth::ping_pong(ping));
resp.to_buf(buf, None).unwrap();
let write_count = socket.write(buf).await.unwrap();
log::debug!("(ping) Write {} bytes to socket: {:?}", write_count, buf);
buf.clear();
}
fn buf_likely_valid(buf: &[u8]) -> bool {
buf.is_empty() || buf[0] == Packet::PING_MAGIC || buf[0] == Packet::FRAMED_MAGIC
}
async fn read_more(buf: &mut Vec<u8>, socket: &mut net::TcpStream) -> Result<usize, std::io::Error> {
let read_count = socket.read_buf(buf).await?;
log::debug!("Read {} bytes from socket: {:?}", read_count, buf);
Ok(read_count)
}
async fn receive_packet(buf: &mut Vec<u8>, socket: &mut net::TcpStream, max_retries: Option<NonZero<usize>>, args: Option<Box<Arc<dyn Cryptographer + 'static>>>) -> Result<Packet, std::io::Error> {
if buf.is_empty() {
let read_count = read_more(buf, socket).await?;
if read_count == 0 { return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "socket did not read any bytes")); } // bad packet
}
let mut last_err = None;
let mut must_succeed_next = false;
if let Some(max_retries) = max_retries {
for _ in 0..max_retries.get() {
match Packet::from_buf(&buf, args.clone()) {
Ok(packet) => {
log::debug!("Received packet {:?}", packet);
return Ok(packet);
},
Err(e) => last_err = Some(e),
}
if must_succeed_next {
break;
}
must_succeed_next = read_more(buf, socket).await? == 0;
}
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, last_err.unwrap()));
} else {
while buf_likely_valid(buf.as_slice()) {
match Packet::from_buf(&buf, args.clone()) {
Ok(packet) => {
log::debug!("Received packet {:?}", packet);
return Ok(packet);
},
Err(e) => last_err = Some(e),
}
if must_succeed_next {
break;
}
must_succeed_next = read_more(buf, socket).await? == 0;
}
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, last_err.unwrap()));
}
}
async fn send_packet(packet: Packet, buf: &mut Vec<u8>, socket: &mut net::TcpStream, args: Option<Box<Arc<dyn Cryptographer>>>) -> Result<(), std::io::Error> {
log::debug!("Sending packet {:?}", packet);
buf.clear();
packet.to_buf(buf, args).map_err(|e| std::io::Error::new(std::io::ErrorKind::NotFound, e))?;
let write_count = socket.write(buf).await?;
log::debug!("Write {} bytes to socket: {:?}", write_count, buf);
#[cfg(debug_assertions)]
{
// print out unencrypted packet too
if let Packet::Packet(standard_p) = packet {
if let Message::Standard(standard_m) = standard_p.message {
if standard_m.is_encrypted() {
let standard_m = standard_m.encrypt(false);
let packet = Packet::Packet(StandardPacket { header: standard_p.header, message: Message::Standard(standard_m) });
packet.to_buf(buf, None).map_err(|e| std::io::Error::new(std::io::ErrorKind::NotFound, e))?;
log::debug!("Unencrypted bytes of packet: {:?} (len: {})", buf, buf.len());
}
}
}
}
buf.clear();
Ok(())
}
const APP_ID: &str = "ChatServer"; const APP_ID: &str = "ChatServer";
struct AuthImpl; struct AuthImpl;
@@ -194,23 +104,20 @@ impl polariton_auth::AuthProvider<AuthError> for AuthImpl {
} }
async fn do_connect_handshake( async fn do_connect_handshake(
buf: &mut Vec<u8>,
socket: &mut net::TcpStream, socket: &mut net::TcpStream,
max_retries: Option<NonZero<usize>>,
game_server_name: &str, game_server_name: &str,
game_server_url: &str, game_server_url: &str,
) -> Option<Box<std::sync::Arc<dyn Cryptographer>>> { ) -> Option<polariton_auth::CryptoImpl> {
let handshake = Handshake::new(APP_ID); let handshake = Handshake::new(APP_ID);
// connect // connect
log::debug!("(connect) Handling first packet"); log::debug!("(connect) Handling first packet");
let packet1 = match receive_packet(buf, socket, max_retries, None).await { let packet1 = match polariton_server::utils::receive_packet_async(socket, &Default::default()).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read connect packet: {}", e); log::error!("Failed to read connect packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
let (handshake, to_send) = match handshake.connect(&packet1) { let (handshake, to_send) = match handshake.connect(&packet1) {
Ok(x) => (x.handshake, x.extra), Ok(x) => (x.handshake, x.extra),
Err(e) => { Err(e) => {
@@ -218,7 +125,7 @@ async fn do_connect_handshake(
return None; return None;
} }
}; };
match send_packet(to_send, buf, socket, None).await { match polariton_server::utils::send_packet_async(&to_send, socket, &Default::default()).await {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
log::error!("Failed to send connect ack packet: {}", e); log::error!("Failed to send connect ack packet: {}", e);
@@ -227,24 +134,22 @@ async fn do_connect_handshake(
} }
// encrypt // encrypt
log::debug!("(connect) Handling second packet"); log::debug!("(connect) Handling second packet");
let mut packet2 = match receive_packet(buf, socket, max_retries, None).await { let mut packet2 = match polariton_server::utils::receive_packet_async(socket, &Default::default()).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) public key packet: {}", e); log::error!("Failed to read (maybe) public key packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
while let Packet::Ping(ping) = packet2 { while let Packet::Ping(ping) = packet2 {
handle_ping(ping, buf, socket).await; polariton_server::utils::handle_ping_async(ping, socket, &Default::default()).await.unwrap_or_default();
packet2 = match receive_packet(buf, socket, max_retries, None).await { packet2 = match polariton_server::utils::receive_packet_async(socket, &Default::default()).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) public key packet: {}", e); log::error!("Failed to read (maybe) public key packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
} }
let (handshake, to_send, crypto) = match handshake.encrypt(&packet2) { let (handshake, to_send, crypto) = match handshake.encrypt(&packet2) {
Ok(x) => (x.handshake, x.extra.0, x.extra.1), Ok(x) => (x.handshake, x.extra.0, x.extra.1),
@@ -253,7 +158,7 @@ async fn do_connect_handshake(
return None; return None;
} }
}; };
match send_packet(to_send, buf, socket, None).await { match polariton_server::utils::send_packet_async(&to_send, socket, &Default::default()).await {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
log::error!("Failed to send encryption ack packet: {}", e); log::error!("Failed to send encryption ack packet: {}", e);
@@ -262,28 +167,28 @@ async fn do_connect_handshake(
} }
// pre-auth // pre-auth
let handshake = handshake.with_auth(AuthImpl); let handshake = handshake.with_auth(AuthImpl);
let op_ctx = polariton::serdes::SerdesContext::default();
let ctx = polariton::packet::SerdesContext::new(&op_ctx, &crypto);
// authenticate // authenticate
log::debug!("(connect) Handling third packet"); log::debug!("(connect) Handling third packet");
let mut packet3 = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await { let mut packet3 = match polariton_server::utils::receive_packet_async(socket, &ctx).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) auth packet: {}", e); log::error!("Failed to read (maybe) auth packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
while let Packet::Ping(ping) = packet3 { while let Packet::Ping(ping) = packet3 {
handle_ping(ping, buf, socket).await; polariton_server::utils::handle_ping_async(ping, socket, &Default::default()).await.unwrap_or_default();
packet3 = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await { packet3 = match polariton_server::utils::receive_packet_async(socket, &ctx).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) auth packet: {}", e); log::error!("Failed to read (maybe) auth packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
} }
let to_send = match handshake.authenticate(&packet3, crypto.clone()) { let to_send = match handshake.authenticate(&packet3, &crypto) {
Ok(x) => x, Ok(x) => x,
Err(h) => match h.extra { Err(h) => match h.extra {
polariton_auth::AuthError::Validation(e) => { polariton_auth::AuthError::Validation(e) => {
@@ -296,7 +201,7 @@ async fn do_connect_handshake(
}, },
}, },
}; };
match send_packet(to_send, buf, socket, Some(crypto.clone())).await { match polariton_server::utils::send_packet_async(&to_send, socket, &ctx).await {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
log::error!("Failed to send auth ack packet: {}", e); log::error!("Failed to send auth ack packet: {}", e);
@@ -305,7 +210,7 @@ async fn do_connect_handshake(
} }
// redirect to lobby // redirect to lobby
let mut packet_j = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await { let mut packet_j = match polariton_server::utils::receive_packet_async(socket, &ctx).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) join packet: {}", e); log::error!("Failed to read (maybe) join packet: {}", e);
@@ -313,8 +218,8 @@ async fn do_connect_handshake(
} }
}; };
while let Packet::Ping(ping) = packet_j { while let Packet::Ping(ping) = packet_j {
handle_ping(ping, buf, socket).await; polariton_server::utils::handle_ping_async(ping, socket, &ctx).await.unwrap_or_default();
packet_j = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await { packet_j = match polariton_server::utils::receive_packet_async(socket, &ctx).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) join packet: {}", e); log::error!("Failed to read (maybe) join packet: {}", e);
@@ -339,8 +244,8 @@ async fn do_connect_handshake(
message: Typed::Null, message: Typed::Null,
params: params.into(), params: params.into(),
}), }),
}.encrypt(true)), 0, true, Some(crypto.clone())).unwrap(); }.encrypt(true)), 0, true, &ctx).unwrap();
match send_packet(resp, buf, socket, Some(crypto.clone())).await { match polariton_server::utils::send_packet_async(&resp, socket, &ctx).await {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
log::error!("Failed to send lobby ack packet: {}", e); log::error!("Failed to send lobby ack packet: {}", e);

View File

@@ -1,17 +1,17 @@
use std::sync::Arc; const SERDES_SERDES_CTX_REF: &'static polariton::serdes::SerdesContext<(), polariton::serdes::NoCustomSerdes> = &polariton::serdes::SerdesContext::default_const();
pub struct State { pub struct State {
pub crypto: Box<Arc<dyn polariton::packet::Cryptographer>>, pub crypto: polariton_auth::CryptoImpl,
} }
impl State { impl State {
pub fn new(c: Box<Arc<dyn polariton::packet::Cryptographer>>) -> Self { pub fn new(c: polariton_auth::CryptoImpl) -> Self {
Self { Self {
crypto: c, crypto: c,
} }
} }
pub fn binrw_args(&self) -> polariton::packet::WriteArgs { pub fn serdes_ctx(&self) -> polariton::packet::SerdesContext<'_, (), polariton::serdes::NoCustomSerdes> {
Some(self.crypto.clone()) polariton::packet::SerdesContext::new(SERDES_SERDES_CTX_REF, &self.crypto)
} }
} }

View File

@@ -11,7 +11,7 @@ impl ChatChannelInfo {
Typed::HashMap(vec![ Typed::HashMap(vec![
(Typed::Str("channelName".into()), Typed::Str(self.channel_name.clone().into())), (Typed::Str("channelName".into()), Typed::Str(self.channel_name.clone().into())),
(Typed::Str("members".into()), Typed::Arr(Arr { (Typed::Str("members".into()), Typed::Arr(Arr {
ty: 104, // hashtable ty: polariton::serdes::TypePrefix::HashMap, // hashtable
items: self.members.iter().map(|x| x.as_transmissible()).collect(), items: self.members.iter().map(|x| x.as_transmissible()).collect(),
})), })),
(Typed::Str("channelType".into()), Typed::Int(self.channel_ty as _)), (Typed::Str("channelType".into()), Typed::Int(self.channel_ty as _)),

View File

@@ -4,14 +4,10 @@ mod state;
mod data; mod data;
mod operations; mod operations;
use std::num::NonZero;
use std::sync::Arc;
use polariton_auth::Handshake; use polariton_auth::Handshake;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net; use tokio::net;
use polariton::packet::{Cryptographer, Data, Message, Packet, Ping, StandardMessage, StandardPacket}; use polariton::packet::{Data, Message, Packet, StandardMessage};
use polariton::operation::{OperationResponse, Typed}; use polariton::operation::{OperationResponse, Typed};
pub type UserTy = std::sync::RwLock<state::UserState>; pub type UserTy = std::sync::RwLock<state::UserState>;
@@ -22,7 +18,7 @@ async fn main() -> std::io::Result<()> {
let args = cli::CliArgs::get(); let args = cli::CliArgs::get();
log::debug!("Got cli args {:?}", args); log::debug!("Got cli args {:?}", args);
let op_handler = Arc::new(operations::handler()); let server = polariton_server::Server::new(operations::handler());
let ip_addr: std::net::IpAddr = args.ip.parse().expect("Invalid IP address"); let ip_addr: std::net::IpAddr = args.ip.parse().expect("Invalid IP address");
@@ -31,166 +27,30 @@ async fn main() -> std::io::Result<()> {
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
loop { loop {
let (socket, address) = listener.accept().await?; let (socket, address) = listener.accept().await?;
tokio::spawn(process_socket(socket, address, NonZero::new(args.retries), op_handler.clone())); tokio::spawn(process_socket(socket, address, &server));
} }
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
let (socket, address) = listener.accept().await?; let (socket, address) = listener.accept().await?;
process_socket(socket, address, NonZero::new(args.retries), op_handler.clone()).await; process_socket(socket, address, &server).await;
Ok(()) Ok(())
} }
} }
async fn process_socket(mut socket: net::TcpStream, address: std::net::SocketAddr, retries: Option<NonZero<usize>>, op_handler: Arc<polariton_server::operations::OperationsHandler<crate::UserTy>>) { async fn process_socket(mut socket: net::TcpStream, address: std::net::SocketAddr, server: &polariton_server::Server<crate::UserTy>) {
log::debug!("Accepting connection from address {}", address); log::debug!("Accepting connection from address {}", address);
let enc = match do_connect_handshake(&mut socket).await {
let mut read_buf = Vec::new();
let mut write_buf = Vec::new();
let enc = match do_connect_handshake(&mut read_buf, &mut socket, retries).await {
Some(x) => x, Some(x) => x,
None => { None => {
log::error!("Failed to do connect handshake with {}", address); log::error!("Failed to do connect handshake with {}", address);
return; return;
} }
}; };
let sock_state = state::State::new(enc); let user_state = state::UserState::new();
let user_state = sock_state.user(); server.handle_async(socket, user_state, enc, Default::default()).await;
while let Ok(packet) = receive_packet(&mut read_buf, &mut socket, retries, sock_state.binrw_args()).await {
match packet {
Packet::Ping(ping) => {
handle_ping(ping, &mut write_buf, &mut socket).await;
for _ in 0..5 {
read_buf.remove(0);
}
},
Packet::Packet(packet) => {
// remove packet's advertised size from the buffer
for _ in 0..packet.header.len {
read_buf.remove(0);
}
match packet.message {
Message::Ping(ping) => {
handle_ping(ping, &mut write_buf, &mut socket).await;
},
Message::Standard(msg) => {
let is_encrypted = msg.is_encrypted();
match msg.data {
Data::OpReq(req) => {
let resp = op_handler.handle_op(&user_state, req);
let result = send_packet(
Packet::from_message(
Message::Standard(StandardMessage {
flags: 0,
data: Data::OpResp(resp),
}.encrypt(is_encrypted)),
packet.header.channel,
packet.header.is_reliable(),
sock_state.binrw_args()).unwrap(),
&mut write_buf, &mut socket, sock_state.binrw_args()).await;
match result {
Ok(_) => {},
Err(e) => {
log::error!("Failed to send operation response packet: {}", e);
}
}
},
data => log::warn!("Failed to handle packet with message data {:?}", data),
}
}
}
}
//log::warn!("Not handling packet {:?}", packet),
}
}
log::debug!("Goodbye connection from address {}", address); log::debug!("Goodbye connection from address {}", address);
} }
async fn handle_ping(ping: Ping, buf: &mut Vec<u8>, socket: &mut net::TcpStream) {
buf.clear();
let resp = Packet::Ping(polariton_auth::ping_pong(ping));
resp.to_buf(buf, None).unwrap();
let write_count = socket.write(buf).await.unwrap();
log::debug!("(ping) Write {} bytes to socket: {:?}", write_count, buf);
buf.clear();
}
fn buf_likely_valid(buf: &[u8]) -> bool {
buf.is_empty() || buf[0] == Packet::PING_MAGIC || buf[0] == Packet::FRAMED_MAGIC
}
async fn read_more(buf: &mut Vec<u8>, socket: &mut net::TcpStream) -> Result<usize, std::io::Error> {
let read_count = socket.read_buf(buf).await?;
log::debug!("Read {} bytes from socket: {:?}", read_count, buf);
Ok(read_count)
}
async fn receive_packet(buf: &mut Vec<u8>, socket: &mut net::TcpStream, max_retries: Option<NonZero<usize>>, args: Option<Box<Arc<dyn Cryptographer + 'static>>>) -> Result<Packet, std::io::Error> {
if buf.is_empty() {
let read_count = read_more(buf, socket).await?;
if read_count == 0 { return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "socket did not read any bytes")); } // bad packet
}
let mut last_err = None;
let mut must_succeed_next = false;
if let Some(max_retries) = max_retries {
for _ in 0..max_retries.get() {
match Packet::from_buf(&buf, args.clone()) {
Ok(packet) => {
log::debug!("Received packet {:?}", packet);
return Ok(packet);
},
Err(e) => last_err = Some(e),
}
if must_succeed_next {
break;
}
must_succeed_next = read_more(buf, socket).await? == 0;
}
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, last_err.unwrap()));
} else {
while buf_likely_valid(buf.as_slice()) {
match Packet::from_buf(&buf, args.clone()) {
Ok(packet) => {
log::debug!("Received packet {:?}", packet);
return Ok(packet);
},
Err(e) => last_err = Some(e),
}
if must_succeed_next {
break;
}
must_succeed_next = read_more(buf, socket).await? == 0;
}
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, last_err.unwrap()));
}
}
async fn send_packet(packet: Packet, buf: &mut Vec<u8>, socket: &mut net::TcpStream, args: Option<Box<Arc<dyn Cryptographer>>>) -> Result<(), std::io::Error> {
log::debug!("Sending packet {:?}", packet);
buf.clear();
packet.to_buf(buf, args).map_err(|e| std::io::Error::new(std::io::ErrorKind::NotFound, e))?;
let write_count = socket.write(buf).await?;
log::debug!("Write {} bytes to socket: {:?}", write_count, buf);
#[cfg(debug_assertions)]
{
// print out unencrypted packet too
if let Packet::Packet(standard_p) = packet {
if let Message::Standard(standard_m) = standard_p.message {
if standard_m.is_encrypted() {
let standard_m = standard_m.encrypt(false);
let packet = Packet::Packet(StandardPacket { header: standard_p.header, message: Message::Standard(standard_m) });
packet.to_buf(buf, None).map_err(|e| std::io::Error::new(std::io::ErrorKind::NotFound, e))?;
log::debug!("Unencrypted bytes of packet: {:?} (len: {})", buf, buf.len());
}
}
}
}
buf.clear();
Ok(())
}
const APP_ID: &str = "ChatServer"; const APP_ID: &str = "ChatServer";
struct AuthImpl; struct AuthImpl;
@@ -239,21 +99,18 @@ impl polariton_auth::AuthProvider<AuthError> for AuthImpl {
} }
async fn do_connect_handshake( async fn do_connect_handshake(
buf: &mut Vec<u8>,
socket: &mut net::TcpStream, socket: &mut net::TcpStream,
max_retries: Option<NonZero<usize>>, ) -> Option<polariton_auth::CryptoImpl> {
) -> Option<Box<std::sync::Arc<dyn Cryptographer>>> {
let handshake = Handshake::new(APP_ID); let handshake = Handshake::new(APP_ID);
// connect // connect
log::debug!("(connect) Handling first packet"); log::debug!("(connect) Handling first packet");
let packet1 = match receive_packet(buf, socket, max_retries, None).await { let packet1 = match polariton_server::utils::receive_packet_async(socket, &Default::default()).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read connect packet: {}", e); log::error!("Failed to read connect packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
let (handshake, to_send) = match handshake.connect(&packet1) { let (handshake, to_send) = match handshake.connect(&packet1) {
Ok(x) => (x.handshake, x.extra), Ok(x) => (x.handshake, x.extra),
Err(e) => { Err(e) => {
@@ -261,7 +118,7 @@ async fn do_connect_handshake(
return None; return None;
} }
}; };
match send_packet(to_send, buf, socket, None).await { match polariton_server::utils::send_packet_async(&to_send, socket, &Default::default()).await {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
log::error!("Failed to send connect ack packet: {}", e); log::error!("Failed to send connect ack packet: {}", e);
@@ -270,24 +127,22 @@ async fn do_connect_handshake(
} }
// encrypt // encrypt
log::debug!("(connect) Handling second packet"); log::debug!("(connect) Handling second packet");
let mut packet2 = match receive_packet(buf, socket, max_retries, None).await { let mut packet2 = match polariton_server::utils::receive_packet_async(socket, &Default::default()).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) public key packet: {}", e); log::error!("Failed to read (maybe) public key packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
while let Packet::Ping(ping) = packet2 { while let Packet::Ping(ping) = packet2 {
handle_ping(ping, buf, socket).await; polariton_server::utils::handle_ping_async(ping, socket, &Default::default()).await.unwrap_or_default();
packet2 = match receive_packet(buf, socket, max_retries, None).await { packet2 = match polariton_server::utils::receive_packet_async(socket, &Default::default()).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) public key packet: {}", e); log::error!("Failed to read (maybe) public key packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
} }
let (handshake, to_send, crypto) = match handshake.encrypt(&packet2) { let (handshake, to_send, crypto) = match handshake.encrypt(&packet2) {
Ok(x) => (x.handshake, x.extra.0, x.extra.1), Ok(x) => (x.handshake, x.extra.0, x.extra.1),
@@ -296,7 +151,7 @@ async fn do_connect_handshake(
return None; return None;
} }
}; };
match send_packet(to_send, buf, socket, None).await { match polariton_server::utils::send_packet_async(&to_send, socket, &Default::default()).await {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
log::error!("Failed to send encryption ack packet: {}", e); log::error!("Failed to send encryption ack packet: {}", e);
@@ -305,28 +160,28 @@ async fn do_connect_handshake(
} }
// pre-auth // pre-auth
let handshake = handshake.with_auth(AuthImpl); let handshake = handshake.with_auth(AuthImpl);
let op_ctx = polariton::serdes::SerdesContext::default();
let ctx = polariton::packet::SerdesContext::new(&op_ctx, &crypto);
// authenticate // authenticate
log::debug!("(connect) Handling third packet"); log::debug!("(connect) Handling third packet");
let mut packet3 = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await { let mut packet3 = match polariton_server::utils::receive_packet_async(socket, &ctx).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) auth packet: {}", e); log::error!("Failed to read (maybe) auth packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
while let Packet::Ping(ping) = packet3 { while let Packet::Ping(ping) = packet3 {
handle_ping(ping, buf, socket).await; polariton_server::utils::handle_ping_async(ping, socket, &Default::default()).await.unwrap_or_default();
packet3 = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await { packet3 = match polariton_server::utils::receive_packet_async(socket, &ctx).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) auth packet: {}", e); log::error!("Failed to read (maybe) auth packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
} }
let to_send = match handshake.authenticate(&packet3, crypto.clone()) { let to_send = match handshake.authenticate(&packet3, &crypto) {
Ok(x) => x, Ok(x) => x,
Err(h) => match h.extra { Err(h) => match h.extra {
polariton_auth::AuthError::Validation(e) => { polariton_auth::AuthError::Validation(e) => {
@@ -339,7 +194,7 @@ async fn do_connect_handshake(
}, },
}, },
}; };
match send_packet(to_send, buf, socket, Some(crypto.clone())).await { match polariton_server::utils::send_packet_async(&to_send, socket, &ctx).await {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
log::error!("Failed to send auth ack packet: {}", e); log::error!("Failed to send auth ack packet: {}", e);
@@ -349,24 +204,22 @@ async fn do_connect_handshake(
// join lobby // join lobby
log::debug!("(join lobby) Handling fourth packet"); log::debug!("(join lobby) Handling fourth packet");
let mut packet_j = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await { let mut packet_j = match polariton_server::utils::receive_packet_async(socket, &ctx).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) join packet: {}", e); log::error!("Failed to read (maybe) join packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
while let Packet::Ping(ping) = packet_j { while let Packet::Ping(ping) = packet_j {
handle_ping(ping, buf, socket).await; polariton_server::utils::handle_ping_async(ping, socket, &Default::default()).await.unwrap_or_default();
packet_j = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await { packet_j = match polariton_server::utils::receive_packet_async(socket, &ctx).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) join packet: {}", e); log::error!("Failed to read (maybe) join packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
} }
if let Packet::Packet(msg) = &packet_j { if let Packet::Packet(msg) = &packet_j {
if let Message::Standard(st) = &msg.message { if let Message::Standard(st) = &msg.message {
@@ -386,8 +239,8 @@ async fn do_connect_handshake(
message: Typed::Null, message: Typed::Null,
params: params.into(), params: params.into(),
}), }),
}.encrypt(true)), 0, true, Some(crypto.clone())).unwrap(); }.encrypt(true)), 0, true, &ctx).unwrap();
match send_packet(resp, buf, socket, Some(crypto.clone())).await { match polariton_server::utils::send_packet_async(&resp, socket, &ctx).await {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
log::error!("Failed to send lobby ack packet: {}", e); log::error!("Failed to send lobby ack packet: {}", e);
@@ -398,7 +251,6 @@ async fn do_connect_handshake(
} }
} }
} }
buf.clear();
Some(crypto) Some(crypto)
} }

View File

@@ -9,7 +9,7 @@ pub(super) fn all_channels_provider() -> SimpleFunc<11, crate::UserTy, impl (Fn(
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Arr(Arr { params.insert(PARAM_KEY, Typed::Arr(Arr {
ty: 104, // hashtable ty: polariton::serdes::TypePrefix::HashMap, // hashtable
items: vec![ items: vec![
ChatChannelInfo { ChatChannelInfo {
channel_name: "RE_public_channel0".to_owned(), channel_name: "RE_public_channel0".to_owned(),

View File

@@ -7,7 +7,7 @@ pub(super) fn ignores_provider() -> SimpleFunc<8, crate::UserTy, impl (Fn(Parame
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Arr(Arr { params.insert(PARAM_KEY, Typed::Arr(Arr {
ty: 115, // str ty: polariton::serdes::TypePrefix::Str,
items: vec![ items: vec![
Typed::Str("Pluto".into()), Typed::Str("Pluto".into()),
], ],

View File

@@ -7,11 +7,11 @@ impl MoreLobbyAuth {
const AUTH_PAYLOAD_KEY: u8 = 245; const AUTH_PAYLOAD_KEY: u8 = 245;
} }
impl Operation for MoreLobbyAuth { impl <C> Operation<C> for MoreLobbyAuth {
type State = (); type State = ();
type User = crate::UserTy; type User = crate::UserTy;
fn handle(&self, params: polariton::operation::ParameterTable, _: &mut Self::State, user: &Self::User) -> polariton::operation::OperationResponse { fn handle(&self, params: polariton::operation::ParameterTable<C>, _: &mut Self::State, user: &Self::User) -> polariton::operation::OperationResponse<C> {
let params_dict = params.to_dict(); let params_dict = params.to_dict();
if let Some(Typed::Str(auth_payload)) = params_dict.get(&Self::AUTH_PAYLOAD_KEY) { if let Some(Typed::Str(auth_payload)) = params_dict.get(&Self::AUTH_PAYLOAD_KEY) {
let mut write_lock = user.write().unwrap(); let mut write_lock = user.write().unwrap();

View File

@@ -1,24 +1,4 @@
use std::sync::{Arc, RwLock}; use std::sync::RwLock;
pub struct State {
pub crypto: Box<Arc<dyn polariton::packet::Cryptographer>>,
}
impl State {
pub fn new(c: Box<Arc<dyn polariton::packet::Cryptographer>>) -> Self {
Self {
crypto: c,
}
}
pub fn binrw_args(&self) -> polariton::packet::WriteArgs {
Some(self.crypto.clone())
}
pub fn user(&self) -> crate::UserTy {
RwLock::new(UserState::default())
}
}
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct UserState { pub struct UserState {
@@ -40,4 +20,8 @@ impl UserState {
true true
} }
} }
pub fn new() -> crate::UserTy {
RwLock::new(UserState::default())
}
} }

View File

@@ -10,3 +10,4 @@ tokio = { version = "1.43", features = [ "net", "macros", "rt-multi-thread", "io
clap.workspace = true clap.workspace = true
polariton.workspace = true polariton.workspace = true
polariton_auth = { version = "*", path = "../polariton_auth" } polariton_auth = { version = "*", path = "../polariton_auth" }
polariton_server.workspace = true

View File

@@ -1,14 +1,10 @@
mod cli; mod cli;
mod state; mod state;
use std::num::NonZero;
use std::sync::Arc;
use polariton_auth::Handshake; use polariton_auth::Handshake;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net; use tokio::net;
use polariton::packet::{Cryptographer, Data, Message, Packet, Ping, StandardMessage, StandardPacket}; use polariton::packet::{Data, Message, Packet, StandardMessage};
use polariton::operation::{OperationResponse, Typed}; use polariton::operation::{OperationResponse, Typed};
#[tokio::main] #[tokio::main]
@@ -27,21 +23,20 @@ async fn main() -> std::io::Result<()> {
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
loop { loop {
let (socket, address) = listener.accept().await?; let (socket, address) = listener.accept().await?;
tokio::spawn(process_socket(socket, address, NonZero::new(args.retries), redirect_static, room_name_static)); tokio::spawn(process_socket(socket, address, redirect_static, room_name_static));
} }
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
let (socket, address) = listener.accept().await?; let (socket, address) = listener.accept().await?;
process_socket(socket, address, NonZero::new(args.retries), redirect_static, room_name_static).await; process_socket(socket, address, redirect_static, room_name_static).await;
Ok(()) Ok(())
} }
} }
async fn process_socket(mut socket: net::TcpStream, address: std::net::SocketAddr, retries: Option<NonZero<usize>>, game_server_url: &str, game_server_name: &str) { async fn process_socket(mut socket: net::TcpStream, address: std::net::SocketAddr, game_server_url: &str, game_server_name: &str) {
log::debug!("Accepting connection from address {}", address); log::debug!("Accepting connection from address {}", address);
let mut buf = Vec::new(); let enc = match do_connect_handshake(&mut socket, game_server_url, game_server_name).await {
let enc = match do_connect_handshake(&mut buf, &mut socket, retries, game_server_url, game_server_name).await {
Some(x) => x, Some(x) => x,
None => { None => {
log::error!("Failed to do connect handshake with {}", address); log::error!("Failed to do connect handshake with {}", address);
@@ -49,10 +44,10 @@ async fn process_socket(mut socket: net::TcpStream, address: std::net::SocketAdd
} }
}; };
let sock_state = state::State::new(enc); let sock_state = state::State::new(enc);
while let Ok(packet) = receive_packet(&mut buf, &mut socket, retries, sock_state.binrw_args()).await { while let Ok(packet) = polariton_server::utils::receive_packet_async(&mut socket, &sock_state.serdes_ctx()).await {
match packet { match packet {
Packet::Ping(ping) => { Packet::Ping(ping) => {
handle_ping(ping, &mut buf, &mut socket).await; polariton_server::utils::handle_ping_async(ping, &mut socket, &sock_state.serdes_ctx()).await.unwrap_or_default();
}, },
Packet::Packet(packet) => log::warn!("Not handling packet {:?}", packet), Packet::Packet(packet) => log::warn!("Not handling packet {:?}", packet),
} }
@@ -60,87 +55,6 @@ async fn process_socket(mut socket: net::TcpStream, address: std::net::SocketAdd
log::debug!("Goodbye connection from address {}", address); log::debug!("Goodbye connection from address {}", address);
} }
async fn handle_ping(ping: Ping, buf: &mut Vec<u8>, socket: &mut net::TcpStream) {
buf.clear();
let resp = Packet::Ping(polariton_auth::ping_pong(ping));
resp.to_buf(buf, None).unwrap();
let write_count = socket.write(buf).await.unwrap();
log::debug!("(ping) Write {} bytes to socket: {:?}", write_count, buf);
}
fn buf_likely_valid(buf: &[u8]) -> bool {
buf.is_empty() || buf[0] == Packet::PING_MAGIC || buf[0] == Packet::FRAMED_MAGIC
}
async fn read_more(buf: &mut Vec<u8>, socket: &mut net::TcpStream) -> Result<usize, std::io::Error> {
let read_count = socket.read_buf(buf).await?;
log::debug!("Read {} bytes from socket: {:?}", read_count, buf);
Ok(read_count)
}
async fn receive_packet(buf: &mut Vec<u8>, socket: &mut net::TcpStream, max_retries: Option<NonZero<usize>>, args: Option<Box<Arc<dyn Cryptographer + 'static>>>) -> Result<Packet, std::io::Error> {
buf.clear();
let read_count = read_more(buf, socket).await?;
if read_count == 0 { return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "socket did not read any bytes")); } // bad packet
let mut last_err = None;
let mut must_succeed_next = false;
if let Some(max_retries) = max_retries {
for _ in 0..max_retries.get() {
match Packet::from_buf(&buf, args.clone()) {
Ok(packet) => {
log::debug!("(connect) Received packet {:?}", packet);
return Ok(packet);
},
Err(e) => last_err = Some(e),
}
if must_succeed_next {
break;
}
must_succeed_next = read_more(buf, socket).await? == 0;
}
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, last_err.unwrap()));
} else {
while buf_likely_valid(buf.as_slice()) {
match Packet::from_buf(&buf, args.clone()) {
Ok(packet) => {
log::debug!("(connect) Received packet {:?}", packet);
return Ok(packet);
},
Err(e) => last_err = Some(e),
}
if must_succeed_next {
break;
}
must_succeed_next = read_more(buf, socket).await? == 0;
}
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, last_err.unwrap()));
}
}
async fn send_packet(packet: Packet, buf: &mut Vec<u8>, socket: &mut net::TcpStream, args: Option<Box<Arc<dyn Cryptographer>>>) -> Result<(), std::io::Error> {
log::debug!("Sending packet {:?}", packet);
buf.clear();
packet.to_buf(buf, args).map_err(|e| std::io::Error::new(std::io::ErrorKind::NotFound, e))?;
let write_count = socket.write(buf).await?;
log::debug!("Write {} bytes to socket: {:?}", write_count, buf);
#[cfg(debug_assertions)]
{
// print out unencrypted packet too
if let Packet::Packet(standard_p) = packet {
if let Message::Standard(standard_m) = standard_p.message {
if standard_m.is_encrypted() {
let standard_m = standard_m.encrypt(false);
let packet = Packet::Packet(StandardPacket { header: standard_p.header, message: Message::Standard(standard_m) });
packet.to_buf(buf, None).map_err(|e| std::io::Error::new(std::io::ErrorKind::NotFound, e))?;
log::debug!("Unencrypted bytes of packet: {:?} (len: {})", buf, buf.len());
}
}
}
}
Ok(())
}
const APP_ID: &str = "WebServicesServer"; const APP_ID: &str = "WebServicesServer";
struct AuthImpl; struct AuthImpl;
@@ -189,16 +103,14 @@ impl polariton_auth::AuthProvider<AuthError> for AuthImpl {
} }
async fn do_connect_handshake( async fn do_connect_handshake(
buf: &mut Vec<u8>,
socket: &mut net::TcpStream, socket: &mut net::TcpStream,
max_retries: Option<NonZero<usize>>,
game_server_url: &str, game_server_url: &str,
game_server_name: &str, game_server_name: &str,
) -> Option<Box<std::sync::Arc<dyn Cryptographer>>> { ) -> Option<polariton_auth::CryptoImpl> {
let handshake = Handshake::new(APP_ID); let handshake = Handshake::new(APP_ID);
// connect // connect
log::debug!("(connect) Handling first packet"); log::debug!("(connect) Handling first packet");
let packet1 = match receive_packet(buf, socket, max_retries, None).await { let packet1 = match polariton_server::utils::receive_packet_async(socket, &Default::default()).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read connect packet: {}", e); log::error!("Failed to read connect packet: {}", e);
@@ -212,7 +124,7 @@ async fn do_connect_handshake(
return None; return None;
} }
}; };
match send_packet(to_send, buf, socket, None).await { match polariton_server::utils::send_packet_async(&to_send, socket, &Default::default()).await {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
log::error!("Failed to send connect ack packet: {}", e); log::error!("Failed to send connect ack packet: {}", e);
@@ -221,7 +133,7 @@ async fn do_connect_handshake(
} }
// encrypt // encrypt
log::debug!("(connect) Handling second packet"); log::debug!("(connect) Handling second packet");
let mut packet2 = match receive_packet(buf, socket, max_retries, None).await { let mut packet2 = match polariton_server::utils::receive_packet_async(socket, &Default::default()).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) public key packet: {}", e); log::error!("Failed to read (maybe) public key packet: {}", e);
@@ -229,8 +141,8 @@ async fn do_connect_handshake(
} }
}; };
while let Packet::Ping(ping) = packet2 { while let Packet::Ping(ping) = packet2 {
handle_ping(ping, buf, socket).await; polariton_server::utils::handle_ping_async(ping, socket, &Default::default()).await.unwrap_or_default();
packet2 = match receive_packet(buf, socket, max_retries, None).await { packet2 = match polariton_server::utils::receive_packet_async(socket, &Default::default()).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) public key packet: {}", e); log::error!("Failed to read (maybe) public key packet: {}", e);
@@ -245,7 +157,7 @@ async fn do_connect_handshake(
return None; return None;
} }
}; };
match send_packet(to_send, buf, socket, None).await { match polariton_server::utils::send_packet_async(&to_send, socket, &Default::default()).await {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
log::error!("Failed to send encryption ack packet: {}", e); log::error!("Failed to send encryption ack packet: {}", e);
@@ -254,9 +166,11 @@ async fn do_connect_handshake(
} }
// pre-auth // pre-auth
let handshake = handshake.with_auth(AuthImpl); let handshake = handshake.with_auth(AuthImpl);
let op_ctx = polariton::serdes::SerdesContext::default();
let ctx = polariton::packet::SerdesContext::new(&op_ctx, &crypto);
// authenticate // authenticate
log::debug!("(connect) Handling third packet"); log::debug!("(connect) Handling third packet");
let mut packet3 = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await { let mut packet3 = match polariton_server::utils::receive_packet_async(socket, &ctx).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) auth packet: {}", e); log::error!("Failed to read (maybe) auth packet: {}", e);
@@ -264,8 +178,8 @@ async fn do_connect_handshake(
} }
}; };
while let Packet::Ping(ping) = packet3 { while let Packet::Ping(ping) = packet3 {
handle_ping(ping, buf, socket).await; polariton_server::utils::handle_ping_async(ping, socket, &Default::default()).await.unwrap_or_default();
packet3 = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await { packet3 = match polariton_server::utils::receive_packet_async(socket, &ctx).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) auth packet: {}", e); log::error!("Failed to read (maybe) auth packet: {}", e);
@@ -273,7 +187,7 @@ async fn do_connect_handshake(
} }
}; };
} }
let to_send = match handshake.authenticate(&packet3, crypto.clone()) { let to_send = match handshake.authenticate(&packet3, &crypto) {
Ok(x) => x, Ok(x) => x,
Err(h) => match h.extra { Err(h) => match h.extra {
polariton_auth::AuthError::Validation(e) => { polariton_auth::AuthError::Validation(e) => {
@@ -286,7 +200,7 @@ async fn do_connect_handshake(
}, },
}, },
}; };
match send_packet(to_send, buf, socket, Some(crypto.clone())).await { match polariton_server::utils::send_packet_async(&to_send, socket, &ctx).await {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
log::error!("Failed to send auth ack packet: {}", e); log::error!("Failed to send auth ack packet: {}", e);
@@ -302,15 +216,15 @@ async fn do_connect_handshake(
code: 14, // CCU passed event code for Web service code: 14, // CCU passed event code for Web service
params: std::collections::HashMap::new().into(), params: std::collections::HashMap::new().into(),
}), }),
}.encrypt(true)), 0, true, Some(crypto.clone())).unwrap(); }.encrypt(true)), 0, true, &ctx).unwrap();
match send_packet(ccu_passed_event, buf, socket, Some(crypto.clone())).await { match polariton_server::utils::send_packet_async(&ccu_passed_event, socket, &ctx).await {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
log::error!("Failed to send CCU event packet: {}", e); log::error!("Failed to send CCU event packet: {}", e);
return None; return None;
} }
} }
let mut packet_j = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await { let mut packet_j = match polariton_server::utils::receive_packet_async(socket, &ctx).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) join packet: {}", e); log::error!("Failed to read (maybe) join packet: {}", e);
@@ -318,8 +232,8 @@ async fn do_connect_handshake(
} }
}; };
while let Packet::Ping(ping) = packet_j { while let Packet::Ping(ping) = packet_j {
handle_ping(ping, buf, socket).await; polariton_server::utils::handle_ping_async(ping, socket, &Default::default()).await.unwrap_or_default();
packet_j = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await { packet_j = match polariton_server::utils::receive_packet_async(socket, &ctx).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) join packet: {}", e); log::error!("Failed to read (maybe) join packet: {}", e);
@@ -344,8 +258,8 @@ async fn do_connect_handshake(
message: Typed::Null, message: Typed::Null,
params: params.into(), params: params.into(),
}), }),
}.encrypt(true)), 0, true, Some(crypto.clone())).unwrap(); }.encrypt(true)), 0, true, &ctx).unwrap();
match send_packet(resp, buf, socket, Some(crypto.clone())).await { match polariton_server::utils::send_packet_async(&resp, socket, &ctx).await {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
log::error!("Failed to send lobby ack packet: {}", e); log::error!("Failed to send lobby ack packet: {}", e);

View File

@@ -1,17 +1,17 @@
use std::sync::Arc; const SERDES_SERDES_CTX_REF: &'static polariton::serdes::SerdesContext<(), polariton::serdes::NoCustomSerdes> = &polariton::serdes::SerdesContext::default_const();
pub struct State { pub struct State {
pub crypto: Box<Arc<dyn polariton::packet::Cryptographer>>, pub crypto: polariton_auth::CryptoImpl,
} }
impl State { impl State {
pub fn new(c: Box<Arc<dyn polariton::packet::Cryptographer >>) -> Self { pub fn new(c: polariton_auth::CryptoImpl) -> Self {
Self { Self {
crypto: c, crypto: c,
} }
} }
pub fn binrw_args(&self) -> polariton::packet::WriteArgs { pub fn serdes_ctx(&self) -> polariton::packet::SerdesContext<'_, (), polariton::serdes::NoCustomSerdes> {
Some(self.crypto.clone()) polariton::packet::SerdesContext::new(SERDES_SERDES_CTX_REF, &self.crypto)
} }
} }

View File

@@ -1,4 +1,5 @@
use polariton::operation::{Typed, Dict}; use polariton::operation::{Typed, Dict};
use polariton::serdes::TypePrefix;
pub struct DamageBoostData { pub struct DamageBoostData {
pub damage_map: Vec<(u32, f32)>, // (cpu, boost) pub damage_map: Vec<(u32, f32)>, // (cpu, boost)
@@ -7,8 +8,8 @@ pub struct DamageBoostData {
impl DamageBoostData { impl DamageBoostData {
pub fn as_transmissible(&self) -> Typed { pub fn as_transmissible(&self) -> Typed {
Typed::Dict(Dict { Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str,
val_ty: 42, // obj val_ty: TypePrefix::Any,
items: self.damage_map.iter() items: self.damage_map.iter()
.map(|(cpu, boost)| (Typed::Str(cpu.to_string().into()), Typed::Float(*boost))) .map(|(cpu, boost)| (Typed::Str(cpu.to_string().into()), Typed::Float(*boost)))
.collect(), .collect(),

View File

@@ -1,4 +1,4 @@
use polariton::operation::{Typed, Arr}; use polariton::{operation::{Arr, Typed}, serdes::TypePrefix};
use super::weapon_list::ItemCategory; use super::weapon_list::ItemCategory;
@@ -31,7 +31,7 @@ impl GarageSlotInfo {
(Typed::Str("crfId".into()), Typed::Int(self.crf_id as i32)), (Typed::Str("crfId".into()), Typed::Int(self.crf_id as i32)),
(Typed::Str("wasRated".into()), Typed::Bool(self.was_rated.into())), (Typed::Str("wasRated".into()), Typed::Bool(self.was_rated.into())),
(Typed::Str("movementCategories".into()), Typed::Arr(Arr { (Typed::Str("movementCategories".into()), Typed::Arr(Arr {
ty: 105, // int ty: TypePrefix::Int, // int
items: self.movement_categories.iter().map(|x| Typed::Int((*x as i32) * 100_000)).collect(), items: self.movement_categories.iter().map(|x| Typed::Int((*x as i32) * 100_000)).collect(),
})), })),
(Typed::Str("uniqueId1".into()), Typed::Int(self.uuid.0 as i32)), (Typed::Str("uniqueId1".into()), Typed::Int(self.uuid.0 as i32)),
@@ -48,7 +48,7 @@ impl GarageSlotInfo {
(Typed::Str("masteryLevel".into()), Typed::Int(self.mastery_level)), (Typed::Str("masteryLevel".into()), Typed::Int(self.mastery_level)),
(Typed::Str("baySkinId".into()), Typed::Str(self.bay_skin_id.clone().into())), (Typed::Str("baySkinId".into()), Typed::Str(self.bay_skin_id.clone().into())),
(Typed::Str("weaponOrder".into()), Typed::Arr(Arr { (Typed::Str("weaponOrder".into()), Typed::Arr(Arr {
ty: 105, // int ty: TypePrefix::Int, // int
items: self.weapon_order.iter().map(|x| Typed::Int(*x)).collect(), items: self.weapon_order.iter().map(|x| Typed::Int(*x)).collect(),
})), })),
].into()) ].into())
@@ -73,7 +73,7 @@ pub struct ControlOptions {
impl ControlOptions { impl ControlOptions {
pub fn as_transmissible(&self) -> Typed { pub fn as_transmissible(&self) -> Typed {
Typed::Arr(Arr { Typed::Arr(Arr {
ty: 111, // bool ty: TypePrefix::Bool, // bool
items: vec![ items: vec![
Typed::Bool(self.vertical_strafing.into()), Typed::Bool(self.vertical_strafing.into()),
Typed::Bool(self.sideways_driving.into()), Typed::Bool(self.sideways_driving.into()),

View File

@@ -1,6 +1,7 @@
#![allow(dead_code)] #![allow(dead_code)]
use polariton::operation::{Typed, Dict}; use polariton::operation::{Typed, Dict};
use polariton::serdes::TypePrefix;
use super::cube_list::ItemTier; use super::cube_list::ItemTier;
@@ -32,8 +33,8 @@ impl MovementCategoryData {
out.push((Typed::Str(tier.as_str().into()), mov_data.as_transmissible())); out.push((Typed::Str(tier.as_str().into()), mov_data.as_transmissible()));
} }
Typed::Dict(Dict { Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str,
val_ty: 42, // any val_ty: TypePrefix::Any,
items: out.into(), items: out.into(),
}) })
} }
@@ -141,8 +142,8 @@ impl MovementData {
self.vertical_top_speed.map(|x| out.push((Typed::Str("verticalTopSpeed".into()), Typed::Float(x)))); self.vertical_top_speed.map(|x| out.push((Typed::Str("verticalTopSpeed".into()), Typed::Float(x))));
out.append(&mut self.specifics.as_transmissible()); out.append(&mut self.specifics.as_transmissible());
Typed::Dict(Dict { Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str, // str
val_ty: 42, // any val_ty: TypePrefix::Any, // any
items: out.into(), items: out.into(),
}) })
} }

View File

@@ -1,4 +1,5 @@
use polariton::operation::{Typed, Dict, Arr}; use polariton::operation::{Typed, Dict, Arr};
use polariton::serdes::TypePrefix;
pub struct PlayerRankStaticInfo { pub struct PlayerRankStaticInfo {
pub sub_rank_thresholds: Vec<i32>, pub sub_rank_thresholds: Vec<i32>,
@@ -7,12 +8,12 @@ pub struct PlayerRankStaticInfo {
impl PlayerRankStaticInfo { impl PlayerRankStaticInfo {
pub fn as_transmissible(&self) -> Typed { pub fn as_transmissible(&self) -> Typed {
Typed::Dict(Dict { Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str,
val_ty: 42, // obj val_ty: TypePrefix::Any,
items: vec![ items: vec![
(Typed::Str("subRankCount".into()), Typed::Int(self.sub_rank_thresholds.len() as i32)), (Typed::Str("subRankCount".into()), Typed::Int(self.sub_rank_thresholds.len() as i32)),
(Typed::Str("subRankThresholds".into()), Typed::Arr(Arr { (Typed::Str("subRankThresholds".into()), Typed::Arr(Arr {
ty: 105, // int ty: TypePrefix::Int, // int
items: self.sub_rank_thresholds.iter().map(|x| Typed::Int(*x)).collect(), items: self.sub_rank_thresholds.iter().map(|x| Typed::Int(*x)).collect(),
})), })),
], ],

View File

@@ -1,4 +1,5 @@
use polariton::operation::{Typed, Dict}; use polariton::operation::{Typed, Dict};
use polariton::serdes::TypePrefix;
pub struct PlayerRoboPassSeasonInfo { pub struct PlayerRoboPassSeasonInfo {
pub delta_xp_to_show: i32, pub delta_xp_to_show: i32,
@@ -11,8 +12,8 @@ pub struct PlayerRoboPassSeasonInfo {
impl PlayerRoboPassSeasonInfo { impl PlayerRoboPassSeasonInfo {
pub fn as_transmissible(&self) -> Typed { pub fn as_transmissible(&self) -> Typed {
Typed::Dict(Dict { Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str,
val_ty: 42, // obj val_ty: TypePrefix::Any,
items: vec![ items: vec![
(Typed::Str("deltaXpToShow".into()), Typed::Int(self.delta_xp_to_show)), (Typed::Str("deltaXpToShow".into()), Typed::Int(self.delta_xp_to_show)),
(Typed::Str("grade".into()), Typed::Int(self.grade)), (Typed::Str("grade".into()), Typed::Int(self.grade)),

View File

@@ -1,4 +1,4 @@
use polariton::operation::{Typed, Dict}; use polariton::{operation::{Dict, Typed}, serdes::TypePrefix};
pub struct PremiumEffects { pub struct PremiumEffects {
pub factor: PremiumFactor, pub factor: PremiumFactor,
@@ -8,8 +8,8 @@ pub struct PremiumEffects {
impl PremiumEffects { impl PremiumEffects {
pub fn as_transmissible(&self) -> Typed { pub fn as_transmissible(&self) -> Typed {
Typed::Dict(Dict { Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str, // str
val_ty: 104, // hashtable val_ty: TypePrefix::HashMap, // hashtable
items: vec![ items: vec![
(Typed::Str("PremiumFactor".into()), self.factor.as_transmissible()), (Typed::Str("PremiumFactor".into()), self.factor.as_transmissible()),
(Typed::Str("TieredMultiplayer".into()), self.multiplayer.as_transmissible()), (Typed::Str("TieredMultiplayer".into()), self.multiplayer.as_transmissible()),

View File

@@ -1,4 +1,4 @@
use polariton::operation::{Typed, Dict}; use polariton::{operation::{Dict, Typed}, serdes::TypePrefix};
pub struct TauntsData { pub struct TauntsData {
pub taunts: Vec<TauntData>, pub taunts: Vec<TauntData>,
@@ -7,8 +7,8 @@ pub struct TauntsData {
impl TauntsData { impl TauntsData {
pub fn as_transmissible(&self) -> Typed { pub fn as_transmissible(&self) -> Typed {
Typed::Dict(Dict { Typed::Dict(Dict {
key_ty: 115, key_ty: TypePrefix::Str,
val_ty: 42, val_ty: TypePrefix::Any,
items: self.taunts.iter().map(|t| (Typed::Str(t.group_name.clone().into()), t.as_transmissible())).collect(), items: self.taunts.iter().map(|t| (Typed::Str(t.group_name.clone().into()), t.as_transmissible())).collect(),
}) })
} }
@@ -31,15 +31,15 @@ impl TauntData {
(Typed::Str("defaultAnimOffsety".into()), Typed::Float(self.animation_offset_y)), (Typed::Str("defaultAnimOffsety".into()), Typed::Float(self.animation_offset_y)),
(Typed::Str("defaultAnimOffsetz".into()), Typed::Float(self.animation_offset_z)), (Typed::Str("defaultAnimOffsetz".into()), Typed::Float(self.animation_offset_z)),
(Typed::Str("cubes".into()), Typed::Dict(Dict { (Typed::Str("cubes".into()), Typed::Dict(Dict {
key_ty: 115, key_ty: TypePrefix::Str,
val_ty: 42, val_ty: TypePrefix::Any,
items: self.cubes.iter().enumerate().map(|(i, cube)| (Typed::Str(i.to_string().into()), cube.as_transmissible())).collect(), items: self.cubes.iter().enumerate().map(|(i, cube)| (Typed::Str(i.to_string().into()), cube.as_transmissible())).collect(),
})), })),
]; ];
items.append(&mut self.assets.as_transmissible()); items.append(&mut self.assets.as_transmissible());
Typed::Dict(Dict { Typed::Dict(Dict {
key_ty: 115, key_ty: TypePrefix::Str,
val_ty: 42, val_ty: TypePrefix::Any,
items, items,
}) })
} }
@@ -72,8 +72,8 @@ pub struct CubeData {
impl CubeData { impl CubeData {
pub fn as_transmissible(&self) -> Typed { pub fn as_transmissible(&self) -> Typed {
Typed::Dict(Dict { Typed::Dict(Dict {
key_ty: 115, key_ty: TypePrefix::Str,
val_ty: 42, val_ty: TypePrefix::Any,
items: vec![ items: vec![
(Typed::Str("cubeid".into()), Typed::Str(hex::encode((self.cube_id as i32).to_le_bytes()).into())), (Typed::Str("cubeid".into()), Typed::Str(hex::encode((self.cube_id as i32).to_le_bytes()).into())),
(Typed::Str("positionx".into()), Typed::Int(self.position_x)), (Typed::Str("positionx".into()), Typed::Int(self.position_x)),

View File

@@ -1,4 +1,4 @@
use polariton::operation::{Typed, Arr}; use polariton::{operation::{Arr, Typed}, serdes::TypePrefix};
pub struct TechTreeNode { pub struct TechTreeNode {
pub main_cube_id: i32, // hex pub main_cube_id: i32, // hex
@@ -20,7 +20,7 @@ impl TechTreeNode {
(Typed::Str("isUnlockable".into()), Typed::Bool(self.is_unlockable.into())), (Typed::Str("isUnlockable".into()), Typed::Bool(self.is_unlockable.into())),
(Typed::Str("tp".into()), Typed::Int(self.tech_points as i32)), (Typed::Str("tp".into()), Typed::Int(self.tech_points as i32)),
(Typed::Str("neighbours".into()), Typed::Arr(Arr { (Typed::Str("neighbours".into()), Typed::Arr(Arr {
ty: 115, // str ty: TypePrefix::Str, // str
items: self.neighbours.iter().map(|cube_id| Typed::Str(hex::encode(cube_id.to_be_bytes()).into())).collect(), items: self.neighbours.iter().map(|cube_id| Typed::Str(hex::encode(cube_id.to_be_bytes()).into())).collect(),
})), })),
].into()) ].into())

View File

@@ -1,4 +1,4 @@
use polariton::operation::{Typed, Dict}; use polariton::{operation::{Dict, Typed}, serdes::TypePrefix};
use super::{cube_list::ItemTier, weapon_list::ItemCategory}; use super::{cube_list::ItemTier, weapon_list::ItemCategory};
@@ -14,8 +14,8 @@ pub struct WeaponUpgradeInfo {
impl WeaponUpgradeInfo { impl WeaponUpgradeInfo {
pub fn as_transmissible(&self) -> Typed { pub fn as_transmissible(&self) -> Typed {
Typed::Dict(Dict { Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str, // str
val_ty: 42, // obj val_ty: TypePrefix::Any, // obj
items: vec![ items: vec![
(Typed::Str("weaponSize".into()), Typed::Int(self.tier as _)), (Typed::Str("weaponSize".into()), Typed::Int(self.tier as _)),
(Typed::Str("weaponType".into()), Typed::Int(self.type_ as _)), (Typed::Str("weaponType".into()), Typed::Int(self.type_ as _)),

View File

@@ -5,14 +5,10 @@ mod data;
mod events; mod events;
mod operations; mod operations;
use std::num::NonZero;
use std::sync::Arc;
use polariton_auth::Handshake; use polariton_auth::Handshake;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net; use tokio::net;
use polariton::packet::{Cryptographer, Data, Message, Packet, Ping, StandardMessage, StandardPacket}; use polariton::packet::{Data, Message, Packet, StandardMessage};
use polariton::operation::{OperationResponse, Typed}; use polariton::operation::{OperationResponse, Typed};
pub type UserTy = std::sync::RwLock<state::UserState>; pub type UserTy = std::sync::RwLock<state::UserState>;
@@ -23,7 +19,7 @@ async fn main() -> std::io::Result<()> {
let args = cli::CliArgs::get(); let args = cli::CliArgs::get();
log::debug!("Got cli args {:?}", args); log::debug!("Got cli args {:?}", args);
let op_handler = Arc::new(operations::handler()); let server = polariton_server::Server::new(operations::handler());
let ip_addr: std::net::IpAddr = args.ip.parse().expect("Invalid IP address"); let ip_addr: std::net::IpAddr = args.ip.parse().expect("Invalid IP address");
@@ -32,166 +28,30 @@ async fn main() -> std::io::Result<()> {
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
loop { loop {
let (socket, address) = listener.accept().await?; let (socket, address) = listener.accept().await?;
tokio::spawn(process_socket(socket, address, NonZero::new(args.retries), op_handler.clone())); tokio::spawn(process_socket(socket, address, &server));
} }
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
let (socket, address) = listener.accept().await?; let (socket, address) = listener.accept().await?;
process_socket(socket, address, NonZero::new(args.retries), op_handler.clone()).await; process_socket(socket, address, &server).await;
Ok(()) Ok(())
} }
} }
async fn process_socket(mut socket: net::TcpStream, address: std::net::SocketAddr, retries: Option<NonZero<usize>>, op_handler: Arc<polariton_server::operations::OperationsHandler<crate::UserTy>>) { async fn process_socket(mut socket: net::TcpStream, address: std::net::SocketAddr, server: &polariton_server::Server<crate::UserTy>) {
log::debug!("Accepting connection from address {}", address); log::debug!("Accepting connection from address {}", address);
let enc = match do_connect_handshake(&mut socket).await {
let mut read_buf = Vec::new();
let mut write_buf = Vec::new();
let enc = match do_connect_handshake(&mut read_buf, &mut socket, retries).await {
Some(x) => x, Some(x) => x,
None => { None => {
log::error!("Failed to do connect handshake with {}", address); log::error!("Failed to do connect handshake with {}", address);
return; return;
} }
}; };
let sock_state = state::State::new(enc); let user_state = state::UserState::new();
let user_state = sock_state.user(); server.handle_async(socket, user_state, enc, Default::default()).await;
while let Ok(packet) = receive_packet(&mut read_buf, &mut socket, retries, sock_state.binrw_args()).await {
match packet {
Packet::Ping(ping) => {
handle_ping(ping, &mut write_buf, &mut socket).await;
for _ in 0..5 {
read_buf.remove(0);
}
},
Packet::Packet(packet) => {
// remove packet's advertised size from the buffer
for _ in 0..packet.header.len {
read_buf.remove(0);
}
match packet.message {
Message::Ping(ping) => {
handle_ping(ping, &mut write_buf, &mut socket).await;
},
Message::Standard(msg) => {
let is_encrypted = msg.is_encrypted();
match msg.data {
Data::OpReq(req) => {
let resp = op_handler.handle_op(&user_state, req);
let result = send_packet(
Packet::from_message(
Message::Standard(StandardMessage {
flags: 0,
data: Data::OpResp(resp),
}.encrypt(is_encrypted)),
packet.header.channel,
packet.header.is_reliable(),
sock_state.binrw_args()).unwrap(),
&mut write_buf, &mut socket, sock_state.binrw_args()).await;
match result {
Ok(_) => {},
Err(e) => {
log::error!("Failed to send operation response packet: {}", e);
}
}
},
data => log::warn!("Failed to handle packet with message data {:?}", data),
}
}
}
}
//log::warn!("Not handling packet {:?}", packet),
}
}
log::debug!("Goodbye connection from address {}", address); log::debug!("Goodbye connection from address {}", address);
} }
async fn handle_ping(ping: Ping, buf: &mut Vec<u8>, socket: &mut net::TcpStream) {
buf.clear();
let resp = Packet::Ping(polariton_auth::ping_pong(ping));
resp.to_buf(buf, None).unwrap();
let write_count = socket.write(buf).await.unwrap();
log::debug!("(ping) Write {} bytes to socket: {:?}", write_count, buf);
buf.clear();
}
fn buf_likely_valid(buf: &[u8]) -> bool {
buf.is_empty() || buf[0] == Packet::PING_MAGIC || buf[0] == Packet::FRAMED_MAGIC
}
async fn read_more(buf: &mut Vec<u8>, socket: &mut net::TcpStream) -> Result<usize, std::io::Error> {
let read_count = socket.read_buf(buf).await?;
log::debug!("Read {} bytes from socket: {:?}", read_count, buf);
Ok(read_count)
}
async fn receive_packet(buf: &mut Vec<u8>, socket: &mut net::TcpStream, max_retries: Option<NonZero<usize>>, args: Option<Box<Arc<dyn Cryptographer + 'static>>>) -> Result<Packet, std::io::Error> {
if buf.is_empty() {
let read_count = read_more(buf, socket).await?;
if read_count == 0 { return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "socket did not read any bytes")); } // bad packet
}
let mut last_err = None;
let mut must_succeed_next = false;
if let Some(max_retries) = max_retries {
for _ in 0..max_retries.get() {
match Packet::from_buf(&buf, args.clone()) {
Ok(packet) => {
log::debug!("Received packet {:?}", packet);
return Ok(packet);
},
Err(e) => last_err = Some(e),
}
if must_succeed_next {
break;
}
must_succeed_next = read_more(buf, socket).await? == 0;
}
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, last_err.unwrap()));
} else {
while buf_likely_valid(buf.as_slice()) {
match Packet::from_buf(&buf, args.clone()) {
Ok(packet) => {
log::debug!("Received packet {:?}", packet);
return Ok(packet);
},
Err(e) => last_err = Some(e),
}
if must_succeed_next {
break;
}
must_succeed_next = read_more(buf, socket).await? == 0;
}
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, last_err.unwrap()));
}
}
async fn send_packet(packet: Packet, buf: &mut Vec<u8>, socket: &mut net::TcpStream, args: Option<Box<Arc<dyn Cryptographer>>>) -> Result<(), std::io::Error> {
log::debug!("Sending packet {:?}", packet);
buf.clear();
packet.to_buf(buf, args).map_err(|e| std::io::Error::new(std::io::ErrorKind::NotFound, e))?;
let write_count = socket.write(buf).await?;
log::debug!("Write {} bytes to socket: {:?}", write_count, buf);
#[cfg(debug_assertions)]
{
// print out unencrypted packet too
if let Packet::Packet(standard_p) = packet {
if let Message::Standard(standard_m) = standard_p.message {
if standard_m.is_encrypted() {
let standard_m = standard_m.encrypt(false);
let packet = Packet::Packet(StandardPacket { header: standard_p.header, message: Message::Standard(standard_m) });
packet.to_buf(buf, None).map_err(|e| std::io::Error::new(std::io::ErrorKind::NotFound, e))?;
log::debug!("Unencrypted bytes of packet: {:?} (len: {})", buf, buf.len());
}
}
}
}
buf.clear();
Ok(())
}
const APP_ID: &str = "WebServicesServer"; const APP_ID: &str = "WebServicesServer";
struct AuthImpl; struct AuthImpl;
@@ -240,21 +100,18 @@ impl polariton_auth::AuthProvider<AuthError> for AuthImpl {
} }
async fn do_connect_handshake( async fn do_connect_handshake(
buf: &mut Vec<u8>,
socket: &mut net::TcpStream, socket: &mut net::TcpStream,
max_retries: Option<NonZero<usize>>, ) -> Option<polariton_auth::CryptoImpl> {
) -> Option<Box<std::sync::Arc<dyn Cryptographer>>> {
let handshake = Handshake::new(APP_ID); let handshake = Handshake::new(APP_ID);
// connect // connect
log::debug!("(connect) Handling first packet"); log::debug!("(connect) Handling first packet");
let packet1 = match receive_packet(buf, socket, max_retries, None).await { let packet1 = match polariton_server::utils::receive_packet_async(socket, &Default::default()).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read connect packet: {}", e); log::error!("Failed to read connect packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
let (handshake, to_send) = match handshake.connect(&packet1) { let (handshake, to_send) = match handshake.connect(&packet1) {
Ok(x) => (x.handshake, x.extra), Ok(x) => (x.handshake, x.extra),
Err(e) => { Err(e) => {
@@ -262,7 +119,7 @@ async fn do_connect_handshake(
return None; return None;
} }
}; };
match send_packet(to_send, buf, socket, None).await { match polariton_server::utils::send_packet_async(&to_send, socket, &Default::default()).await {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
log::error!("Failed to send connect ack packet: {}", e); log::error!("Failed to send connect ack packet: {}", e);
@@ -271,24 +128,22 @@ async fn do_connect_handshake(
} }
// encrypt // encrypt
log::debug!("(connect) Handling second packet"); log::debug!("(connect) Handling second packet");
let mut packet2 = match receive_packet(buf, socket, max_retries, None).await { let mut packet2 = match polariton_server::utils::receive_packet_async(socket, &Default::default()).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) public key packet: {}", e); log::error!("Failed to read (maybe) public key packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
while let Packet::Ping(ping) = packet2 { while let Packet::Ping(ping) = packet2 {
handle_ping(ping, buf, socket).await; polariton_server::utils::handle_ping_async(ping, socket, &Default::default()).await.unwrap_or_default();
packet2 = match receive_packet(buf, socket, max_retries, None).await { packet2 = match polariton_server::utils::receive_packet_async(socket, &Default::default()).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) public key packet: {}", e); log::error!("Failed to read (maybe) public key packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
} }
let (handshake, to_send, crypto) = match handshake.encrypt(&packet2) { let (handshake, to_send, crypto) = match handshake.encrypt(&packet2) {
Ok(x) => (x.handshake, x.extra.0, x.extra.1), Ok(x) => (x.handshake, x.extra.0, x.extra.1),
@@ -297,7 +152,7 @@ async fn do_connect_handshake(
return None; return None;
} }
}; };
match send_packet(to_send, buf, socket, None).await { match polariton_server::utils::send_packet_async(&to_send, socket, &Default::default()).await {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
log::error!("Failed to send encryption ack packet: {}", e); log::error!("Failed to send encryption ack packet: {}", e);
@@ -306,28 +161,28 @@ async fn do_connect_handshake(
} }
// pre-auth // pre-auth
let handshake = handshake.with_auth(AuthImpl); let handshake = handshake.with_auth(AuthImpl);
let op_ctx = polariton::serdes::SerdesContext::default();
let ctx = polariton::packet::SerdesContext::new(&op_ctx, &crypto);
// authenticate // authenticate
log::debug!("(connect) Handling third packet"); log::debug!("(connect) Handling third packet");
let mut packet3 = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await { let mut packet3 = match polariton_server::utils::receive_packet_async(socket, &ctx).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) auth packet: {}", e); log::error!("Failed to read (maybe) auth packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
while let Packet::Ping(ping) = packet3 { while let Packet::Ping(ping) = packet3 {
handle_ping(ping, buf, socket).await; polariton_server::utils::handle_ping_async(ping, socket, &Default::default()).await.unwrap_or_default();
packet3 = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await { packet3 = match polariton_server::utils::receive_packet_async(socket, &ctx).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) auth packet: {}", e); log::error!("Failed to read (maybe) auth packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
} }
let to_send = match handshake.authenticate(&packet3, crypto.clone()) { let to_send = match handshake.authenticate(&packet3, &crypto) {
Ok(x) => x, Ok(x) => x,
Err(h) => match h.extra { Err(h) => match h.extra {
polariton_auth::AuthError::Validation(e) => { polariton_auth::AuthError::Validation(e) => {
@@ -340,7 +195,7 @@ async fn do_connect_handshake(
}, },
}, },
}; };
match send_packet(to_send, buf, socket, Some(crypto.clone())).await { match polariton_server::utils::send_packet_async(&to_send, socket, &ctx).await {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
log::error!("Failed to send auth ack packet: {}", e); log::error!("Failed to send auth ack packet: {}", e);
@@ -350,24 +205,22 @@ async fn do_connect_handshake(
// join lobby // join lobby
log::debug!("(join lobby) Handling fourth packet"); log::debug!("(join lobby) Handling fourth packet");
let mut packet_j = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await { let mut packet_j = match polariton_server::utils::receive_packet_async(socket, &ctx).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) join packet: {}", e); log::error!("Failed to read (maybe) join packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
while let Packet::Ping(ping) = packet_j { while let Packet::Ping(ping) = packet_j {
handle_ping(ping, buf, socket).await; polariton_server::utils::handle_ping_async(ping, socket, &Default::default()).await.unwrap_or_default();
packet_j = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await { packet_j = match polariton_server::utils::receive_packet_async(socket, &ctx).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) join packet: {}", e); log::error!("Failed to read (maybe) join packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
} }
if let Packet::Packet(msg) = &packet_j { if let Packet::Packet(msg) = &packet_j {
if let Message::Standard(st) = &msg.message { if let Message::Standard(st) = &msg.message {
@@ -387,8 +240,8 @@ async fn do_connect_handshake(
message: Typed::Null, message: Typed::Null,
params: params.into(), params: params.into(),
}), }),
}.encrypt(true)), 0, true, Some(crypto.clone())).unwrap(); }.encrypt(true)), 0, true, &ctx).unwrap();
match send_packet(resp, buf, socket, Some(crypto.clone())).await { match polariton_server::utils::send_packet_async(&resp, socket, &ctx).await {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
log::error!("Failed to send lobby ack packet: {}", e); log::error!("Failed to send lobby ack packet: {}", e);
@@ -399,7 +252,6 @@ async fn do_connect_handshake(
} }
} }
} }
buf.clear();
Some(crypto) Some(crypto)
} }

View File

@@ -1,5 +1,5 @@
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Arr}; use polariton::{operation::{Arr, ParameterTable, Typed}, serdes::TypePrefix};
use crate::data::customisation_info::CustomisationData; use crate::data::customisation_info::CustomisationData;
@@ -16,7 +16,7 @@ pub(super) fn all_customisations_provider() -> SimpleFunc<216, crate::UserTy, im
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(SKINS_KEY, Typed::Arr(Arr { params.insert(SKINS_KEY, Typed::Arr(Arr {
ty: 104, // hashtable ty: TypePrefix::HashMap, // hashtable
items: vec![ items: vec![
CustomisationData { CustomisationData {
id: "RC_MothershipSkin_Neptune_01".to_string(), id: "RC_MothershipSkin_Neptune_01".to_string(),
@@ -29,7 +29,7 @@ pub(super) fn all_customisations_provider() -> SimpleFunc<216, crate::UserTy, im
], ],
})); }));
params.insert(SPAWNS_KEY, Typed::Arr(Arr { params.insert(SPAWNS_KEY, Typed::Arr(Arr {
ty: 104, // hashtable ty: TypePrefix::HashMap, // hashtable
items: vec![ items: vec![
CustomisationData { CustomisationData {
id: "spawn0".to_string(), id: "spawn0".to_string(),
@@ -42,7 +42,7 @@ pub(super) fn all_customisations_provider() -> SimpleFunc<216, crate::UserTy, im
], ],
})); }));
params.insert(DEATHS_KEY, Typed::Arr(Arr { params.insert(DEATHS_KEY, Typed::Arr(Arr {
ty: 104, // hashtable ty: TypePrefix::HashMap, // hashtable
items: vec![ items: vec![
CustomisationData { CustomisationData {
id: "death0".to_string(), id: "death0".to_string(),

View File

@@ -1,5 +1,5 @@
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Dict}; use polariton::{operation::{Dict, ParameterTable, Typed}, serdes::TypePrefix};
use crate::data::battle_arena_config::*; use crate::data::battle_arena_config::*;
@@ -9,8 +9,8 @@ pub(super) fn battle_arena_config_provider() -> SimpleFunc<53, crate::UserTy, im
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Dict(Dict { params.insert(PARAM_KEY, Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str, // str
val_ty: 104, // obj val_ty: TypePrefix::HashMap, // hashmap
items: vec![ items: vec![
(Typed::Str("BattleArenaSettings".into()), BattleArenaData { (Typed::Str("BattleArenaSettings".into()), BattleArenaData {
protonium_health: 1_000, protonium_health: 1_000,

View File

@@ -1,5 +1,5 @@
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Dict}; use polariton::{operation::{Dict, ParameterTable, Typed}, serdes::TypePrefix};
const PARAM_KEY: u8 = 79; const PARAM_KEY: u8 = 79;
@@ -7,8 +7,8 @@ pub(super) fn building_xp_config_provider() -> SimpleFunc<199, crate::UserTy, im
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Dict(Dict { params.insert(PARAM_KEY, Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str, // str
val_ty: 104, // hashtable val_ty: TypePrefix::HashMap, // hashtable
items: vec![ items: vec![
(Typed::Str("BuildXPSettings".into()), Typed::HashMap(vec![ (Typed::Str("BuildXPSettings".into()), Typed::HashMap(vec![
(Typed::Str("buildModePeriodUserEarnXP".into()), Typed::Float(1.0)), // TODO what are the time units? (Typed::Str("buildModePeriodUserEarnXP".into()), Typed::Float(1.0)), // TODO what are the time units?

View File

@@ -1,5 +1,5 @@
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Dict}; use polariton::{operation::{Dict, ParameterTable, Typed}, serdes::TypePrefix};
use crate::data::client_config::*; use crate::data::client_config::*;
@@ -9,8 +9,8 @@ pub(super) fn client_config_provider() -> SimpleFunc<34, crate::UserTy, impl (Fn
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Dict(Dict { params.insert(PARAM_KEY, Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str, // str
val_ty: 104, // hashtable val_ty: TypePrefix::HashMap, // hashtable
items: vec![ items: vec![
(Typed::Str("GameplaySettings".into()), GameplaySettings { (Typed::Str("GameplaySettings".into()), GameplaySettings {
show_tutorial_after_date: "2025-01-01".to_owned(), show_tutorial_after_date: "2025-01-01".to_owned(),

View File

@@ -1,5 +1,5 @@
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Arr}; use polariton::{operation::{Arr, ParameterTable, Typed}, serdes::TypePrefix};
const PARAM_KEY: u8 = 216; const PARAM_KEY: u8 = 216;
@@ -7,7 +7,7 @@ pub(super) fn cube_awards_provider() -> SimpleFunc<206, crate::UserTy, impl (Fn(
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Arr(Arr { params.insert(PARAM_KEY, Typed::Arr(Arr {
ty: 115, // str ty: TypePrefix::Str, // str
items: Vec::default(), items: Vec::default(),
})); }));
Ok(params.into()) Ok(params.into())

View File

@@ -1,5 +1,5 @@
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Dict}; use polariton::{operation::{Dict, ParameterTable, Typed}, serdes::TypePrefix};
const PARAM_KEY: u8 = 16; const PARAM_KEY: u8 = 16;
@@ -7,8 +7,8 @@ pub(super) fn cube_inv_provider() -> SimpleFunc<16, crate::UserTy, impl (Fn(Para
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Dict(Dict { params.insert(PARAM_KEY, Typed::Dict(Dict {
key_ty: 105, // int key_ty: TypePrefix::Int, // int
val_ty: 105, // int val_ty: TypePrefix::Int, // int
items: vec![ items: vec![
(Typed::Int(0), Typed::Int(99)), (Typed::Int(0), Typed::Int(99)),
] })); ] }));

View File

@@ -1,7 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Dict}; use polariton::{operation::{Dict, ParameterTable, Typed}, serdes::TypePrefix};
use crate::data::cube_list::*; use crate::data::cube_list::*;
@@ -12,8 +12,8 @@ pub(super) fn cube_list_provider() -> SimpleFunc<2, crate::UserTy, impl (Fn(Para
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Dict(Dict { params.insert(PARAM_KEY, Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str, // str
val_ty: 104, // hashtable val_ty: TypePrefix::HashMap, // hashtable
items: vec![ items: vec![
//(u32 in base16 aka hex, hashtable) //(u32 in base16 aka hex, hashtable)
CubeInfo { CubeInfo {

View File

@@ -1,5 +1,5 @@
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Dict}; use polariton::{operation::{Dict, ParameterTable, Typed}, serdes::TypePrefix};
use crate::data::custom_games::*; use crate::data::custom_games::*;
@@ -10,8 +10,8 @@ pub(super) fn allowed_maps_provider() -> SimpleFunc<146, crate::UserTy, impl (Fn
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(MODE_MAP_PARAM_KEY, Typed::Dict(Dict { params.insert(MODE_MAP_PARAM_KEY, Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str, // str
val_ty: 122, // obj arr val_ty: TypePrefix::ObjArr, // obj arr
items: vec![ items: vec![
(Typed::Str(GameMode::BattleArena.as_str().into()), Typed::ObjArr(vec![ (Typed::Str(GameMode::BattleArena.as_str().into()), Typed::ObjArr(vec![
Typed::Str("RC_Planet_Neptune_02_BA".into()), Typed::Str("RC_Planet_Neptune_02_BA".into()),
@@ -30,8 +30,8 @@ pub(super) fn allowed_maps_provider() -> SimpleFunc<146, crate::UserTy, impl (Fn
], ],
})); }));
params.insert(MAP_NAMES_PARAM_KEY, Typed::Dict(Dict { params.insert(MAP_NAMES_PARAM_KEY, Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str, // str
val_ty: 115, // str val_ty: TypePrefix::Str, // str
items: vec![ items: vec![
(Typed::Str("RC_Planet_Neptune_02_BA".into()), Typed::Str("strCustomGameMapNameRC_Planet_Neptune_02_BA".into())), (Typed::Str("RC_Planet_Neptune_02_BA".into()), Typed::Str("strCustomGameMapNameRC_Planet_Neptune_02_BA".into())),
(Typed::Str("RC_Planet_Neptune_01_CTF".into()), Typed::Str("strCustomGameMapNameRC_Planet_Neptune_01_CTF".into())), (Typed::Str("RC_Planet_Neptune_01_CTF".into()), Typed::Str("strCustomGameMapNameRC_Planet_Neptune_01_CTF".into())),

View File

@@ -1,5 +1,5 @@
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Dict}; use polariton::{operation::{Dict, ParameterTable, Typed}, serdes::TypePrefix};
use crate::data::custom_games::*; use crate::data::custom_games::*;
@@ -9,8 +9,8 @@ pub(super) fn team_setup_provider() -> SimpleFunc<162, crate::UserTy, impl (Fn(P
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Dict(Dict { params.insert(PARAM_KEY, Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str, // str
val_ty: 105, // int val_ty: TypePrefix::Int, // int
items: vec![ items: vec![
(Typed::Str(GameMode::BattleArena.as_str().into()), Typed::Int(10)), (Typed::Str(GameMode::BattleArena.as_str().into()), Typed::Int(10)),
(Typed::Str(GameMode::SuddenDeath.as_str().into()), Typed::Int(10)), (Typed::Str(GameMode::SuddenDeath.as_str().into()), Typed::Int(10)),

View File

@@ -1,5 +1,5 @@
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Dict}; use polariton::{operation::{Dict, ParameterTable, Typed}, serdes::TypePrefix};
use crate::data::damage_boost::*; use crate::data::damage_boost::*;
@@ -9,8 +9,8 @@ pub(super) fn damage_boost_provider() -> SimpleFunc<163, crate::UserTy, impl (Fn
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Dict(Dict { params.insert(PARAM_KEY, Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str, // str
val_ty: 42, // obj val_ty: TypePrefix::Any, // obj
items: vec![ items: vec![
(Typed::Str("damageBoost".into()), DamageBoostData { (Typed::Str("damageBoost".into()), DamageBoostData {
damage_map: vec![ damage_map: vec![

View File

@@ -2,11 +2,11 @@ use polariton_server::operations::{Operation, OperationCode};
pub struct EacChallengeIgnorer; pub struct EacChallengeIgnorer;
impl Operation for EacChallengeIgnorer { impl <C> Operation<C> for EacChallengeIgnorer {
type State = (); type State = ();
type User = crate::UserTy; type User = crate::UserTy;
fn handle(&self, params: polariton::operation::ParameterTable, _: &mut Self::State, _: &Self::User) -> polariton::operation::OperationResponse { fn handle(&self, params: polariton::operation::ParameterTable<C>, _: &mut Self::State, _: &Self::User) -> polariton::operation::OperationResponse<C> {
polariton::operation::OperationResponse { polariton::operation::OperationResponse {
code: 161, // skip the challenge (hopefully) code: 161, // skip the challenge (hopefully)
return_code: 0, return_code: 0,

View File

@@ -1,5 +1,5 @@
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Arr}; use polariton::{operation::{Arr, ParameterTable, Typed}, serdes::TypePrefix};
use crate::data::custom_games::*; use crate::data::custom_games::*;
@@ -13,28 +13,28 @@ pub(super) fn event_system_params_provider() -> SimpleFunc<24, crate::UserTy, im
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(MAP_NAMES_PARAM_KEY, Typed::Arr(Arr { params.insert(MAP_NAMES_PARAM_KEY, Typed::Arr(Arr {
ty: 115, // str ty: TypePrefix::Str, // str
items: vec![ items: vec![
Typed::Str("RC_Planet_Neptune_03_BA".into()), Typed::Str("RC_Planet_Neptune_03_BA".into()),
Typed::Str("RC_Planet_Earth_01_BA".into()), Typed::Str("RC_Planet_Earth_01_BA".into()),
], ],
})); }));
params.insert(VISIBILITY_PARAM_KEY, Typed::Arr(Arr { params.insert(VISIBILITY_PARAM_KEY, Typed::Arr(Arr {
ty: 105, // int ty: TypePrefix::Int, // int
items: vec![ items: vec![
Typed::Int(GameMode::BattleArena as _), Typed::Int(GameMode::BattleArena as _),
Typed::Int(GameMode::BattleArena as _), Typed::Int(GameMode::BattleArena as _),
], ],
})); }));
params.insert(MODE_PARAM_KEY, Typed::Arr(Arr { params.insert(MODE_PARAM_KEY, Typed::Arr(Arr {
ty: 105, // int ty: TypePrefix::Int, // int
items: vec![ items: vec![
Typed::Int(MapVisibility::Good as _), Typed::Int(MapVisibility::Good as _),
Typed::Int(MapVisibility::Bad as _), Typed::Int(MapVisibility::Bad as _),
], ],
})); }));
params.insert(AUTO_HEAL_PARAM_KEY, Typed::Arr(Arr { params.insert(AUTO_HEAL_PARAM_KEY, Typed::Arr(Arr {
ty: 111, // bool ty: TypePrefix::Bool, // bool
items: vec![ items: vec![
Typed::Bool(true.into()), Typed::Bool(true.into()),
Typed::Bool(false.into()), Typed::Bool(false.into()),

View File

@@ -1,51 +1,51 @@
use std::collections::HashMap; use std::collections::HashMap;
use polariton::operation::{Typed, ParameterTable, OperationResponse, Dict}; use polariton::{operation::{Dict, OperationResponse, ParameterTable, Typed}, serdes::TypePrefix};
use polariton_server::operations::{Operation, OperationCode}; use polariton_server::operations::{Operation, OperationCode};
pub struct QualityConfigTeller; pub struct QualityConfigTeller;
impl Operation for QualityConfigTeller { impl <C> Operation<C> for QualityConfigTeller {
type State = (); type State = ();
type User = crate::UserTy; type User = crate::UserTy;
fn handle(&self, _: ParameterTable, _: &mut Self::State, _: &Self::User) -> OperationResponse { fn handle(&self, _: ParameterTable<C>, _: &mut Self::State, _: &Self::User) -> OperationResponse<C> {
let quality_levels = Typed::HashMap(vec![ let quality_levels = Typed::HashMap(vec![
(Typed::Str("extremLow".into()), Typed::Dict(Dict { (Typed::Str("extremLow".into()), Typed::Dict(Dict {
key_ty: 115, key_ty: TypePrefix::Str,
val_ty: 42, val_ty: TypePrefix::Any,
items: vec![ items: vec![
(Typed::Str("Level".into()), Typed::Long(0)), (Typed::Str("Level".into()), Typed::Long(0)),
(Typed::Str("default".into()), Typed::Float(0.0)), (Typed::Str("default".into()), Typed::Float(0.0)),
], ],
})), })),
(Typed::Str("low".into()), Typed::Dict(Dict { (Typed::Str("low".into()), Typed::Dict(Dict {
key_ty: 115, key_ty: TypePrefix::Str,
val_ty: 42, val_ty: TypePrefix::Any,
items: vec![ items: vec![
(Typed::Str("Level".into()), Typed::Long(1)), (Typed::Str("Level".into()), Typed::Long(1)),
(Typed::Str("default".into()), Typed::Float(0.0)), (Typed::Str("default".into()), Typed::Float(0.0)),
], ],
})), })),
(Typed::Str("normal".into()), Typed::Dict(Dict { (Typed::Str("normal".into()), Typed::Dict(Dict {
key_ty: 115, key_ty: TypePrefix::Str,
val_ty: 42, val_ty: TypePrefix::Any,
items: vec![ items: vec![
(Typed::Str("Level".into()), Typed::Long(2)), (Typed::Str("Level".into()), Typed::Long(2)),
(Typed::Str("default".into()), Typed::Float(0.0)), (Typed::Str("default".into()), Typed::Float(0.0)),
], ],
})), })),
(Typed::Str("beautiful".into()), Typed::Dict(Dict { (Typed::Str("beautiful".into()), Typed::Dict(Dict {
key_ty: 115, key_ty: TypePrefix::Str,
val_ty: 42, val_ty: TypePrefix::Any,
items: vec![ items: vec![
(Typed::Str("Level".into()), Typed::Long(3)), (Typed::Str("Level".into()), Typed::Long(3)),
(Typed::Str("default".into()), Typed::Float(0.0)), (Typed::Str("default".into()), Typed::Float(0.0)),
], ],
})), })),
(Typed::Str("fantastic".into()), Typed::Dict(Dict { (Typed::Str("fantastic".into()), Typed::Dict(Dict {
key_ty: 115, key_ty: TypePrefix::Str,
val_ty: 42, val_ty: TypePrefix::Any,
items: vec![ items: vec![
(Typed::Str("Level".into()), Typed::Long(4)), (Typed::Str("Level".into()), Typed::Long(4)),
(Typed::Str("default".into()), Typed::Float(f32::MAX)), (Typed::Str("default".into()), Typed::Float(f32::MAX)),
@@ -59,8 +59,8 @@ impl Operation for QualityConfigTeller {
let mut resp_params = HashMap::new(); let mut resp_params = HashMap::new();
resp_params.insert(1 /* dict<string, hashtable> */, Typed::Dict( resp_params.insert(1 /* dict<string, hashtable> */, Typed::Dict(
Dict { Dict {
key_ty: 115, // str key_ty: TypePrefix::Str, // str
val_ty: 104, // hash table val_ty: TypePrefix::HashMap, // hash table
items: vec![ items: vec![
(Typed::Str("qualityLevels".into()), quality_levels), (Typed::Str("qualityLevels".into()), quality_levels),
(Typed::Str("systemMemoryThresholds".into()), mem_thresholds), (Typed::Str("systemMemoryThresholds".into()), mem_thresholds),

View File

@@ -1,3 +1,4 @@
use polariton::serdes::TypePrefix;
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Dict}; use polariton::operation::{ParameterTable, Typed, Dict};
@@ -12,8 +13,8 @@ pub(super) fn garage_slot_provider() -> SimpleFunc<40, crate::UserTy, impl (Fn(P
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(SLOTS_PARAM_KEY, Typed::Dict(Dict { params.insert(SLOTS_PARAM_KEY, Typed::Dict(Dict {
key_ty: 105, // int key_ty: TypePrefix::Int, // int
val_ty: 104, // hashmap val_ty: TypePrefix::HashMap, // hashmap
items: vec![ items: vec![
(Typed::Int(0), GarageSlotInfo { (Typed::Int(0), GarageSlotInfo {
name: "Reverse-engineer great success! slot_name".to_owned(), name: "Reverse-engineer great success! slot_name".to_owned(),

View File

@@ -1,5 +1,5 @@
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Dict}; use polariton::{operation::{Dict, ParameterTable, Typed}, serdes::TypePrefix};
const PARAM_KEY: u8 = 1; const PARAM_KEY: u8 = 1;
@@ -8,8 +8,8 @@ pub(super) fn garage_upgrades_provider() -> SimpleFunc<1, crate::UserTy, impl (F
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::HashMap(vec![ params.insert(PARAM_KEY, Typed::HashMap(vec![
(Typed::Str("cpuIncreaseCost".into()), Typed::Dict(Dict { (Typed::Str("cpuIncreaseCost".into()), Typed::Dict(Dict {
key_ty: 105, // int key_ty: TypePrefix::Int, // int
val_ty: 105, // int val_ty: TypePrefix::Int, // int
items: vec![ items: vec![
// (CPU limit, upgrade cost) // (CPU limit, upgrade cost)
(Typed::Int(100), Typed::Int(100)), (Typed::Int(100), Typed::Int(100)),

View File

@@ -1,5 +1,5 @@
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Dict}; use polariton::{operation::{Dict, ParameterTable, Typed}, serdes::TypePrefix};
const PARAM_KEY: u8 = 1; const PARAM_KEY: u8 = 1;
@@ -7,8 +7,8 @@ pub(super) fn league_battle_parameters_provider() -> SimpleFunc<57, crate::UserT
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Dict(Dict { params.insert(PARAM_KEY, Typed::Dict(Dict {
key_ty: 115, //str key_ty: TypePrefix::Str, //str
val_ty: 42, // obj val_ty: TypePrefix::Any, // obj
items: vec![ items: vec![
(Typed::Str("playerLevelRequired".into()), Typed::Int(10)), (Typed::Str("playerLevelRequired".into()), Typed::Int(10)),
(Typed::Str("minCpu".into()), Typed::Int(100)), (Typed::Str("minCpu".into()), Typed::Int(100)),

View File

@@ -1,4 +1,4 @@
use polariton::operation::Dict; use polariton::{operation::Dict, serdes::TypePrefix};
use polariton_server::operations::{Operation, OperationCode}; use polariton_server::operations::{Operation, OperationCode};
pub struct NoAnalytics; pub struct NoAnalytics;
@@ -7,15 +7,15 @@ impl NoAnalytics {
const ANALYTICS_DICT_KEY: u8 = 83; const ANALYTICS_DICT_KEY: u8 = 83;
} }
impl Operation for NoAnalytics { impl <C> Operation<C> for NoAnalytics {
type State = (); type State = ();
type User = crate::UserTy; type User = crate::UserTy;
fn handle(&self, _: polariton::operation::ParameterTable, _: &mut Self::State, _: &Self::User) -> polariton::operation::OperationResponse { fn handle(&self, _: polariton::operation::ParameterTable<C>, _: &mut Self::State, _: &Self::User) -> polariton::operation::OperationResponse<C> {
let mut resp_params = std::collections::HashMap::new(); let mut resp_params = std::collections::HashMap::new();
resp_params.insert(Self::ANALYTICS_DICT_KEY, polariton::operation::Typed::Dict(Dict { resp_params.insert(Self::ANALYTICS_DICT_KEY, polariton::operation::Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str, // str
val_ty: 115, // str val_ty: TypePrefix::Str, // str
items: Vec::new(), items: Vec::new(),
})); }));
polariton::operation::OperationResponse { polariton::operation::OperationResponse {

View File

@@ -14,11 +14,11 @@ impl UserFlagsTeller {
const AB_GROUP_KEY: u8 = 167; const AB_GROUP_KEY: u8 = 167;
} }
impl Operation for UserFlagsTeller { impl <C> Operation<C> for UserFlagsTeller {
type State = (); type State = ();
type User = crate::UserTy; type User = crate::UserTy;
fn handle(&self, _: polariton::operation::ParameterTable, _: &mut Self::State, _: &Self::User) -> polariton::operation::OperationResponse { fn handle(&self, _: polariton::operation::ParameterTable<C>, _: &mut Self::State, _: &Self::User) -> polariton::operation::OperationResponse<C> {
let mut resp_params = std::collections::HashMap::new(); let mut resp_params = std::collections::HashMap::new();
resp_params.insert(Self::REMOVE_OBSOLETE_CUBES_KEY, polariton::operation::Typed::Bool(false.into())); resp_params.insert(Self::REMOVE_OBSOLETE_CUBES_KEY, polariton::operation::Typed::Bool(false.into()));
resp_params.insert(Self::REMOVE_UNOWNED_CUBES_KEY, polariton::operation::Typed::Bool(false.into())); resp_params.insert(Self::REMOVE_UNOWNED_CUBES_KEY, polariton::operation::Typed::Bool(false.into()));

View File

@@ -4,11 +4,11 @@ use polariton_server::operations::{Operation, OperationCode};
pub struct MaintenanceModeTeller; pub struct MaintenanceModeTeller;
impl Operation for MaintenanceModeTeller { impl <C> Operation<C> for MaintenanceModeTeller {
type State = (); type State = ();
type User = crate::UserTy; type User = crate::UserTy;
fn handle(&self, _: polariton::operation::ParameterTable, _: &mut Self::State, _: &Self::User) -> polariton::operation::OperationResponse { fn handle(&self, _: polariton::operation::ParameterTable<C>, _: &mut Self::State, _: &Self::User) -> polariton::operation::OperationResponse<C> {
let mut resp_params = HashMap::new(); let mut resp_params = HashMap::new();
resp_params.insert(20 /* is in maintenance mode? */, polariton::operation::Typed::Bool(false.into())); resp_params.insert(20 /* is in maintenance mode? */, polariton::operation::Typed::Bool(false.into()));
resp_params.insert(19 /* maintenace mode message */, polariton::operation::Typed::Str("OpenJam's servers are currently undergoing maintenance".into())); resp_params.insert(19 /* maintenace mode message */, polariton::operation::Typed::Str("OpenJam's servers are currently undergoing maintenance".into()));

View File

@@ -7,11 +7,11 @@ impl MoreLobbyAuth {
const AUTH_PAYLOAD_KEY: u8 = 245; const AUTH_PAYLOAD_KEY: u8 = 245;
} }
impl Operation for MoreLobbyAuth { impl <C> Operation<C> for MoreLobbyAuth {
type State = (); type State = ();
type User = crate::UserTy; type User = crate::UserTy;
fn handle(&self, params: polariton::operation::ParameterTable, _: &mut Self::State, user: &Self::User) -> polariton::operation::OperationResponse { fn handle(&self, params: polariton::operation::ParameterTable<C>, _: &mut Self::State, user: &Self::User) -> polariton::operation::OperationResponse<C> {
let params_dict = params.to_dict(); let params_dict = params.to_dict();
if let Some(Typed::Str(auth_payload)) = params_dict.get(&Self::AUTH_PAYLOAD_KEY) { if let Some(Typed::Str(auth_payload)) = params_dict.get(&Self::AUTH_PAYLOAD_KEY) {
let mut write_lock = user.write().unwrap(); let mut write_lock = user.write().unwrap();

View File

@@ -1,3 +1,4 @@
use polariton::serdes::TypePrefix;
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Dict}; use polariton::operation::{ParameterTable, Typed, Dict};
@@ -11,8 +12,8 @@ pub(super) fn movement_config_provider() -> SimpleFunc<62, crate::UserTy, impl (
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Dict(Dict { params.insert(PARAM_KEY, Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str, // str
val_ty: 104, // hashtable val_ty: TypePrefix::HashMap, // hashtable
items: vec![ items: vec![
(Typed::Str("Global".into()), Typed::HashMap(vec![ (Typed::Str("Global".into()), Typed::HashMap(vec![
(Typed::Str("lerpValue".into()), Typed::Float(10.0)), (Typed::Str("lerpValue".into()), Typed::Float(10.0)),

View File

@@ -1,5 +1,5 @@
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Arr}; use polariton::{operation::{Arr, ParameterTable, Typed}, serdes::TypePrefix};
const PARAM_KEY: u8 = 50; const PARAM_KEY: u8 = 50;
@@ -7,7 +7,7 @@ pub(super) fn owned_cosmetics_provider() -> SimpleFunc<23, crate::UserTy, impl (
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Arr(Arr { params.insert(PARAM_KEY, Typed::Arr(Arr {
ty: 115, // str ty: TypePrefix::Str, // str
items: vec![Typed::Str("1".into())], items: vec![Typed::Str("1".into())],
})); }));
Ok(params.into()) Ok(params.into())
@@ -18,7 +18,7 @@ pub(super) fn selected_cosmetics_provider() -> SimpleFunc<21, crate::UserTy, imp
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Arr(Arr { params.insert(PARAM_KEY, Typed::Arr(Arr {
ty: 115, // str ty: TypePrefix::Str, // str
items: vec![Typed::Str("1".into())], items: vec![Typed::Str("1".into())],
})); }));
Ok(params.into()) Ok(params.into())

View File

@@ -1,5 +1,5 @@
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Dict}; use polariton::{operation::{Dict, ParameterTable, Typed}, serdes::TypePrefix};
const PLATFORM_CONFIG_KEY: u8 = 197; const PLATFORM_CONFIG_KEY: u8 = 197;
@@ -7,8 +7,8 @@ pub(super) fn platform_config_provider() -> SimpleFunc<165, crate::UserTy, impl
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(PLATFORM_CONFIG_KEY, Typed::Dict(Dict { params.insert(PLATFORM_CONFIG_KEY, Typed::Dict(Dict {
key_ty: 42, // obj key_ty: TypePrefix::Any, // obj
val_ty: 42, // obj val_ty: TypePrefix::Any, // obj
items: vec![ items: vec![
(Typed::Str("BuyPremiumAvailable".into()), Typed::Bool(false.into())), (Typed::Str("BuyPremiumAvailable".into()), Typed::Bool(false.into())),
(Typed::Str("MainShopButtonAvailable".into()), Typed::Bool(false.into())), (Typed::Str("MainShopButtonAvailable".into()), Typed::Bool(false.into())),

View File

@@ -1,5 +1,5 @@
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Arr}; use polariton::{operation::{Arr, ParameterTable, Typed}, serdes::TypePrefix};
use crate::data::{garage_bay::*, weapon_list::ItemCategory}; use crate::data::{garage_bay::*, weapon_list::ItemCategory};
@@ -22,13 +22,13 @@ pub(super) fn player_data_provider() -> SimpleFunc<61, crate::UserTy, impl (Fn(P
params.insert(CONTROL_TYPE_KEY, Typed::Int(ControlType::Camera as _)); params.insert(CONTROL_TYPE_KEY, Typed::Int(ControlType::Camera as _));
params.insert(CONTROL_OPTIONS_KEY, ControlOptions { vertical_strafing: false, sideways_driving: false, tracks_turn_on_spot: false, }.as_transmissible()); params.insert(CONTROL_OPTIONS_KEY, ControlOptions { vertical_strafing: false, sideways_driving: false, tracks_turn_on_spot: false, }.as_transmissible());
params.insert(WEAPON_ORDER_KEY, Typed::Arr(Arr { params.insert(WEAPON_ORDER_KEY, Typed::Arr(Arr {
ty: 105, // int ty: TypePrefix::Int, // int
items: vec![ items: vec![
Typed::Int(0), Typed::Int(0),
], ],
})); }));
params.insert(ITEM_CATEGORY_KEY, Typed::Arr(Arr { params.insert(ITEM_CATEGORY_KEY, Typed::Arr(Arr {
ty: 105, // int ty: TypePrefix::Int, // int
items: vec![ items: vec![
Typed::Int(ItemCategory::Wheel.but_bigger()), Typed::Int(ItemCategory::Wheel.but_bigger()),
], ],

View File

@@ -1,5 +1,5 @@
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Dict}; use polariton::{operation::{Dict, ParameterTable, Typed}, serdes::TypePrefix};
const PARAM_KEY: u8 = 1; const PARAM_KEY: u8 = 1;
@@ -7,8 +7,8 @@ pub(super) fn player_level_info_provider() -> SimpleFunc<3, crate::UserTy, impl
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Dict(Dict { params.insert(PARAM_KEY, Typed::Dict(Dict {
key_ty: 105, // int key_ty: TypePrefix::Int, // int
val_ty: 105, // int val_ty: TypePrefix::Int, // int
items: vec![ items: vec![
(Typed::Int(0), Typed::Int(99)), (Typed::Int(0), Typed::Int(99)),
(Typed::Int(10_000), Typed::Int(99_000)), (Typed::Int(10_000), Typed::Int(99_000)),

View File

@@ -1,5 +1,5 @@
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Dict}; use polariton::{operation::{Dict, ParameterTable, Typed}, serdes::TypePrefix};
use crate::data::robot_data::*; use crate::data::robot_data::*;
@@ -9,8 +9,8 @@ pub(super) fn garage_robot_data_provider() -> SimpleFunc<4, crate::UserTy, impl
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Dict(Dict { params.insert(PARAM_KEY, Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str, // str
val_ty: 104, // hashmap val_ty: TypePrefix::HashMap, // hashmap
items: vec![ items: vec![
(Typed::Str(format!("{}_{}", 12345, 54321).into()), PrebuiltRobotInfo { (Typed::Str(format!("{}_{}", 12345, 54321).into()), PrebuiltRobotInfo {
name: "Reverse-engineer great success! prebuilt_name".to_owned(), name: "Reverse-engineer great success! prebuilt_name".to_owned(),

View File

@@ -1,5 +1,5 @@
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Dict}; use polariton::{operation::{Dict, ParameterTable, Typed}, serdes::TypePrefix};
const PARAM_KEY: u8 = 88; const PARAM_KEY: u8 = 88;
@@ -8,8 +8,8 @@ pub(super) fn pending_purchases_provider() -> SimpleFunc<81, crate::UserTy, impl
let mut params = params.to_dict(); let mut params = params.to_dict();
// TODO implement purchases system // TODO implement purchases system
params.insert(PARAM_KEY, Typed::Dict(Dict { params.insert(PARAM_KEY, Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str, // str
val_ty: 104, // hashtable val_ty: TypePrefix::HashMap, // hashtable
items: vec![], items: vec![],
})); }));
Ok(params.into()) Ok(params.into())

View File

@@ -1,5 +1,5 @@
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Dict}; use polariton::{operation::{Dict, ParameterTable, Typed}, serdes::TypePrefix};
const PARAM_KEY: u8 = 1; const PARAM_KEY: u8 = 1;
@@ -7,8 +7,8 @@ pub(super) fn robopass_preview_provider() -> SimpleFunc<167, crate::UserTy, impl
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Dict(Dict { params.insert(PARAM_KEY, Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str, // str
val_ty: 104, // hashtable val_ty: TypePrefix::HashMap, // hashtable
items: vec![], items: vec![],
})); }));
Ok(params.into()) Ok(params.into())

View File

@@ -1,5 +1,5 @@
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Arr}; use polariton::{operation::{Arr, ParameterTable, Typed}, serdes::TypePrefix};
const ROBOT_ID_PARAM_KEY: u8 = 54; // str (in) const ROBOT_ID_PARAM_KEY: u8 = 54; // str (in)
const SANCTION_JSONS_PARAM_KEY: u8 = 102; // str arr (out; list of jsons) const SANCTION_JSONS_PARAM_KEY: u8 = 102; // str arr (out; list of jsons)
@@ -11,7 +11,7 @@ pub(super) fn robot_sanction_provider() -> SimpleFunc<174, crate::UserTy, impl (
log::debug!("Got sanction check for robot {}", s.string); log::debug!("Got sanction check for robot {}", s.string);
} }
params.insert(SANCTION_JSONS_PARAM_KEY, Typed::Arr(Arr { params.insert(SANCTION_JSONS_PARAM_KEY, Typed::Arr(Arr {
ty: 115, // str ty: TypePrefix::Str, // str
items: Vec::default(), items: Vec::default(),
})); }));
Ok(params.into()) Ok(params.into())
@@ -22,7 +22,7 @@ pub(super) fn all_robot_sanctions_provider() -> SimpleFunc<176, crate::UserTy, i
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(SANCTION_JSONS_PARAM_KEY, Typed::Arr(Arr { params.insert(SANCTION_JSONS_PARAM_KEY, Typed::Arr(Arr {
ty: 115, // str ty: TypePrefix::Str, // str
items: Vec::default(), items: Vec::default(),
})); }));
Ok(params.into()) Ok(params.into())

View File

@@ -1,5 +1,5 @@
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Dict}; use polariton::{operation::{Dict, ParameterTable, Typed}, serdes::TypePrefix};
use crate::data::special_item::*; use crate::data::special_item::*;
@@ -9,8 +9,8 @@ pub(super) fn special_item_list_provider() -> SimpleFunc<6, crate::UserTy, impl
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Dict(Dict { params.insert(PARAM_KEY, Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str, // str
val_ty: 104, // hashtable val_ty: TypePrefix::HashMap, // hashtable
items: vec![ items: vec![
//(u32 in base16 aka hex, hashtable) //(u32 in base16 aka hex, hashtable)
(Typed::Str("DEADBEEF".into()), SpecialItem { (Typed::Str("DEADBEEF".into()), SpecialItem {

View File

@@ -1,5 +1,5 @@
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed}; use polariton::{operation::{ParameterTable, Typed}, serdes::TypePrefix};
use crate::data::taunts_config::*; use crate::data::taunts_config::*;
@@ -9,8 +9,8 @@ pub(super) fn taunts_config_provider() -> SimpleFunc<164, crate::UserTy, impl (F
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Dict(polariton::operation::Dict { params.insert(PARAM_KEY, Typed::Dict(polariton::operation::Dict {
key_ty: 115, key_ty: TypePrefix::Str,
val_ty: 42, val_ty: TypePrefix::Any,
items: vec![ items: vec![
(Typed::Str("taunts".into()), TauntsData { (Typed::Str("taunts".into()), TauntsData {
taunts: vec![ taunts: vec![

View File

@@ -1,5 +1,5 @@
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Dict}; use polariton::{operation::{Dict, ParameterTable, Typed}, serdes::TypePrefix};
use crate::data::tech_tree::*; use crate::data::tech_tree::*;
@@ -9,8 +9,8 @@ pub(super) fn tech_tree_layout_provider() -> SimpleFunc<183, crate::UserTy, impl
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Dict(Dict { params.insert(PARAM_KEY, Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str, // str
val_ty: 104, // hashmap val_ty: TypePrefix::HashMap, // hashmap
items: vec![ items: vec![
TechTreeNode { TechTreeNode {
main_cube_id: 227205318, // default cube id main_cube_id: 227205318, // default cube id

View File

@@ -1,5 +1,5 @@
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Dict}; use polariton::{operation::{Dict, ParameterTable, Typed}, serdes::TypePrefix};
const PARAM_KEY: u8 = 1; const PARAM_KEY: u8 = 1;
@@ -7,8 +7,8 @@ pub(super) fn tiers_banding_provider() -> SimpleFunc<7, crate::UserTy, impl (Fn(
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Dict(Dict { params.insert(PARAM_KEY, Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str, // str
val_ty: 42, // obj val_ty: TypePrefix::Any, // obj
items: vec![ items: vec![
(Typed::Str("tiersbands".into()), Typed::IntArr(vec![ (Typed::Str("tiersbands".into()), Typed::IntArr(vec![
1 1

View File

@@ -7,11 +7,11 @@ impl VersionTeller {
const LATEST_VERSION: i32 = 2855; const LATEST_VERSION: i32 = 2855;
} }
impl Operation for VersionTeller { impl <C> Operation<C> for VersionTeller {
type State = (); type State = ();
type User = crate::UserTy; type User = crate::UserTy;
fn handle(&self, _: polariton::operation::ParameterTable, _: &mut Self::State, _: &Self::User) -> polariton::operation::OperationResponse { fn handle(&self, _: polariton::operation::ParameterTable<C>, _: &mut Self::State, _: &Self::User) -> polariton::operation::OperationResponse<C> {
let mut resp_params = std::collections::HashMap::new(); let mut resp_params = std::collections::HashMap::new();
resp_params.insert(Self::VERSION_NUMBER_KEY, polariton::operation::Typed::Int(Self::LATEST_VERSION)); resp_params.insert(Self::VERSION_NUMBER_KEY, polariton::operation::Typed::Int(Self::LATEST_VERSION));
polariton::operation::OperationResponse { polariton::operation::OperationResponse {

View File

@@ -1,5 +1,5 @@
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Dict}; use polariton::{operation::{Dict, ParameterTable, Typed}, serdes::TypePrefix};
const PARAM_KEY: u8 = 1; const PARAM_KEY: u8 = 1;
@@ -11,16 +11,16 @@ pub(super) fn weapon_rating_provider() -> SimpleFunc<127, crate::UserTy, impl (F
(Typed::Str("subRankInterval".into()), Typed::Int(10)), (Typed::Str("subRankInterval".into()), Typed::Int(10)),
(Typed::Str("gainsPerRank".into()), Typed::ObjArr(vec![ (Typed::Str("gainsPerRank".into()), Typed::ObjArr(vec![
Typed::Dict(Dict { Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str,
val_ty: 42, // obj val_ty: TypePrefix::Any,
items: vec![ items: vec![
(Typed::Str("win".into()), Typed::Int(7)), (Typed::Str("win".into()), Typed::Int(7)),
(Typed::Str("loss".into()), Typed::Int(3)), (Typed::Str("loss".into()), Typed::Int(3)),
], ],
}), }),
Typed::Dict(Dict { Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str,
val_ty: 42, // obj val_ty: TypePrefix::Any,
items: vec![ items: vec![
(Typed::Str("win".into()), Typed::Int(11)), (Typed::Str("win".into()), Typed::Int(11)),
(Typed::Str("loss".into()), Typed::Int(3)), (Typed::Str("loss".into()), Typed::Int(3)),

View File

@@ -1,3 +1,4 @@
use polariton::serdes::TypePrefix;
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Dict}; use polariton::operation::{ParameterTable, Typed, Dict};
@@ -10,8 +11,8 @@ pub(super) fn weapon_config_provider() -> SimpleFunc<47, crate::UserTy, impl (Fn
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Dict(Dict { params.insert(PARAM_KEY, Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str, // str
val_ty: 104, // hashtable val_ty: TypePrefix::HashMap, // hashtable
items: vec![ items: vec![
// (Item category, map<tier, weapon stats>) // (Item category, map<tier, weapon stats>)
(Typed::Str(ItemCategory::Laser.as_str().into()), Typed::HashMap(vec![ (Typed::Str(ItemCategory::Laser.as_str().into()), Typed::HashMap(vec![

View File

@@ -1,5 +1,5 @@
use polariton_server::operations::SimpleFunc; use polariton_server::operations::SimpleFunc;
use polariton::operation::{ParameterTable, Typed, Dict}; use polariton::{operation::{Dict, ParameterTable, Typed}, serdes::TypePrefix};
use crate::data::cube_list::ItemTier; use crate::data::cube_list::ItemTier;
@@ -11,13 +11,13 @@ pub(super) fn weapon_xp_provider() -> SimpleFunc<129, crate::UserTy, impl (Fn(Pa
params.insert(PARAM_KEY, Typed::HashMap(vec![ params.insert(PARAM_KEY, Typed::HashMap(vec![
(Typed::Str("maxPower".into()), Typed::Int(2)), (Typed::Str("maxPower".into()), Typed::Int(2)),
(Typed::Str("powerLevelsPerTier".into()), Typed::Dict(Dict { (Typed::Str("powerLevelsPerTier".into()), Typed::Dict(Dict {
key_ty: 105, // int key_ty: TypePrefix::Int, // int
val_ty: 122, // obj arr val_ty: TypePrefix::ObjArr, // obj arr
items: vec![ items: vec![
(Typed::Int(ItemTier::T0 as _), Typed::ObjArr(vec![ (Typed::Int(ItemTier::T0 as _), Typed::ObjArr(vec![
Typed::Dict(Dict { Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str,
val_ty: 42, // obj val_ty: TypePrefix::Any,
items: vec![ items: vec![
(Typed::Str("xp".into()), Typed::Int(1_000)), (Typed::Str("xp".into()), Typed::Int(1_000)),
(Typed::Str("costRobits".into()), Typed::Int(1_000)), (Typed::Str("costRobits".into()), Typed::Int(1_000)),
@@ -25,8 +25,8 @@ pub(super) fn weapon_xp_provider() -> SimpleFunc<129, crate::UserTy, impl (Fn(Pa
], ],
}), }),
Typed::Dict(Dict { Typed::Dict(Dict {
key_ty: 115, // str key_ty: TypePrefix::Str,
val_ty: 42, // obj val_ty: TypePrefix::Any,
items: vec![ items: vec![
(Typed::Str("xp".into()), Typed::Int(2_000)), (Typed::Str("xp".into()), Typed::Int(2_000)),
(Typed::Str("costRobits".into()), Typed::Int(2_000)), (Typed::Str("costRobits".into()), Typed::Int(2_000)),

View File

@@ -1,24 +1,4 @@
use std::sync::{Arc, RwLock}; use std::sync::RwLock;
pub struct State {
pub crypto: Box<Arc<dyn polariton::packet::Cryptographer>>,
}
impl State {
pub fn new(c: Box<Arc<dyn polariton::packet::Cryptographer>>) -> Self {
Self {
crypto: c,
}
}
pub fn binrw_args(&self) -> polariton::packet::WriteArgs {
Some(self.crypto.clone())
}
pub fn user(&self) -> crate::UserTy {
RwLock::new(UserState::default())
}
}
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct UserState { pub struct UserState {
@@ -40,4 +20,8 @@ impl UserState {
true true
} }
} }
pub fn new() -> crate::UserTy {
RwLock::new(UserState::default())
}
} }

View File

@@ -1,14 +1,10 @@
mod cli; mod cli;
mod state; mod state;
use std::num::NonZero;
use std::sync::Arc;
use polariton_auth::Handshake; use polariton_auth::Handshake;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net; use tokio::net;
use polariton::packet::{Cryptographer, Data, Message, Packet, Ping, StandardMessage, StandardPacket}; use polariton::packet::{Data, Message, Packet, StandardMessage};
use polariton::operation::{OperationResponse, Typed}; use polariton::operation::{OperationResponse, Typed};
#[tokio::main] #[tokio::main]
@@ -28,21 +24,20 @@ async fn main() -> std::io::Result<()> {
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
loop { loop {
let (socket, address) = listener.accept().await?; let (socket, address) = listener.accept().await?;
tokio::spawn(process_socket(socket, address, NonZero::new(args.retries), op_handler.clone(), redirect_static, room_name_static)); tokio::spawn(process_socket(socket, address, op_handler.clone(), redirect_static, room_name_static));
} }
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
let (socket, address) = listener.accept().await?; let (socket, address) = listener.accept().await?;
process_socket(socket, address, NonZero::new(args.retries), redirect_static, room_name_static).await; process_socket(socket, address, redirect_static, room_name_static).await;
Ok(()) Ok(())
} }
} }
async fn process_socket(mut socket: net::TcpStream, address: std::net::SocketAddr, retries: Option<NonZero<usize>>, redirect_url: &str, lobby_name: &str) { async fn process_socket(mut socket: net::TcpStream, address: std::net::SocketAddr, redirect_url: &str, lobby_name: &str) {
log::debug!("Accepting connection from address {}", address); log::debug!("Accepting connection from address {}", address);
let mut buf = Vec::new(); let enc = match do_connect_handshake(&mut socket, lobby_name, redirect_url).await {
let enc = match do_connect_handshake(&mut buf, &mut socket, retries, lobby_name, redirect_url).await {
Some(x) => x, Some(x) => x,
None => { None => {
log::error!("Failed to do connect handshake with {}", address); log::error!("Failed to do connect handshake with {}", address);
@@ -50,10 +45,10 @@ async fn process_socket(mut socket: net::TcpStream, address: std::net::SocketAdd
} }
}; };
let sock_state = state::State::new(enc); let sock_state = state::State::new(enc);
while let Ok(packet) = receive_packet(&mut buf, &mut socket, retries, sock_state.binrw_args()).await { while let Ok(packet) = polariton_server::utils::receive_packet_async(&mut socket, &sock_state.serdes_ctx()).await {
match packet { match packet {
Packet::Ping(ping) => { Packet::Ping(ping) => {
handle_ping(ping, &mut buf, &mut socket).await; polariton_server::utils::handle_ping_async(ping, &mut socket, &sock_state.serdes_ctx()).await.unwrap_or_default();
}, },
Packet::Packet(packet) => log::warn!("Not handling packet {:?}", packet), Packet::Packet(packet) => log::warn!("Not handling packet {:?}", packet),
} }
@@ -61,91 +56,6 @@ async fn process_socket(mut socket: net::TcpStream, address: std::net::SocketAdd
log::debug!("Goodbye connection from address {}", address); log::debug!("Goodbye connection from address {}", address);
} }
async fn handle_ping(ping: Ping, buf: &mut Vec<u8>, socket: &mut net::TcpStream) {
buf.clear();
let resp = Packet::Ping(polariton_auth::ping_pong(ping));
resp.to_buf(buf, None).unwrap();
let write_count = socket.write(buf).await.unwrap();
log::debug!("(ping) Write {} bytes to socket: {:?}", write_count, buf);
buf.clear();
}
fn buf_likely_valid(buf: &[u8]) -> bool {
buf.is_empty() || buf[0] == Packet::PING_MAGIC || buf[0] == Packet::FRAMED_MAGIC
}
async fn read_more(buf: &mut Vec<u8>, socket: &mut net::TcpStream) -> Result<usize, std::io::Error> {
let read_count = socket.read_buf(buf).await?;
log::debug!("Read {} bytes from socket: {:?}", read_count, buf);
Ok(read_count)
}
async fn receive_packet(buf: &mut Vec<u8>, socket: &mut net::TcpStream, max_retries: Option<NonZero<usize>>, args: Option<Box<Arc<dyn Cryptographer + 'static>>>) -> Result<Packet, std::io::Error> {
if buf.is_empty() {
let read_count = read_more(buf, socket).await?;
if read_count == 0 { return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "socket did not read any bytes")); } // bad packet
}
let mut last_err = None;
let mut must_succeed_next = false;
if let Some(max_retries) = max_retries {
for _ in 0..max_retries.get() {
match Packet::from_buf(&buf, args.clone()) {
Ok(packet) => {
log::debug!("Received packet {:?}", packet);
return Ok(packet);
},
Err(e) => last_err = Some(e),
}
if must_succeed_next {
break;
}
must_succeed_next = read_more(buf, socket).await? == 0;
}
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, last_err.unwrap()));
} else {
while buf_likely_valid(buf.as_slice()) {
match Packet::from_buf(&buf, args.clone()) {
Ok(packet) => {
log::debug!("Received packet {:?}", packet);
return Ok(packet);
},
Err(e) => last_err = Some(e),
}
if must_succeed_next {
break;
}
must_succeed_next = read_more(buf, socket).await? == 0;
}
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, last_err.unwrap()));
}
}
async fn send_packet(packet: Packet, buf: &mut Vec<u8>, socket: &mut net::TcpStream, args: Option<Box<Arc<dyn Cryptographer>>>) -> Result<(), std::io::Error> {
log::debug!("Sending packet {:?}", packet);
buf.clear();
packet.to_buf(buf, args).map_err(|e| std::io::Error::new(std::io::ErrorKind::NotFound, e))?;
let write_count = socket.write(buf).await?;
log::debug!("Write {} bytes to socket: {:?}", write_count, buf);
#[cfg(debug_assertions)]
{
// print out unencrypted packet too
if let Packet::Packet(standard_p) = packet {
if let Message::Standard(standard_m) = standard_p.message {
if standard_m.is_encrypted() {
let standard_m = standard_m.encrypt(false);
let packet = Packet::Packet(StandardPacket { header: standard_p.header, message: Message::Standard(standard_m) });
packet.to_buf(buf, None).map_err(|e| std::io::Error::new(std::io::ErrorKind::NotFound, e))?;
log::debug!("Unencrypted bytes of packet: {:?} (len: {})", buf, buf.len());
}
}
}
}
buf.clear();
Ok(())
}
const APP_ID: &str = "SocialServer"; const APP_ID: &str = "SocialServer";
struct AuthImpl; struct AuthImpl;
@@ -194,23 +104,20 @@ impl polariton_auth::AuthProvider<AuthError> for AuthImpl {
} }
async fn do_connect_handshake( async fn do_connect_handshake(
buf: &mut Vec<u8>,
socket: &mut net::TcpStream, socket: &mut net::TcpStream,
max_retries: Option<NonZero<usize>>,
game_server_name: &str, game_server_name: &str,
game_server_url: &str, game_server_url: &str,
) -> Option<Box<std::sync::Arc<dyn Cryptographer>>> { ) -> Option<polariton_auth::CryptoImpl> {
let handshake = Handshake::new(APP_ID); let handshake = Handshake::new(APP_ID);
// connect // connect
log::debug!("(connect) Handling first packet"); log::debug!("(connect) Handling first packet");
let packet1 = match receive_packet(buf, socket, max_retries, None).await { let packet1 = match polariton_server::utils::receive_packet_async(socket, &Default::default()).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read connect packet: {}", e); log::error!("Failed to read connect packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
let (handshake, to_send) = match handshake.connect(&packet1) { let (handshake, to_send) = match handshake.connect(&packet1) {
Ok(x) => (x.handshake, x.extra), Ok(x) => (x.handshake, x.extra),
Err(e) => { Err(e) => {
@@ -218,7 +125,7 @@ async fn do_connect_handshake(
return None; return None;
} }
}; };
match send_packet(to_send, buf, socket, None).await { match polariton_server::utils::send_packet_async(&to_send, socket, &Default::default()).await {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
log::error!("Failed to send connect ack packet: {}", e); log::error!("Failed to send connect ack packet: {}", e);
@@ -227,24 +134,22 @@ async fn do_connect_handshake(
} }
// encrypt // encrypt
log::debug!("(connect) Handling second packet"); log::debug!("(connect) Handling second packet");
let mut packet2 = match receive_packet(buf, socket, max_retries, None).await { let mut packet2 = match polariton_server::utils::receive_packet_async(socket, &Default::default()).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) public key packet: {}", e); log::error!("Failed to read (maybe) public key packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
while let Packet::Ping(ping) = packet2 { while let Packet::Ping(ping) = packet2 {
handle_ping(ping, buf, socket).await; polariton_server::utils::handle_ping_async(ping, socket, &Default::default()).await.unwrap_or_default();
packet2 = match receive_packet(buf, socket, max_retries, None).await { packet2 = match polariton_server::utils::receive_packet_async(socket, &Default::default()).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) public key packet: {}", e); log::error!("Failed to read (maybe) public key packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
} }
let (handshake, to_send, crypto) = match handshake.encrypt(&packet2) { let (handshake, to_send, crypto) = match handshake.encrypt(&packet2) {
Ok(x) => (x.handshake, x.extra.0, x.extra.1), Ok(x) => (x.handshake, x.extra.0, x.extra.1),
@@ -253,7 +158,7 @@ async fn do_connect_handshake(
return None; return None;
} }
}; };
match send_packet(to_send, buf, socket, None).await { match polariton_server::utils::send_packet_async(&to_send, socket, &Default::default()).await {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
log::error!("Failed to send encryption ack packet: {}", e); log::error!("Failed to send encryption ack packet: {}", e);
@@ -262,28 +167,28 @@ async fn do_connect_handshake(
} }
// pre-auth // pre-auth
let handshake = handshake.with_auth(AuthImpl); let handshake = handshake.with_auth(AuthImpl);
let op_ctx = polariton::serdes::SerdesContext::default();
let ctx = polariton::packet::SerdesContext::new(&op_ctx, &crypto);
// authenticate // authenticate
log::debug!("(connect) Handling third packet"); log::debug!("(connect) Handling third packet");
let mut packet3 = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await { let mut packet3 = match polariton_server::utils::receive_packet_async(socket, &ctx).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) auth packet: {}", e); log::error!("Failed to read (maybe) auth packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
while let Packet::Ping(ping) = packet3 { while let Packet::Ping(ping) = packet3 {
handle_ping(ping, buf, socket).await; polariton_server::utils::handle_ping_async(ping, socket, &Default::default()).await.unwrap_or_default();
packet3 = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await { packet3 = match polariton_server::utils::receive_packet_async(socket, &ctx).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) auth packet: {}", e); log::error!("Failed to read (maybe) auth packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
} }
let to_send = match handshake.authenticate(&packet3, crypto.clone()) { let to_send = match handshake.authenticate(&packet3, &crypto) {
Ok(x) => x, Ok(x) => x,
Err(h) => match h.extra { Err(h) => match h.extra {
polariton_auth::AuthError::Validation(e) => { polariton_auth::AuthError::Validation(e) => {
@@ -296,7 +201,7 @@ async fn do_connect_handshake(
}, },
}, },
}; };
match send_packet(to_send, buf, socket, Some(crypto.clone())).await { match polariton_server::utils::send_packet_async(&to_send, socket, &ctx).await {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
log::error!("Failed to send auth ack packet: {}", e); log::error!("Failed to send auth ack packet: {}", e);
@@ -305,7 +210,7 @@ async fn do_connect_handshake(
} }
// redirect to lobby // redirect to lobby
let mut packet_j = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await { let mut packet_j = match polariton_server::utils::receive_packet_async(socket, &ctx).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) join packet: {}", e); log::error!("Failed to read (maybe) join packet: {}", e);
@@ -313,8 +218,8 @@ async fn do_connect_handshake(
} }
}; };
while let Packet::Ping(ping) = packet_j { while let Packet::Ping(ping) = packet_j {
handle_ping(ping, buf, socket).await; polariton_server::utils::handle_ping_async(ping, socket, &Default::default()).await.unwrap_or_default();
packet_j = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await { packet_j = match polariton_server::utils::receive_packet_async(socket, &ctx).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) join packet: {}", e); log::error!("Failed to read (maybe) join packet: {}", e);
@@ -339,8 +244,8 @@ async fn do_connect_handshake(
message: Typed::Null, message: Typed::Null,
params: params.into(), params: params.into(),
}), }),
}.encrypt(true)), 0, true, Some(crypto.clone())).unwrap(); }.encrypt(true)), 0, true, &ctx).unwrap();
match send_packet(resp, buf, socket, Some(crypto.clone())).await { match polariton_server::utils::send_packet_async(&resp, socket, &ctx).await {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
log::error!("Failed to send lobby ack packet: {}", e); log::error!("Failed to send lobby ack packet: {}", e);

View File

@@ -1,17 +1,17 @@
use std::sync::Arc; const SERDES_SERDES_CTX_REF: &'static polariton::serdes::SerdesContext<(), polariton::serdes::NoCustomSerdes> = &polariton::serdes::SerdesContext::default_const();
pub struct State { pub struct State {
pub crypto: Box<Arc<dyn polariton::packet::Cryptographer>>, pub crypto: polariton_auth::CryptoImpl,
} }
impl State { impl State {
pub fn new(c: Box<Arc<dyn polariton::packet::Cryptographer>>) -> Self { pub fn new(c: polariton_auth::CryptoImpl) -> Self {
Self { Self {
crypto: c, crypto: c,
} }
} }
pub fn binrw_args(&self) -> polariton::packet::WriteArgs { pub fn serdes_ctx(&self) -> polariton::packet::SerdesContext<'_, (), polariton::serdes::NoCustomSerdes> {
Some(self.crypto.clone()) polariton::packet::SerdesContext::new(SERDES_SERDES_CTX_REF, &self.crypto)
} }
} }

View File

@@ -13,7 +13,7 @@ pub struct ClanMember {
} }
impl ClanMember { impl ClanMember {
pub fn as_transmissible(&self) -> Typed { pub fn as_transmissible<C>(&self) -> Typed<C> {
Typed::HashMap(vec![ Typed::HashMap(vec![
(Typed::Str("userName".into()), Typed::Str(self.username.clone().into())), (Typed::Str("userName".into()), Typed::Str(self.username.clone().into())),
(Typed::Str("displayName".into()), Typed::Str(self.display_name.clone().into())), (Typed::Str("displayName".into()), Typed::Str(self.display_name.clone().into())),
@@ -59,7 +59,7 @@ pub struct ClanInfo {
} }
impl ClanInfo { impl ClanInfo {
pub fn as_transmissible(&self) -> Typed { pub fn as_transmissible<C>(&self) -> Typed<C> {
Typed::HashMap(vec![ Typed::HashMap(vec![
(Typed::Str("clanName".into()), Typed::Str(self.clan_name.clone().into())), (Typed::Str("clanName".into()), Typed::Str(self.clan_name.clone().into())),
(Typed::Str("clanDescription".into()), Typed::Str(self.clan_description.clone().into())), (Typed::Str("clanDescription".into()), Typed::Str(self.clan_description.clone().into())),

View File

@@ -10,7 +10,7 @@ pub struct ClanInviteInfo {
} }
impl ClanInviteInfo { impl ClanInviteInfo {
pub fn as_transmissible(&self) -> Typed { pub fn as_transmissible<C>(&self) -> Typed<C> {
Typed::HashMap(vec![ Typed::HashMap(vec![
(Typed::Str("userName".into()), Typed::Str(self.username.clone().into())), (Typed::Str("userName".into()), Typed::Str(self.username.clone().into())),
(Typed::Str("displayName".into()), Typed::Str(self.display_name.clone().into())), (Typed::Str("displayName".into()), Typed::Str(self.display_name.clone().into())),

View File

@@ -0,0 +1,21 @@
#[derive(Debug, Clone)]
pub enum CustomType {
FriendInfo, // TODO actually serialise
}
pub struct CustomTypeSerdes;
impl polariton::serdes::CustomSerdes<CustomType> for CustomTypeSerdes {
fn dump(_c: &CustomType, w: &mut dyn std::io::Write) -> std::io::Result<usize> {
let payload = vec![ // FIXME don't manually serialize
0u8, // byte custom type
0u8, 5u8, // short custom object size
3u8, 0u8, 0u8, 0u8, 0u8, // content
];
w.write(&payload)
}
fn parse(_r: &mut dyn std::io::Read) -> std::io::Result<CustomType> {
Ok(CustomType::FriendInfo)
}
}

View File

@@ -7,7 +7,7 @@ pub struct AvatarInfo {
} }
impl AvatarInfo { impl AvatarInfo {
pub fn as_transmissible(&self) -> Typed { pub fn as_transmissible<C>(&self) -> Typed<C> {
Typed::HashMap(vec![ Typed::HashMap(vec![
(Typed::Str("name".into()), Typed::Str(self.name.clone().into())), (Typed::Str("name".into()), Typed::Str(self.name.clone().into())),
(Typed::Str("useCustomAvatar".into()), Typed::Bool(self.use_custom_avatar.into())), (Typed::Str("useCustomAvatar".into()), Typed::Bool(self.use_custom_avatar.into())),

View File

@@ -1,3 +1,4 @@
pub mod friend; pub mod friend;
pub mod clan_invite; pub mod clan_invite;
pub mod clan; pub mod clan;
pub mod custom;

View File

@@ -4,14 +4,10 @@ mod state;
mod data; mod data;
mod operations; mod operations;
use std::num::NonZero;
use std::sync::Arc;
use polariton_auth::Handshake; use polariton_auth::Handshake;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net; use tokio::net;
use polariton::packet::{Cryptographer, Data, Message, Packet, Ping, StandardMessage, StandardPacket}; use polariton::packet::{Data, Message, Packet, StandardMessage};
use polariton::operation::{OperationResponse, Typed}; use polariton::operation::{OperationResponse, Typed};
pub type UserTy = std::sync::RwLock<state::UserState>; pub type UserTy = std::sync::RwLock<state::UserState>;
@@ -22,7 +18,7 @@ async fn main() -> std::io::Result<()> {
let args = cli::CliArgs::get(); let args = cli::CliArgs::get();
log::debug!("Got cli args {:?}", args); log::debug!("Got cli args {:?}", args);
let op_handler = Arc::new(operations::handler()); let server = polariton_server::Server::new(operations::handler());
let ip_addr: std::net::IpAddr = args.ip.parse().expect("Invalid IP address"); let ip_addr: std::net::IpAddr = args.ip.parse().expect("Invalid IP address");
@@ -31,166 +27,31 @@ async fn main() -> std::io::Result<()> {
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
loop { loop {
let (socket, address) = listener.accept().await?; let (socket, address) = listener.accept().await?;
tokio::spawn(process_socket(socket, address, NonZero::new(args.retries), op_handler.clone())); tokio::spawn(process_socket(socket, address, &server));
} }
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
let (socket, address) = listener.accept().await?; let (socket, address) = listener.accept().await?;
process_socket(socket, address, NonZero::new(args.retries), op_handler.clone()).await; process_socket(socket, address, &server).await;
Ok(()) Ok(())
} }
} }
async fn process_socket(mut socket: net::TcpStream, address: std::net::SocketAddr, retries: Option<NonZero<usize>>, op_handler: Arc<polariton_server::operations::OperationsHandler<crate::UserTy>>) { async fn process_socket(mut socket: net::TcpStream, address: std::net::SocketAddr, server: &polariton_server::Server<crate::UserTy, crate::data::custom::CustomType>) {
log::debug!("Accepting connection from address {}", address); log::debug!("Accepting connection from address {}", address);
let enc = match do_connect_handshake(&mut socket).await {
let mut read_buf = Vec::new();
let mut write_buf = Vec::new();
let enc = match do_connect_handshake(&mut read_buf, &mut socket, retries).await {
Some(x) => x, Some(x) => x,
None => { None => {
log::error!("Failed to do connect handshake with {}", address); log::error!("Failed to do connect handshake with {}", address);
return; return;
} }
}; };
let sock_state = state::State::new(enc); let user_state = state::UserState::new();
let user_state = sock_state.user(); let op_ctx = polariton::serdes::SerdesContext::<crate::data::custom::CustomType, crate::data::custom::CustomTypeSerdes>::default_const();
while let Ok(packet) = receive_packet(&mut read_buf, &mut socket, retries, sock_state.binrw_args()).await { server.handle_async(socket, user_state, enc, op_ctx).await;
match packet {
Packet::Ping(ping) => {
handle_ping(ping, &mut write_buf, &mut socket).await;
for _ in 0..5 {
read_buf.remove(0);
}
},
Packet::Packet(packet) => {
// remove packet's advertised size from the buffer
for _ in 0..packet.header.len {
read_buf.remove(0);
}
match packet.message {
Message::Ping(ping) => {
handle_ping(ping, &mut write_buf, &mut socket).await;
},
Message::Standard(msg) => {
let is_encrypted = msg.is_encrypted();
match msg.data {
Data::OpReq(req) => {
let resp = op_handler.handle_op(&user_state, req);
let result = send_packet(
Packet::from_message(
Message::Standard(StandardMessage {
flags: 0,
data: Data::OpResp(resp),
}.encrypt(is_encrypted)),
packet.header.channel,
packet.header.is_reliable(),
sock_state.binrw_args()).unwrap(),
&mut write_buf, &mut socket, sock_state.binrw_args()).await;
match result {
Ok(_) => {},
Err(e) => {
log::error!("Failed to send operation response packet: {}", e);
}
}
},
data => log::warn!("Failed to handle packet with message data {:?}", data),
}
}
}
}
//log::warn!("Not handling packet {:?}", packet),
}
}
log::debug!("Goodbye connection from address {}", address); log::debug!("Goodbye connection from address {}", address);
} }
async fn handle_ping(ping: Ping, buf: &mut Vec<u8>, socket: &mut net::TcpStream) {
buf.clear();
let resp = Packet::Ping(polariton_auth::ping_pong(ping));
resp.to_buf(buf, None).unwrap();
let write_count = socket.write(buf).await.unwrap();
log::debug!("(ping) Write {} bytes to socket: {:?}", write_count, buf);
buf.clear();
}
fn buf_likely_valid(buf: &[u8]) -> bool {
buf.is_empty() || buf[0] == Packet::PING_MAGIC || buf[0] == Packet::FRAMED_MAGIC
}
async fn read_more(buf: &mut Vec<u8>, socket: &mut net::TcpStream) -> Result<usize, std::io::Error> {
let read_count = socket.read_buf(buf).await?;
log::debug!("Read {} bytes from socket: {:?}", read_count, buf);
Ok(read_count)
}
async fn receive_packet(buf: &mut Vec<u8>, socket: &mut net::TcpStream, max_retries: Option<NonZero<usize>>, args: Option<Box<Arc<dyn Cryptographer + 'static>>>) -> Result<Packet, std::io::Error> {
if buf.is_empty() {
let read_count = read_more(buf, socket).await?;
if read_count == 0 { return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "socket did not read any bytes")); } // bad packet
}
let mut last_err = None;
let mut must_succeed_next = false;
if let Some(max_retries) = max_retries {
for _ in 0..max_retries.get() {
match Packet::from_buf(&buf, args.clone()) {
Ok(packet) => {
log::debug!("Received packet {:?}", packet);
return Ok(packet);
},
Err(e) => last_err = Some(e),
}
if must_succeed_next {
break;
}
must_succeed_next = read_more(buf, socket).await? == 0;
}
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, last_err.unwrap()));
} else {
while buf_likely_valid(buf.as_slice()) {
match Packet::from_buf(&buf, args.clone()) {
Ok(packet) => {
log::debug!("Received packet {:?}", packet);
return Ok(packet);
},
Err(e) => last_err = Some(e),
}
if must_succeed_next {
break;
}
must_succeed_next = read_more(buf, socket).await? == 0;
}
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, last_err.unwrap()));
}
}
async fn send_packet(packet: Packet, buf: &mut Vec<u8>, socket: &mut net::TcpStream, args: Option<Box<Arc<dyn Cryptographer>>>) -> Result<(), std::io::Error> {
log::debug!("Sending packet {:?}", packet);
buf.clear();
packet.to_buf(buf, args).map_err(|e| std::io::Error::new(std::io::ErrorKind::NotFound, e))?;
let write_count = socket.write(buf).await?;
log::debug!("Write {} bytes to socket: {:?}", write_count, buf);
#[cfg(debug_assertions)]
{
// print out unencrypted packet too
if let Packet::Packet(standard_p) = packet {
if let Message::Standard(standard_m) = standard_p.message {
if standard_m.is_encrypted() {
let standard_m = standard_m.encrypt(false);
let packet = Packet::Packet(StandardPacket { header: standard_p.header, message: Message::Standard(standard_m) });
packet.to_buf(buf, None).map_err(|e| std::io::Error::new(std::io::ErrorKind::NotFound, e))?;
log::debug!("Unencrypted bytes of packet: {:?} (len: {})", buf, buf.len());
}
}
}
}
buf.clear();
Ok(())
}
const APP_ID: &str = "SocialServer"; const APP_ID: &str = "SocialServer";
struct AuthImpl; struct AuthImpl;
@@ -239,21 +100,18 @@ impl polariton_auth::AuthProvider<AuthError> for AuthImpl {
} }
async fn do_connect_handshake( async fn do_connect_handshake(
buf: &mut Vec<u8>,
socket: &mut net::TcpStream, socket: &mut net::TcpStream,
max_retries: Option<NonZero<usize>>, ) -> Option<polariton_auth::CryptoImpl> {
) -> Option<Box<std::sync::Arc<dyn Cryptographer>>> {
let handshake = Handshake::new(APP_ID); let handshake = Handshake::new(APP_ID);
// connect // connect
log::debug!("(connect) Handling first packet"); log::debug!("(connect) Handling first packet");
let packet1 = match receive_packet(buf, socket, max_retries, None).await { let packet1 = match polariton_server::utils::receive_packet_async(socket, &Default::default()).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read connect packet: {}", e); log::error!("Failed to read connect packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
let (handshake, to_send) = match handshake.connect(&packet1) { let (handshake, to_send) = match handshake.connect(&packet1) {
Ok(x) => (x.handshake, x.extra), Ok(x) => (x.handshake, x.extra),
Err(e) => { Err(e) => {
@@ -261,7 +119,7 @@ async fn do_connect_handshake(
return None; return None;
} }
}; };
match send_packet(to_send, buf, socket, None).await { match polariton_server::utils::send_packet_async(&to_send, socket, &Default::default()).await {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
log::error!("Failed to send connect ack packet: {}", e); log::error!("Failed to send connect ack packet: {}", e);
@@ -270,24 +128,22 @@ async fn do_connect_handshake(
} }
// encrypt // encrypt
log::debug!("(connect) Handling second packet"); log::debug!("(connect) Handling second packet");
let mut packet2 = match receive_packet(buf, socket, max_retries, None).await { let mut packet2 = match polariton_server::utils::receive_packet_async(socket, &Default::default()).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) public key packet: {}", e); log::error!("Failed to read (maybe) public key packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
while let Packet::Ping(ping) = packet2 { while let Packet::Ping(ping) = packet2 {
handle_ping(ping, buf, socket).await; polariton_server::utils::handle_ping_async(ping, socket, &Default::default()).await.unwrap_or_default();
packet2 = match receive_packet(buf, socket, max_retries, None).await { packet2 = match polariton_server::utils::receive_packet_async(socket, &Default::default()).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) public key packet: {}", e); log::error!("Failed to read (maybe) public key packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
} }
let (handshake, to_send, crypto) = match handshake.encrypt(&packet2) { let (handshake, to_send, crypto) = match handshake.encrypt(&packet2) {
Ok(x) => (x.handshake, x.extra.0, x.extra.1), Ok(x) => (x.handshake, x.extra.0, x.extra.1),
@@ -296,7 +152,7 @@ async fn do_connect_handshake(
return None; return None;
} }
}; };
match send_packet(to_send, buf, socket, None).await { match polariton_server::utils::send_packet_async(&to_send, socket, &Default::default()).await {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
log::error!("Failed to send encryption ack packet: {}", e); log::error!("Failed to send encryption ack packet: {}", e);
@@ -305,28 +161,28 @@ async fn do_connect_handshake(
} }
// pre-auth // pre-auth
let handshake = handshake.with_auth(AuthImpl); let handshake = handshake.with_auth(AuthImpl);
let op_ctx = polariton::serdes::SerdesContext::default();
let ctx = polariton::packet::SerdesContext::new(&op_ctx, &crypto);
// authenticate // authenticate
log::debug!("(connect) Handling third packet"); log::debug!("(connect) Handling third packet");
let mut packet3 = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await { let mut packet3 = match polariton_server::utils::receive_packet_async(socket, &ctx).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) auth packet: {}", e); log::error!("Failed to read (maybe) auth packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
while let Packet::Ping(ping) = packet3 { while let Packet::Ping(ping) = packet3 {
handle_ping(ping, buf, socket).await; polariton_server::utils::handle_ping_async(ping, socket, &Default::default()).await.unwrap_or_default();
packet3 = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await { packet3 = match polariton_server::utils::receive_packet_async(socket, &ctx).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) auth packet: {}", e); log::error!("Failed to read (maybe) auth packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
} }
let to_send = match handshake.authenticate(&packet3, crypto.clone()) { let to_send = match handshake.authenticate(&packet3, &crypto) {
Ok(x) => x, Ok(x) => x,
Err(h) => match h.extra { Err(h) => match h.extra {
polariton_auth::AuthError::Validation(e) => { polariton_auth::AuthError::Validation(e) => {
@@ -339,7 +195,7 @@ async fn do_connect_handshake(
}, },
}, },
}; };
match send_packet(to_send, buf, socket, Some(crypto.clone())).await { match polariton_server::utils::send_packet_async(&to_send, socket, &ctx).await {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
log::error!("Failed to send auth ack packet: {}", e); log::error!("Failed to send auth ack packet: {}", e);
@@ -349,24 +205,22 @@ async fn do_connect_handshake(
// join lobby // join lobby
log::debug!("(join lobby) Handling fourth packet"); log::debug!("(join lobby) Handling fourth packet");
let mut packet_j = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await { let mut packet_j = match polariton_server::utils::receive_packet_async(socket, &ctx).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) join packet: {}", e); log::error!("Failed to read (maybe) join packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
while let Packet::Ping(ping) = packet_j { while let Packet::Ping(ping) = packet_j {
handle_ping(ping, buf, socket).await; polariton_server::utils::handle_ping_async(ping, socket, &Default::default()).await.unwrap_or_default();
packet_j = match receive_packet(buf, socket, max_retries, Some(crypto.clone())).await { packet_j = match polariton_server::utils::receive_packet_async(socket, &ctx).await {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
log::error!("Failed to read (maybe) join packet: {}", e); log::error!("Failed to read (maybe) join packet: {}", e);
return None; return None;
} }
}; };
buf.clear();
} }
if let Packet::Packet(msg) = &packet_j { if let Packet::Packet(msg) = &packet_j {
if let Message::Standard(st) = &msg.message { if let Message::Standard(st) = &msg.message {
@@ -386,8 +240,8 @@ async fn do_connect_handshake(
message: Typed::Null, message: Typed::Null,
params: params.into(), params: params.into(),
}), }),
}.encrypt(true)), 0, true, Some(crypto.clone())).unwrap(); }.encrypt(true)), 0, true, &ctx).unwrap();
match send_packet(resp, buf, socket, Some(crypto.clone())).await { match polariton_server::utils::send_packet_async(&resp, socket, &ctx).await {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
log::error!("Failed to send lobby ack packet: {}", e); log::error!("Failed to send lobby ack packet: {}", e);
@@ -398,7 +252,6 @@ async fn do_connect_handshake(
} }
} }
} }
buf.clear();
Some(crypto) Some(crypto)
} }

View File

@@ -9,13 +9,13 @@ const ROBITS_CONVERSION_PARAM_KEY: u8 = 51; // out only
const CLAN_DESCRIPTION_PARAM_KEY: u8 = 32; // out only const CLAN_DESCRIPTION_PARAM_KEY: u8 = 32; // out only
const CLAN_TYPE_PARAM_KEY: u8 = 32; // out only const CLAN_TYPE_PARAM_KEY: u8 = 32; // out only
pub(super) fn clan_info_provider() -> SimpleFunc<33, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result<ParameterTable, i16>) + Sync + Sync> { pub(super) fn clan_info_provider<C: Send + Sync>() -> SimpleFunc<33, crate::UserTy, impl (Fn(ParameterTable<C>, &crate::UserTy) -> Result<ParameterTable<C>, i16>) + Sync + Sync, C> {
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
if let Some(Typed::Str(clan_name)) = params.get(&CLAN_NAME_PARAM_KEY) { if let Some(Typed::Str(clan_name)) = params.get(&CLAN_NAME_PARAM_KEY) {
log::debug!("Requested info on clan {}", clan_name.string); log::debug!("Requested info on clan {}", clan_name.string);
params.insert(MEMBERS_PARAM_KEY, Typed::Arr(Arr { params.insert(MEMBERS_PARAM_KEY, Typed::Arr(Arr {
ty: 104, // hashmap ty: polariton::serdes::TypePrefix::HashMap, // hashmap
items: vec![ items: vec![
ClanMember { ClanMember {
username: "RE_clan_user_idk0".to_owned(), username: "RE_clan_user_idk0".to_owned(),

View File

@@ -5,11 +5,11 @@ use crate::data::clan_invite::*;
const PARAM_KEY: u8 = 42; const PARAM_KEY: u8 = 42;
pub(super) fn clan_invites_provider() -> SimpleFunc<39, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result<ParameterTable, i16>) + Sync + Sync> { pub(super) fn clan_invites_provider<C: Send + Sync>() -> SimpleFunc<39, crate::UserTy, impl (Fn(ParameterTable<C>, &crate::UserTy) -> Result<ParameterTable<C>, i16>) + Sync + Sync, C> {
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Arr(Arr { params.insert(PARAM_KEY, Typed::<C>::Arr(Arr {
ty: 104, // hashmap ty: polariton::serdes::TypePrefix::HashMap, // hashmap
items: vec![ items: vec![
ClanInviteInfo { ClanInviteInfo {
username: "RE_user1".to_owned(), username: "RE_user1".to_owned(),

View File

@@ -6,18 +6,14 @@ use crate::data::friend::*;
const FRIENDS_PARAM_KEY: u8 = 5; const FRIENDS_PARAM_KEY: u8 = 5;
const AVATAR_PARAM_KEY: u8 = 76; const AVATAR_PARAM_KEY: u8 = 76;
pub(super) fn friends_provider() -> SimpleFunc<4, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result<ParameterTable, i16>) + Sync + Sync> { pub(super) fn friends_provider() -> SimpleFunc<4, crate::UserTy, impl (Fn(ParameterTable<crate::data::custom::CustomType>, &crate::UserTy) -> Result<ParameterTable<crate::data::custom::CustomType>, i16>) + Sync + Sync, crate::data::custom::CustomType> {
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(FRIENDS_PARAM_KEY, Typed::Arr(Arr { params.insert(FRIENDS_PARAM_KEY, Typed::Arr(Arr {
ty: 99, // custom ty: polariton::serdes::TypePrefix::Custom, // custom
items: vec![Typed::Custom(vec![ // FIXME don't manually serialize items: vec![Typed::Custom(crate::data::custom::CustomType::FriendInfo)] }));
0u8, // byte custom type
0u8, 5u8, // short custom object size
3u8, 0u8, 0u8, 0u8, 0u8, // content
].into())] }));
params.insert(AVATAR_PARAM_KEY, Typed::Arr(Arr { params.insert(AVATAR_PARAM_KEY, Typed::Arr(Arr {
ty: 104, // hashmap ty: polariton::serdes::TypePrefix::HashMap, // hashmap
items: vec![AvatarInfo { items: vec![AvatarInfo {
name: "".to_string(), name: "".to_string(),
use_custom_avatar: false, use_custom_avatar: false,

View File

@@ -10,8 +10,8 @@ mod platoon_data;
use polariton_server::operations::OperationsHandler; use polariton_server::operations::OperationsHandler;
pub fn handler() -> OperationsHandler<crate::UserTy> { pub fn handler() -> OperationsHandler<crate::UserTy, crate::data::custom::CustomType> {
OperationsHandler::new() OperationsHandler::<crate::UserTy, crate::data::custom::CustomType>::new()
.without_state(more_auth::MoreLobbyAuth) .without_state(more_auth::MoreLobbyAuth)
//.without_state(polariton_server::operations::Ack::<33, _>::default()) // get user clan info (this is equivalent to not being in a clan) //.without_state(polariton_server::operations::Ack::<33, _>::default()) // get user clan info (this is equivalent to not being in a clan)
.without_state(friend_list::friends_provider()) // TODO friend object parsing Token: 0x0200169C RID: 5788 .without_state(friend_list::friends_provider()) // TODO friend object parsing Token: 0x0200169C RID: 5788

View File

@@ -7,11 +7,11 @@ impl MoreLobbyAuth {
const AUTH_PAYLOAD_KEY: u8 = 245; const AUTH_PAYLOAD_KEY: u8 = 245;
} }
impl Operation for MoreLobbyAuth { impl <C> Operation<C> for MoreLobbyAuth {
type State = (); type State = ();
type User = crate::UserTy; type User = crate::UserTy;
fn handle(&self, params: polariton::operation::ParameterTable, _: &mut Self::State, user: &Self::User) -> polariton::operation::OperationResponse { fn handle(&self, params: polariton::operation::ParameterTable<C>, _: &mut Self::State, user: &Self::User) -> polariton::operation::OperationResponse<C> {
let params_dict = params.to_dict(); let params_dict = params.to_dict();
if let Some(Typed::Str(auth_payload)) = params_dict.get(&Self::AUTH_PAYLOAD_KEY) { if let Some(Typed::Str(auth_payload)) = params_dict.get(&Self::AUTH_PAYLOAD_KEY) {
let mut write_lock = user.write().unwrap(); let mut write_lock = user.write().unwrap();

View File

@@ -5,7 +5,7 @@ use polariton::operation::ParameterTable;
//const PLATOON_LEADER_PARAM_KEY: u8 = 17; //const PLATOON_LEADER_PARAM_KEY: u8 = 17;
//const USER_LIST_PARAM_KEY: u8 = 7; //const USER_LIST_PARAM_KEY: u8 = 7;
pub(super) fn platoon_provider() -> SimpleFunc<18, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result<ParameterTable, i16>) + Sync + Sync> { pub(super) fn platoon_provider<C: Send + Sync>() -> SimpleFunc<18, crate::UserTy, impl (Fn(ParameterTable<C>, &crate::UserTy) -> Result<ParameterTable<C>, i16>) + Sync + Sync, C> {
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
//let mut params = params.to_dict(); //let mut params = params.to_dict();
// if platoon ID is not provided, you're not in a platoon // if platoon ID is not provided, you're not in a platoon

View File

@@ -8,7 +8,7 @@ const INVITER_DISPLAY_NAME_PARAM_KEY: u8 = 75;
const INVITER_CUSTOM_AVATAR_NAME_PARAM_KEY: u8 = 13; const INVITER_CUSTOM_AVATAR_NAME_PARAM_KEY: u8 = 13;
const INVITER_AVATAR_ID_NAME_PARAM_KEY: u8 = 14; const INVITER_AVATAR_ID_NAME_PARAM_KEY: u8 = 14;
pub(super) fn platoon_pending_provider() -> SimpleFunc<19, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result<ParameterTable, i16>) + Sync + Sync> { pub(super) fn platoon_pending_provider<C: Send + Sync>() -> SimpleFunc<19, crate::UserTy, impl (Fn(ParameterTable<C>, &crate::UserTy) -> Result<ParameterTable<C>, i16>) + Sync + Sync, C> {
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(INVITER_NAME_PARAM_KEY, Typed::Str("RE_platoon_inviter".into()))); params.insert(INVITER_NAME_PARAM_KEY, Typed::Str("RE_platoon_inviter".into())));

View File

@@ -4,7 +4,7 @@ use polariton::operation::{ParameterTable, Typed};
const PARAM_KEY: u8 = 60; const PARAM_KEY: u8 = 60;
//const USER_PARAM_KEY: u8 = 1; // str (username) //const USER_PARAM_KEY: u8 = 1; // str (username)
pub(super) fn pending_battle_rewards_provider() -> SimpleFunc<54, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result<ParameterTable, i16>) + Sync + Sync> { pub(super) fn pending_battle_rewards_provider<C: Send + Sync>() -> SimpleFunc<54, crate::UserTy, impl (Fn(ParameterTable<C>, &crate::UserTy) -> Result<ParameterTable<C>, i16>) + Sync + Sync, C> {
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Bool(false.into())); params.insert(PARAM_KEY, Typed::Bool(false.into()));

View File

@@ -13,7 +13,7 @@ const TYPES_PARAM_KEY: u8 = 34;*/
// params out // params out
const RESULTS_PARAM_KEY: u8 = 42; const RESULTS_PARAM_KEY: u8 = 42;
pub(super) fn search_clans_provider() -> SimpleFunc<32, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result<ParameterTable, i16>) + Sync + Sync> { pub(super) fn search_clans_provider<C: Send + Sync>() -> SimpleFunc<32, crate::UserTy, impl (Fn(ParameterTable<C>, &crate::UserTy) -> Result<ParameterTable<C>, i16>) + Sync + Sync, C> {
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
if let Some(Typed::Str(s)) = params.get(&STRING_PARAM_KEY) { if let Some(Typed::Str(s)) = params.get(&STRING_PARAM_KEY) {
@@ -22,7 +22,7 @@ pub(super) fn search_clans_provider() -> SimpleFunc<32, crate::UserTy, impl (Fn(
} }
} }
params.insert(RESULTS_PARAM_KEY, Typed::Arr(Arr { params.insert(RESULTS_PARAM_KEY, Typed::Arr(Arr {
ty: 104, // hashmap ty: polariton::serdes::TypePrefix::HashMap, // hashmap
items: vec![ items: vec![
ClanInfo { ClanInfo {
clan_name: "".to_owned(), clan_name: "".to_owned(),

View File

@@ -10,7 +10,7 @@ const CLAN_TOTAL_PARAM_KEY: u8 = 55;
const CLAN_NAME_PARAM_KEY: u8 = 31; const CLAN_NAME_PARAM_KEY: u8 = 31;
const PLAYER_XP_PARAM_KEY: u8 = 57; const PLAYER_XP_PARAM_KEY: u8 = 57;
pub(super) fn season_rewards_provider() -> SimpleFunc<50, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result<ParameterTable, i16>) + Sync + Sync> { pub(super) fn season_rewards_provider<C: Send + Sync>() -> SimpleFunc<50, crate::UserTy, impl (Fn(ParameterTable<C>, &crate::UserTy) -> Result<ParameterTable<C>, i16>) + Sync + Sync, C> {
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(MONTH_PARAM_KEY, Typed::Int(02)); params.insert(MONTH_PARAM_KEY, Typed::Int(02));

View File

@@ -3,12 +3,12 @@ use polariton::operation::{ParameterTable, Typed, Dict};
const PARAM_KEY: u8 = 30; const PARAM_KEY: u8 = 30;
pub(super) fn settings_provider() -> SimpleFunc<24, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result<ParameterTable, i16>) + Sync + Sync> { pub(super) fn settings_provider<C: Send + Sync>() -> SimpleFunc<24, crate::UserTy, impl (Fn(ParameterTable<C>, &crate::UserTy) -> Result<ParameterTable<C>, i16>) + Sync + Sync, C> {
SimpleFunc::new(|params, _| { SimpleFunc::new(|params, _| {
let mut params = params.to_dict(); let mut params = params.to_dict();
params.insert(PARAM_KEY, Typed::Dict(Dict { params.insert(PARAM_KEY, Typed::Dict(Dict {
key_ty: 115, key_ty: polariton::serdes::TypePrefix::Str,
val_ty: 42, val_ty: polariton::serdes::TypePrefix::Any,
items: Vec::default(), items: Vec::default(),
})); }));
Ok(params.into()) Ok(params.into())

View File

@@ -1,24 +1,4 @@
use std::sync::{Arc, RwLock}; use std::sync::RwLock;
pub struct State {
pub crypto: Box<Arc<dyn polariton::packet::Cryptographer>>,
}
impl State {
pub fn new(c: Box<Arc<dyn polariton::packet::Cryptographer>>) -> Self {
Self {
crypto: c,
}
}
pub fn binrw_args(&self) -> polariton::packet::WriteArgs {
Some(self.crypto.clone())
}
pub fn user(&self) -> crate::UserTy {
RwLock::new(UserState::default())
}
}
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct UserState { pub struct UserState {
@@ -40,4 +20,8 @@ impl UserState {
true true
} }
} }
pub fn new() -> crate::UserTy {
RwLock::new(UserState::default())
}
} }