mod db; mod handle; mod net; use crate::{ db::{Db, ServerPerms}, handle::{ClientHandler, ClientState}, }; use clap::Parser; use net::{ClientSender, ConAccepter, listen}; use openworm::{ net::{AccountToken, ClientMsgInst, RecvHandler, install_crypto_provider}, rsc::DataDir, }; use rand::distr::{Alphanumeric, SampleString}; use std::{ collections::HashMap, sync::{ Arc, atomic::{AtomicU64, Ordering}, }, }; use tokio::{signal::ctrl_c, sync::RwLock}; #[derive(Parser, Debug)] #[command(version, about, long_about = None)] struct Args { /// port to listen on #[arg(short, long)] port: u16, } fn main() { let args = Args::parse(); install_crypto_provider(); run_server(args.port); } #[tokio::main] pub async fn run_server(port: u16) { let dir = DataDir::new(Some("server")); let db = Db::open(dir.path.join("db")); let handler = ServerListener { senders: Default::default(), count: 0.into(), db: db.clone(), }; if db.users.is_empty() { let token = account_token(&db, ServerPerms::ALL); println!("no users found, token for admin: {token}"); } let (endpoint, handle) = listen(port, &dir.path, handler); let _ = ctrl_c().await; println!("stopping server"); println!("closing connections..."); endpoint.close(0u32.into(), &[]); let _ = handle.await; endpoint.wait_idle().await; } pub fn account_token(db: &Db, perms: ServerPerms) -> AccountToken { let token = Alphanumeric.sample_string(&mut rand::rng(), 16); db.account_tokens.insert(&token, &perms); token } type ClientId = u64; struct ServerListener { db: Db, senders: Arc>>, count: AtomicU64, } impl ConAccepter for ServerListener { async fn accept(&self, send: ClientSender) -> impl RecvHandler { let id = self.count.fetch_add(1, Ordering::Release); self.senders.write().await.insert(id, send.clone()); ClientHandler { db: self.db.clone(), senders: self.senders.clone(), state: Arc::new(RwLock::new(ClientState::Login)), send, id, } } }