2020-05-17 11:30:18 +00:00
|
|
|
use syndicate::{spaces, packets, ConnId, V, Syndicate};
|
|
|
|
use syndicate::peer::{Peer, ResultC2S};
|
|
|
|
use preserves::value;
|
2019-09-19 09:54:01 +00:00
|
|
|
|
2019-10-16 15:54:58 +00:00
|
|
|
use std::sync::{Mutex, Arc};
|
2020-05-17 11:30:18 +00:00
|
|
|
use futures::{SinkExt, StreamExt};
|
|
|
|
|
2019-10-16 15:54:58 +00:00
|
|
|
use tokio::net::TcpListener;
|
2020-05-17 11:30:18 +00:00
|
|
|
use tokio::net::TcpStream;
|
|
|
|
use tokio_util::codec::Framed;
|
2018-12-09 13:28:01 +00:00
|
|
|
|
2020-05-17 11:30:18 +00:00
|
|
|
use tungstenite::Message;
|
|
|
|
|
|
|
|
use structopt::StructOpt;
|
|
|
|
|
2020-05-18 09:37:54 +00:00
|
|
|
#[derive(Clone, StructOpt)]
|
2020-05-17 11:30:18 +00:00
|
|
|
struct Cli {
|
|
|
|
#[structopt(short = "p", long = "port", default_value = "8001")]
|
|
|
|
ports: Vec<u16>,
|
2020-05-18 09:37:54 +00:00
|
|
|
|
|
|
|
#[structopt(long)]
|
|
|
|
recv_buffer_size: Option<usize>,
|
|
|
|
#[structopt(long)]
|
|
|
|
send_buffer_size: Option<usize>,
|
2020-05-17 11:30:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type UnitAsyncResult = Result<(), std::io::Error>;
|
|
|
|
|
|
|
|
fn other_eio<E: std::fmt::Display>(e: E) -> std::io::Error {
|
|
|
|
std::io::Error::new(std::io::ErrorKind::Other, e.to_string())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn translate_sink_err(e: tungstenite::Error) -> packets::EncodeError {
|
|
|
|
packets::EncodeError::Write(other_eio(e))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn encode_message(codec: &value::Codec<V, Syndicate>, p: packets::S2C) ->
|
|
|
|
Result<Message, packets::EncodeError>
|
|
|
|
{
|
|
|
|
let v: V = value::to_value(p)?;
|
|
|
|
Ok(Message::Binary(codec.encode_bytes(&v)?))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn message_encoder(codec: &value::Codec<V, Syndicate>)
|
|
|
|
-> impl Fn(packets::S2C) -> futures::future::Ready<Result<Message, packets::EncodeError>> + '_
|
|
|
|
{
|
|
|
|
return move |p| futures::future::ready(encode_message(codec, p));
|
|
|
|
}
|
|
|
|
|
2020-05-18 08:44:09 +00:00
|
|
|
fn message_decoder(codec: &value::Codec<V, Syndicate>)
|
|
|
|
-> impl Fn(Result<Message, tungstenite::Error>) -> ResultC2S + '_
|
|
|
|
{
|
2020-05-17 11:30:18 +00:00
|
|
|
return move |r| {
|
|
|
|
loop {
|
|
|
|
return match r {
|
|
|
|
Ok(ref m) => match m {
|
|
|
|
Message::Text(_) => Err(packets::DecodeError::Read(
|
|
|
|
value::decoder::Error::Syntax("Text websocket frames are not accepted"))),
|
|
|
|
Message::Binary(ref bs) => {
|
|
|
|
let v = codec.decode(&mut &bs[..])?;
|
|
|
|
value::from_value(&v).map_err(|e| packets::DecodeError::Parse(e, v))
|
|
|
|
}
|
|
|
|
Message::Ping(_) => continue, // pings are handled by tungstenite before we see them
|
|
|
|
Message::Pong(_) => continue, // unsolicited pongs are to be ignored
|
|
|
|
Message::Close(_) => Err(packets::DecodeError::Read(value::decoder::Error::Eof)),
|
|
|
|
}
|
|
|
|
Err(tungstenite::Error::Io(e)) => Err(e.into()),
|
|
|
|
Err(e) => Err(packets::DecodeError::Read(value::decoder::Error::Io(other_eio(e)))),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
2019-09-19 09:54:01 +00:00
|
|
|
|
2020-05-17 11:30:18 +00:00
|
|
|
async fn run_connection(connid: ConnId,
|
|
|
|
mut stream: TcpStream,
|
|
|
|
spaces: Arc<Mutex<spaces::Spaces>>) ->
|
|
|
|
UnitAsyncResult
|
|
|
|
{
|
|
|
|
let mut buf = [0; 1]; // peek at the first byte to see what kind of connection to expect
|
|
|
|
match stream.peek(&mut buf).await? {
|
|
|
|
1 => match buf[0] {
|
|
|
|
71 /* ASCII 'G' for "GET" */ => {
|
|
|
|
let s = tokio_tungstenite::accept_async(stream).await
|
|
|
|
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
|
|
|
|
let (o, i) = s.split();
|
|
|
|
let codec = packets::standard_preserves_codec();
|
|
|
|
let i = i.map(message_decoder(&codec));
|
|
|
|
let o = o.sink_map_err(translate_sink_err).with(message_encoder(&codec));
|
|
|
|
let mut p = Peer::new(connid, i, o);
|
|
|
|
p.run(spaces).await?
|
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
println!("First byte: {:?}", buf);
|
|
|
|
let (o, i) = Framed::new(stream, packets::Codec::standard()).split();
|
|
|
|
let mut p = Peer::new(connid, i, o);
|
|
|
|
p.run(spaces).await?
|
|
|
|
}
|
|
|
|
}
|
|
|
|
0 => return Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof,
|
|
|
|
"closed before starting")),
|
|
|
|
_ => unreachable!()
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-05-18 09:37:54 +00:00
|
|
|
async fn run_listener(spaces: Arc<Mutex<spaces::Spaces>>, port: u16, args: Cli) -> UnitAsyncResult {
|
2019-10-15 15:58:52 +00:00
|
|
|
let mut listener = TcpListener::bind(format!("0.0.0.0:{}", port)).await?;
|
|
|
|
println!("Listening on port {}", port);
|
2020-05-17 11:30:18 +00:00
|
|
|
let mut id = port as u64 + 100000000000000;
|
2019-09-19 09:54:01 +00:00
|
|
|
loop {
|
|
|
|
let (stream, addr) = listener.accept().await?;
|
|
|
|
let connid = id;
|
2019-10-16 13:16:50 +00:00
|
|
|
let spaces = Arc::clone(&spaces);
|
2020-05-17 11:30:18 +00:00
|
|
|
id += 100000;
|
2020-05-18 09:37:54 +00:00
|
|
|
if let Some(n) = args.recv_buffer_size { stream.set_recv_buffer_size(n)?; }
|
|
|
|
if let Some(n) = args.send_buffer_size { stream.set_send_buffer_size(n)?; }
|
2019-09-19 09:54:01 +00:00
|
|
|
tokio::spawn(async move {
|
2020-05-17 11:30:18 +00:00
|
|
|
println!("Connection {} ({:?}) accepted from port {}", connid, addr, port);
|
2020-05-18 09:37:38 +00:00
|
|
|
match run_connection(connid, stream, spaces).await {
|
2020-05-17 11:30:18 +00:00
|
|
|
Ok(()) => println!("Connection {} ({:?}) terminated normally", connid, addr),
|
|
|
|
Err(e) => println!("Connection {} ({:?}) terminated: {}", connid, addr, e),
|
2019-09-19 09:54:01 +00:00
|
|
|
}
|
|
|
|
});
|
2019-09-17 19:28:31 +00:00
|
|
|
}
|
2018-12-09 13:28:01 +00:00
|
|
|
}
|
2020-05-17 11:30:18 +00:00
|
|
|
|
2020-05-18 08:44:57 +00:00
|
|
|
async fn periodic_tasks(spaces: Arc<Mutex<spaces::Spaces>>) -> UnitAsyncResult {
|
2020-05-18 09:36:44 +00:00
|
|
|
let interval = core::time::Duration::from_secs(5);
|
|
|
|
let mut delay = tokio::time::interval(interval);
|
2020-05-18 08:44:57 +00:00
|
|
|
loop {
|
|
|
|
delay.next().await.unwrap();
|
|
|
|
{
|
|
|
|
let mut spaces = spaces.lock().unwrap();
|
|
|
|
spaces.cleanup();
|
2020-05-18 09:36:44 +00:00
|
|
|
println!("{}", spaces.stats_string(interval));
|
2020-05-18 08:44:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-17 11:30:18 +00:00
|
|
|
#[tokio::main]
|
|
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
|
|
let args = Cli::from_args();
|
|
|
|
|
|
|
|
let spaces = Arc::new(Mutex::new(spaces::Spaces::new()));
|
2020-05-18 08:44:35 +00:00
|
|
|
let mut daemons = Vec::new();
|
2020-05-17 11:30:18 +00:00
|
|
|
|
2020-05-18 08:44:57 +00:00
|
|
|
{
|
|
|
|
let spaces = Arc::clone(&spaces);
|
|
|
|
tokio::spawn(async move {
|
|
|
|
periodic_tasks(spaces).await
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-05-18 09:37:54 +00:00
|
|
|
for port in args.ports.clone() {
|
2020-05-17 11:30:18 +00:00
|
|
|
let spaces = Arc::clone(&spaces);
|
2020-05-18 09:37:54 +00:00
|
|
|
let args = args.clone();
|
2020-05-18 08:44:35 +00:00
|
|
|
daemons.push(tokio::spawn(async move {
|
2020-05-18 09:37:54 +00:00
|
|
|
match run_listener(spaces, port, args).await {
|
2020-05-17 11:30:18 +00:00
|
|
|
Ok(()) => (),
|
|
|
|
Err(e) => {
|
|
|
|
eprintln!("Error from listener for port {}: {}", port, e);
|
|
|
|
std::process::exit(2)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
2020-05-18 08:44:35 +00:00
|
|
|
futures::future::join_all(daemons).await;
|
2020-05-17 11:30:18 +00:00
|
|
|
Ok(())
|
|
|
|
}
|