use super::V; use super::ConnId; use super::dataspace; use super::packets; use super::spaces; use core::time::Duration; use futures::FutureExt; use futures::SinkExt; use futures::select; use preserves::value::{self, Map}; use std::sync::{Mutex, Arc}; use tokio::net::TcpStream; use tokio::stream::StreamExt; use tokio::sync::mpsc::{unbounded_channel, UnboundedSender, UnboundedReceiver}; use tokio::time::interval; use tokio_util::codec::Framed; pub struct Peer { id: ConnId, tx: UnboundedSender, rx: UnboundedReceiver, frames: Framed, space: Option, } fn err(s: &str, ctx: V) -> packets::Out { packets::Out::Err(s.into(), ctx) } impl Peer { pub async fn new(id: ConnId, stream: TcpStream) -> Self { let (tx, rx) = unbounded_channel(); let frames = Framed::new(stream, packets::Codec::new(value::Codec::new({ let mut m = Map::new(); m.insert(0, value::Value::symbol("Discard")); m.insert(1, value::Value::symbol("Capture")); m.insert(2, value::Value::symbol("Observe")); m }))); Peer{ id, tx, rx, frames, space: None } } pub async fn run(&mut self, spaces: Arc>) -> Result<(), std::io::Error> { println!("{:?}: {:?}", self.id, &self.frames.get_ref()); let firstpacket = self.frames.next().await; let dsname = if let Some(Ok(packets::In::Connect(dsname))) = firstpacket { dsname } else { let e: String = format!("Expected initial Connect, got {:?}", firstpacket); println!("{:?}: {}", self.id, e); self.frames.send(err(&e, value::Value::from(false).wrap())).await?; return Ok(()) }; self.space = Some(spaces.lock().unwrap().lookup(&dsname)); self.space.as_ref().unwrap().write().unwrap().register(self.id, self.tx.clone()); let mut ping_timer = interval(Duration::from_secs(60)); let mut running = true; while running { let mut to_send = Vec::new(); select! { _instant = ping_timer.next().boxed().fuse() => to_send.push(packets::Out::Ping()), frame = self.frames.next().boxed().fuse() => match frame { Some(res) => match res { Ok(p) => { println!("{:?}: input {:?}", self.id, &p); match p { packets::In::Turn(actions) => { match self.space.as_ref().unwrap().write().unwrap() .turn(self.id, actions) { Ok(()) => (), Err((msg, ctx)) => { to_send.push(err(&msg, ctx)); running = false; } } } packets::In::Ping() => to_send.push(packets::Out::Pong()), packets::In::Pong() => (), packets::In::Connect(_) => { to_send.push(err("Unexpected Connect", value::to_value(p).unwrap())); running = false; } } } Err(packets::DecodeError::Read(value::decoder::Error::Eof)) => running = false, Err(packets::DecodeError::Read(value::decoder::Error::Io(e))) => return Err(e), Err(packets::DecodeError::Read(value::decoder::Error::Syntax(s))) => { to_send.push(err(s, value::Value::from(false).wrap())); running = false; } Err(packets::DecodeError::Parse(e, v)) => { to_send.push(err(&format!("Packet deserialization error: {}", e), v)); running = false; } } None => running = false, }, msgopt = self.rx.recv().boxed().fuse() => { match msgopt { Some(msg) => to_send.push(msg), None => { /* weird. */ to_send.push(err("Outbound channel closed unexpectedly", value::Value::from(false).wrap())); running = false; } } }, } for v in to_send { if let packets::Out::Err(ref msg, ref ctx) = v { println!("{:?}: connection crashed: {}; context {:?}", self.id, msg, ctx); } else { println!("{:?}: output {:?}", self.id, &v); } self.frames.send(v).await?; } } Ok(()) } } impl Drop for Peer { fn drop(&mut self) { if let Some(ref s) = self.space { s.write().unwrap().deregister(self.id); } } }