2019-10-24 19:05:39 +00:00
|
|
|
use super::V;
|
2019-10-20 15:01:27 +00:00
|
|
|
use super::ConnId;
|
|
|
|
use super::dataspace;
|
2019-10-16 15:54:58 +00:00
|
|
|
use super::packets;
|
2019-10-20 15:01:27 +00:00
|
|
|
use super::spaces;
|
2020-05-18 11:16:14 +00:00
|
|
|
use super::config;
|
2019-10-16 15:54:58 +00:00
|
|
|
|
|
|
|
use core::time::Duration;
|
2020-05-17 11:30:18 +00:00
|
|
|
use futures::{Sink, SinkExt, Stream};
|
2020-05-06 15:14:05 +00:00
|
|
|
use futures::FutureExt;
|
2019-10-16 15:54:58 +00:00
|
|
|
use futures::select;
|
2020-05-11 20:02:43 +00:00
|
|
|
use preserves::value;
|
2020-05-17 11:30:18 +00:00
|
|
|
use std::pin::Pin;
|
2020-05-18 11:16:14 +00:00
|
|
|
use std::sync::{Mutex, Arc, atomic::{AtomicUsize, Ordering}};
|
2020-05-06 15:14:05 +00:00
|
|
|
use tokio::stream::StreamExt;
|
2020-05-18 11:16:14 +00:00
|
|
|
use tokio::sync::mpsc::{unbounded_channel, UnboundedSender, UnboundedReceiver, error::TryRecvError};
|
2020-05-06 15:14:05 +00:00
|
|
|
use tokio::time::interval;
|
2019-10-16 15:54:58 +00:00
|
|
|
|
2020-05-17 11:30:18 +00:00
|
|
|
pub type ResultC2S = Result<packets::C2S, packets::DecodeError>;
|
|
|
|
|
|
|
|
pub struct Peer<I, O>
|
|
|
|
where I: Stream<Item = ResultC2S> + Send,
|
2020-05-25 14:13:11 +00:00
|
|
|
O: Sink<packets::S2C, Error = std::io::Error>,
|
2020-05-17 11:30:18 +00:00
|
|
|
{
|
2019-10-16 15:54:58 +00:00
|
|
|
id: ConnId,
|
2020-05-11 20:08:27 +00:00
|
|
|
tx: UnboundedSender<packets::S2C>,
|
|
|
|
rx: UnboundedReceiver<packets::S2C>,
|
2020-05-17 11:30:18 +00:00
|
|
|
i: Pin<Box<I>>,
|
|
|
|
o: Pin<Box<O>>,
|
2019-10-20 15:01:27 +00:00
|
|
|
space: Option<dataspace::DataspaceRef>,
|
2019-10-16 15:54:58 +00:00
|
|
|
}
|
|
|
|
|
2020-05-11 20:08:27 +00:00
|
|
|
fn err(s: &str, ctx: V) -> packets::S2C {
|
|
|
|
packets::S2C::Err(s.into(), ctx)
|
2019-10-16 15:54:58 +00:00
|
|
|
}
|
|
|
|
|
2020-05-17 11:30:18 +00:00
|
|
|
impl<I, O> Peer<I, O>
|
|
|
|
where I: Stream<Item = ResultC2S> + Send,
|
2020-05-25 14:13:11 +00:00
|
|
|
O: Sink<packets::S2C, Error = std::io::Error>,
|
2020-05-17 11:30:18 +00:00
|
|
|
{
|
|
|
|
pub fn new(id: ConnId, i: I, o: O) -> Self {
|
2019-10-16 15:54:58 +00:00
|
|
|
let (tx, rx) = unbounded_channel();
|
2020-05-17 11:30:18 +00:00
|
|
|
Peer{ id, tx, rx, i: Box::pin(i), o: Box::pin(o), space: None }
|
2019-10-16 15:54:58 +00:00
|
|
|
}
|
|
|
|
|
2020-05-18 11:16:14 +00:00
|
|
|
pub async fn run(&mut self, spaces: Arc<Mutex<spaces::Spaces>>, config: &config::ServerConfig) ->
|
|
|
|
Result<(), std::io::Error>
|
|
|
|
{
|
2020-05-17 11:30:18 +00:00
|
|
|
let firstpacket = self.i.next().await;
|
2020-05-11 20:08:27 +00:00
|
|
|
let dsname = if let Some(Ok(packets::C2S::Connect(dsname))) = firstpacket {
|
2019-10-16 15:54:58 +00:00
|
|
|
dsname
|
|
|
|
} else {
|
2020-05-17 11:30:18 +00:00
|
|
|
let e = format!("Expected initial Connect, got {:?}", firstpacket);
|
|
|
|
self.o.send(err(&e, value::Value::from(false).wrap())).await?;
|
|
|
|
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, e))
|
2019-10-16 15:54:58 +00:00
|
|
|
};
|
|
|
|
|
2019-10-20 15:01:27 +00:00
|
|
|
self.space = Some(spaces.lock().unwrap().lookup(&dsname));
|
2020-05-18 11:16:14 +00:00
|
|
|
let queue_depth = Arc::new(AtomicUsize::new(0));
|
|
|
|
self.space.as_ref().unwrap().write().unwrap().register(
|
|
|
|
self.id,
|
|
|
|
self.tx.clone(),
|
|
|
|
Arc::clone(&queue_depth));
|
2019-10-16 15:54:58 +00:00
|
|
|
|
2020-05-06 15:14:05 +00:00
|
|
|
let mut ping_timer = interval(Duration::from_secs(60));
|
2019-10-16 15:54:58 +00:00
|
|
|
|
|
|
|
let mut running = true;
|
2020-05-18 11:16:14 +00:00
|
|
|
let mut overloaded = None;
|
|
|
|
let mut previous_sample = None;
|
2019-10-16 15:54:58 +00:00
|
|
|
while running {
|
|
|
|
let mut to_send = Vec::new();
|
2020-05-18 11:16:14 +00:00
|
|
|
|
|
|
|
let queue_depth_sample = queue_depth.load(Ordering::Relaxed);
|
|
|
|
if queue_depth_sample > config.overload_threshold {
|
|
|
|
let n = overloaded.unwrap_or(0);
|
2020-05-18 12:33:36 +00:00
|
|
|
tracing::warn!(turns=n, queue_depth=queue_depth_sample, "overloaded");
|
2020-05-18 11:16:14 +00:00
|
|
|
if n == config.overload_turn_limit {
|
|
|
|
to_send.push(err("Overloaded",
|
|
|
|
value::Value::from(queue_depth_sample as u64).wrap()));
|
|
|
|
running = false;
|
|
|
|
} else {
|
|
|
|
if queue_depth_sample > previous_sample.unwrap_or(0) {
|
|
|
|
overloaded = Some(n + 1)
|
|
|
|
} else {
|
|
|
|
overloaded = Some(0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if let Some(_) = overloaded {
|
2020-05-18 12:33:36 +00:00
|
|
|
tracing::info!(queue_depth=queue_depth_sample, "recovered");
|
2020-05-18 11:16:14 +00:00
|
|
|
}
|
|
|
|
overloaded = None;
|
|
|
|
}
|
|
|
|
previous_sample = Some(queue_depth_sample);
|
|
|
|
|
2019-10-16 15:54:58 +00:00
|
|
|
select! {
|
2020-05-11 20:08:27 +00:00
|
|
|
_instant = ping_timer.next().boxed().fuse() => to_send.push(packets::S2C::Ping()),
|
2020-05-17 11:30:18 +00:00
|
|
|
frame = self.i.next().fuse() => match frame {
|
2019-10-16 15:54:58 +00:00
|
|
|
Some(res) => match res {
|
|
|
|
Ok(p) => {
|
2020-05-18 12:33:36 +00:00
|
|
|
tracing::trace!(packet = debug(&p), "input");
|
2019-10-16 15:54:58 +00:00
|
|
|
match p {
|
2020-05-11 20:08:27 +00:00
|
|
|
packets::C2S::Turn(actions) => {
|
2019-10-24 19:05:39 +00:00
|
|
|
match self.space.as_ref().unwrap().write().unwrap()
|
|
|
|
.turn(self.id, actions)
|
|
|
|
{
|
|
|
|
Ok(()) => (),
|
|
|
|
Err((msg, ctx)) => {
|
|
|
|
to_send.push(err(&msg, ctx));
|
|
|
|
running = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-05-11 20:08:27 +00:00
|
|
|
packets::C2S::Ping() =>
|
|
|
|
to_send.push(packets::S2C::Pong()),
|
|
|
|
packets::C2S::Pong() =>
|
2019-10-20 15:01:27 +00:00
|
|
|
(),
|
2020-05-11 20:08:27 +00:00
|
|
|
packets::C2S::Connect(_) => {
|
2020-05-25 14:13:11 +00:00
|
|
|
to_send.push(err("Unexpected Connect", value::to_value(p)));
|
2019-10-16 15:54:58 +00:00
|
|
|
running = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-05-25 13:04:50 +00:00
|
|
|
Err(packets::DecodeError::Read(e)) => {
|
|
|
|
if value::is_eof_error(&e) {
|
|
|
|
tracing::trace!("eof");
|
|
|
|
running = false;
|
|
|
|
} else if value::is_syntax_error(&e) {
|
|
|
|
to_send.push(err(&e.to_string(), value::Value::from(false).wrap()));
|
|
|
|
running = false;
|
|
|
|
} else {
|
|
|
|
return Err(e)
|
|
|
|
}
|
2019-10-16 15:54:58 +00:00
|
|
|
}
|
2019-10-17 14:41:42 +00:00
|
|
|
Err(packets::DecodeError::Parse(e, v)) => {
|
2019-10-24 19:05:39 +00:00
|
|
|
to_send.push(err(&format!("Packet deserialization error: {}", e), v));
|
2019-10-16 15:54:58 +00:00
|
|
|
running = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => running = false,
|
|
|
|
},
|
|
|
|
msgopt = self.rx.recv().boxed().fuse() => {
|
2020-05-18 11:16:14 +00:00
|
|
|
let mut ok = true;
|
2019-10-16 15:54:58 +00:00
|
|
|
match msgopt {
|
2020-05-18 11:16:14 +00:00
|
|
|
Some(msg) => {
|
|
|
|
to_send.push(msg);
|
|
|
|
loop {
|
|
|
|
match self.rx.try_recv() {
|
|
|
|
Ok(m) => to_send.push(m),
|
|
|
|
Err(TryRecvError::Empty) => {
|
|
|
|
queue_depth.store(0, Ordering::Relaxed);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Err(TryRecvError::Closed) => {
|
|
|
|
ok = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-10-16 15:54:58 +00:00
|
|
|
}
|
2020-05-18 11:16:14 +00:00
|
|
|
None => ok = false,
|
|
|
|
}
|
|
|
|
if !ok {
|
|
|
|
/* weird. */
|
|
|
|
to_send.push(err("Outbound channel closed unexpectedly",
|
|
|
|
value::Value::from(false).wrap()));
|
|
|
|
running = false;
|
2019-10-16 15:54:58 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for v in to_send {
|
2020-05-11 20:08:27 +00:00
|
|
|
if let packets::S2C::Err(ref msg, ref ctx) = v {
|
2020-05-18 12:33:36 +00:00
|
|
|
tracing::error!(context = debug(ctx), msg = display(msg), "error");
|
2019-10-16 15:54:58 +00:00
|
|
|
} else {
|
2020-05-18 12:33:36 +00:00
|
|
|
tracing::trace!(packet = debug(&v), "output");
|
2019-10-16 15:54:58 +00:00
|
|
|
}
|
2020-05-17 11:30:18 +00:00
|
|
|
self.o.send(v).await?;
|
2019-10-16 15:54:58 +00:00
|
|
|
}
|
2020-05-11 21:31:00 +00:00
|
|
|
tokio::task::yield_now().await;
|
2019-10-16 15:54:58 +00:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-17 11:30:18 +00:00
|
|
|
impl<I, O> Drop for Peer<I, O>
|
|
|
|
where I: Stream<Item = ResultC2S> + Send,
|
2020-05-25 14:13:11 +00:00
|
|
|
O: Sink<packets::S2C, Error = std::io::Error>,
|
2020-05-17 11:30:18 +00:00
|
|
|
{
|
2019-10-16 15:54:58 +00:00
|
|
|
fn drop(&mut self) {
|
2019-10-20 15:01:27 +00:00
|
|
|
if let Some(ref s) = self.space {
|
|
|
|
s.write().unwrap().deregister(self.id);
|
|
|
|
}
|
2019-10-16 15:54:58 +00:00
|
|
|
}
|
|
|
|
}
|