Files
openworm/src/bin/server/main.rs
2026-02-18 21:52:22 -05:00

88 lines
2.2 KiB
Rust

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<RwLock<HashMap<ClientId, ClientSender>>>,
count: AtomicU64,
}
impl ConAccepter for ServerListener {
async fn accept(&self, send: ClientSender) -> impl RecvHandler<ClientMsgInst> {
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,
}
}
}