base2020/src/main.rs

72 lines
2.0 KiB
Rust

#[macro_use]
extern crate log;
use anyhow::{Context, Error, Result};
use futures::prelude::*;
use net::{ClientMessage, ServerMessage};
use serde_json::{from_str, Value};
use std::net::ToSocketAddrs;
use stream::{iter, FuturesUnordered};
use structopt::StructOpt;
use warp::{serve, ws, ws::Ws, Filter};
use ws::{Message, WebSocket};
pub mod net;
#[derive(StructOpt)]
/// Server for base2020 lockstep protocol for multiplayer games.
struct Args {
/// The socket address to listen for connections on;
/// can be a hostname to bind to multiple hosts at once,
/// such as to listen on both IPv4 & IPv6.
listen: String,
}
#[tokio::main]
async fn main() -> Result<()> {
env_logger::init();
let args = Args::from_args();
// dispatch websockets
let socket_handler = ws().map(|upgrade: Ws| upgrade.on_upgrade(handle_socket));
let addrs = args
.listen
.to_socket_addrs()
.context("Couldn't parse the listen address")?;
let servers = FuturesUnordered::new();
for addr in addrs {
let (_, server) = serve(socket_handler).try_bind_ephemeral(addr)?;
servers.push(server);
}
servers.for_each(|_| async {}).await;
Ok(())
}
async fn handle_socket(websocket: WebSocket) {
let (_sink, mut source) = websocket.split();
let error: Option<Error> = loop {
match source.next().await {
Some(Ok(msg)) => match msg.to_str() {
Ok(json) => {
match from_str::<ClientMessage<Value, Value>>(json).context("Parsing JSON") {
Ok(msg) => {
debug!("Client message: {:?}", &msg);
}
Err(error) => break Some(error),
}
}
Err(()) => debug!("Non-text message"),
},
Some(Err(error)) => break Some(error.into()),
None => break None,
}
};
if let Some(error) = error {
warn!("Websocket connection lost: {:#}", error);
}
}