Remove quasi-dataspace actor; more precise error handling
This commit is contained in:
parent
9e256376a1
commit
34909828eb
|
@ -5,7 +5,7 @@ authors = ["Tony Garnock-Jones <tonyg@leastfixedpoint.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
preserves = "0.2.0"
|
preserves = "0.2.1"
|
||||||
|
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_bytes = "0.11"
|
serde_bytes = "0.11"
|
||||||
|
|
228
src/main.rs
228
src/main.rs
|
@ -1,4 +1,4 @@
|
||||||
#![recursion_limit="256"]
|
#![recursion_limit="512"]
|
||||||
|
|
||||||
mod bag;
|
mod bag;
|
||||||
mod skeleton;
|
mod skeleton;
|
||||||
|
@ -7,9 +7,10 @@ use bytes::BytesMut;
|
||||||
use preserves::value::{self, Map};
|
use preserves::value::{self, Map};
|
||||||
use tokio::prelude::*;
|
use tokio::prelude::*;
|
||||||
use tokio::net::{TcpListener, TcpStream};
|
use tokio::net::{TcpListener, TcpStream};
|
||||||
use tokio::sync::mpsc::{channel, Sender, Receiver};
|
use tokio::sync::mpsc::{unbounded_channel, UnboundedSender, UnboundedReceiver};
|
||||||
use tokio::codec::{Framed, Encoder, Decoder};
|
use tokio::codec::{Framed, Encoder, Decoder};
|
||||||
use futures::select;
|
use futures::select;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
// use self::skeleton::Index;
|
// use self::skeleton::Index;
|
||||||
|
|
||||||
|
@ -58,25 +59,64 @@ mod packets {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum DataspaceMessage {
|
enum PacketDecodeError {
|
||||||
Join(ConnId, Sender<packets::Out>),
|
Read(value::decoder::Error),
|
||||||
Input(ConnId, packets::In),
|
Parse(value::error::Error),
|
||||||
Leave(ConnId),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ValueCodec {
|
impl From<io::Error> for PacketDecodeError {
|
||||||
codec: value::Codec<V>,
|
fn from(v: io::Error) -> Self {
|
||||||
}
|
PacketDecodeError::Read(v.into())
|
||||||
|
|
||||||
impl ValueCodec {
|
|
||||||
fn new(codec: value::Codec<V>) -> Self {
|
|
||||||
ValueCodec { codec }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decoder for ValueCodec {
|
impl From<value::error::Error> for PacketDecodeError {
|
||||||
type Item = V;
|
fn from(v: value::error::Error) -> Self {
|
||||||
type Error = value::decoder::Error;
|
PacketDecodeError::Parse(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum PacketEncodeError {
|
||||||
|
Write(value::encoder::Error),
|
||||||
|
Unparse(value::error::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<io::Error> for PacketEncodeError {
|
||||||
|
fn from(v: io::Error) -> Self {
|
||||||
|
PacketEncodeError::Write(v.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<value::error::Error> for PacketEncodeError {
|
||||||
|
fn from(v: value::error::Error) -> Self {
|
||||||
|
PacketEncodeError::Unparse(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PacketEncodeError> for io::Error {
|
||||||
|
fn from(v: PacketEncodeError) -> Self {
|
||||||
|
match v {
|
||||||
|
PacketEncodeError::Write(e) => e,
|
||||||
|
PacketEncodeError::Unparse(e) =>
|
||||||
|
Self::new(io::ErrorKind::InvalidData, format!("{:?}", e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PacketCodec {
|
||||||
|
codec: value::Codec<V>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PacketCodec {
|
||||||
|
fn new(codec: value::Codec<V>) -> Self {
|
||||||
|
PacketCodec { codec }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Decoder for PacketCodec {
|
||||||
|
type Item = packets::In;
|
||||||
|
type Error = PacketDecodeError;
|
||||||
fn decode(&mut self, bs: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
|
fn decode(&mut self, bs: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
|
||||||
let mut buf = &bs[..];
|
let mut buf = &bs[..];
|
||||||
let orig_len = buf.len();
|
let orig_len = buf.len();
|
||||||
|
@ -84,68 +124,90 @@ impl Decoder for ValueCodec {
|
||||||
let final_len = buf.len();
|
let final_len = buf.len();
|
||||||
bs.advance(orig_len - final_len);
|
bs.advance(orig_len - final_len);
|
||||||
match res {
|
match res {
|
||||||
Ok(v) => Ok(Some(v)),
|
Ok(v) => Ok(Some(value::from_value(&v)?)),
|
||||||
Err(value::codec::Error::Eof) => Ok(None),
|
Err(value::decoder::Error::Eof) => Ok(None),
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(PacketDecodeError::Read(e)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encoder for ValueCodec {
|
impl Encoder for PacketCodec {
|
||||||
type Item = V;
|
type Item = packets::Out;
|
||||||
type Error = value::encoder::Error;
|
type Error = PacketEncodeError;
|
||||||
fn encode(&mut self, item: Self::Item, bs: &mut BytesMut) -> Result<(), Self::Error> {
|
fn encode(&mut self, item: Self::Item, bs: &mut BytesMut) -> Result<(), Self::Error> {
|
||||||
bs.extend(self.codec.encode_bytes(&item)?);
|
let v: V = value::to_value(&item)?;
|
||||||
|
bs.extend(self.codec.encode_bytes(&v)?);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn err(s: &str) -> packets::Out {
|
||||||
|
packets::Out::Err(s.into())
|
||||||
|
}
|
||||||
|
|
||||||
struct Peer {
|
struct Peer {
|
||||||
id: ConnId,
|
id: ConnId,
|
||||||
rx: Receiver<packets::Out>,
|
tx: UnboundedSender<packets::Out>,
|
||||||
dataspace: Sender<DataspaceMessage>,
|
rx: UnboundedReceiver<packets::Out>,
|
||||||
frames: Framed<TcpStream, ValueCodec>,
|
frames: Framed<TcpStream, PacketCodec>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Peer {
|
impl Peer {
|
||||||
async fn new(id: ConnId, mut dataspace: Sender<DataspaceMessage>, stream: TcpStream) -> Self {
|
async fn new(id: ConnId, stream: TcpStream) -> Self {
|
||||||
let (tx, rx) = channel(1);
|
let (tx, rx) = unbounded_channel();
|
||||||
let frames = Framed::new(stream, ValueCodec::new(value::Codec::new({
|
let frames = Framed::new(stream, PacketCodec::new(value::Codec::new({
|
||||||
let mut m = Map::new();
|
let mut m = Map::new();
|
||||||
m.insert(0, value::Value::symbol("Discard"));
|
m.insert(0, value::Value::symbol("Discard"));
|
||||||
m.insert(1, value::Value::symbol("Capture"));
|
m.insert(1, value::Value::symbol("Capture"));
|
||||||
m.insert(2, value::Value::symbol("Observe"));
|
m.insert(2, value::Value::symbol("Observe"));
|
||||||
m
|
m
|
||||||
})));
|
})));
|
||||||
dataspace.send(DataspaceMessage::Join(id, tx)).await.unwrap();
|
Peer{ id, tx, rx, frames }
|
||||||
Peer{ id, rx, dataspace, frames }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(&mut self) -> Result<(), std::io::Error> {
|
async fn run(&mut self) -> Result<(), io::Error> {
|
||||||
println!("Got {:?} {:?}", self.id, &self.frames.get_ref());
|
println!("Got {:?} {:?}", 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!("{}", e);
|
||||||
|
self.frames.send(err(&e)).await?;
|
||||||
|
return Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("{}: connected to dataspace {:?}", self.id, dsname);
|
||||||
|
|
||||||
let mut running = true;
|
let mut running = true;
|
||||||
while running {
|
while running {
|
||||||
let mut to_send = Vec::new();
|
let mut to_send = Vec::new();
|
||||||
select! {
|
select! {
|
||||||
frame = self.frames.next().boxed().fuse() => match frame {
|
frame = self.frames.next().boxed().fuse() => match frame {
|
||||||
Some(res) => match res {
|
Some(res) => match res {
|
||||||
Ok(v) => {
|
Ok(p) => {
|
||||||
println!("Input {}: {:?}", self.id, &v);
|
println!("Input {}: {:?}", self.id, &p);
|
||||||
match value::from_value(&v) {
|
match p {
|
||||||
Ok(p) => {
|
packets::In::Turn(actions) => (),
|
||||||
let m = DataspaceMessage::Input(self.id, p);
|
packets::In::Ping() => {
|
||||||
self.dataspace.send(m).await.unwrap()
|
to_send.push(packets::Out::Pong())
|
||||||
}
|
}
|
||||||
Err(e) => {
|
packets::In::Pong() => (),
|
||||||
to_send.push(packets::Out::Err(format!("{:?}", e)));
|
packets::In::Connect(dsname) => {
|
||||||
|
to_send.push(err("Unexpected Connect"));
|
||||||
running = false;
|
running = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(value::codec::Error::Eof) => running = false,
|
Err(PacketDecodeError::Read(value::decoder::Error::Eof)) => running = false,
|
||||||
Err(value::codec::Error::Io(e)) => return Err(e),
|
Err(PacketDecodeError::Read(value::decoder::Error::Io(e))) => return Err(e),
|
||||||
Err(value::codec::Error::Syntax(s)) => {
|
Err(PacketDecodeError::Read(value::decoder::Error::Syntax(s))) => {
|
||||||
to_send.push(packets::Out::Err(s.to_string()));
|
to_send.push(err(s));
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
Err(PacketDecodeError::Parse(e)) => {
|
||||||
|
to_send.push(err(&format!("Packet deserialization error: {:?}", e)));
|
||||||
running = false;
|
running = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,7 +216,11 @@ impl Peer {
|
||||||
msgopt = self.rx.recv().boxed().fuse() => {
|
msgopt = self.rx.recv().boxed().fuse() => {
|
||||||
match msgopt {
|
match msgopt {
|
||||||
Some(msg) => to_send.push(msg),
|
Some(msg) => to_send.push(msg),
|
||||||
None => /* weird. */ running = false,
|
None => {
|
||||||
|
/* weird. */
|
||||||
|
to_send.push(err("Outbound channel closed unexpectedly"));
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -164,7 +230,7 @@ impl Peer {
|
||||||
} else {
|
} else {
|
||||||
println!("Output {}: {:?}", self.id, &v);
|
println!("Output {}: {:?}", self.id, &v);
|
||||||
}
|
}
|
||||||
self.frames.send(value::to_value(v).unwrap()).await?;
|
self.frames.send(v).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -173,67 +239,6 @@ impl Peer {
|
||||||
|
|
||||||
impl Drop for Peer {
|
impl Drop for Peer {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let mut dataspace = self.dataspace.clone();
|
|
||||||
let id = self.id;
|
|
||||||
tokio::spawn(async move {
|
|
||||||
let _ = dataspace.send(DataspaceMessage::Leave(id)).await;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Dataspace {
|
|
||||||
rx: Receiver<DataspaceMessage>,
|
|
||||||
peers: Map<ConnId, Sender<packets::Out>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Dataspace {
|
|
||||||
fn new(rx: Receiver<DataspaceMessage>) -> Self {
|
|
||||||
Dataspace { rx, peers: Map::new() }
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn send(&mut self, i: ConnId, s: &mut Sender<packets::Out>, m: &packets::Out)
|
|
||||||
-> bool
|
|
||||||
{
|
|
||||||
match s.send(m.clone()).await {
|
|
||||||
Ok(_) => true,
|
|
||||||
Err(_) => { self.remove(i); false }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn send_to(&mut self, i: ConnId, m: &packets::Out) -> bool {
|
|
||||||
let mut ms = self.peers.get(&i).map(|s| s.clone());
|
|
||||||
match ms {
|
|
||||||
Some(ref mut s) => self.send(i, s, m).await,
|
|
||||||
None => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove(&mut self, i: ConnId) {
|
|
||||||
self.peers.remove(&i);
|
|
||||||
// TODO: cleanup. Previously, this was:
|
|
||||||
// self.pending.push(PeerMessage::Leave(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn run(&mut self) {
|
|
||||||
loop {
|
|
||||||
println!("Dataspace waiting for message ({} connected)", self.peers.len());
|
|
||||||
let msg = self.rx.recv().await.unwrap();
|
|
||||||
println!("Dataspace: {:?}", msg);
|
|
||||||
match msg {
|
|
||||||
DataspaceMessage::Join(i, s) => {
|
|
||||||
self.peers.insert(i, s);
|
|
||||||
}
|
|
||||||
DataspaceMessage::Input(i, p) => {
|
|
||||||
match p {
|
|
||||||
packets::In::Connect(dsname) => (),
|
|
||||||
packets::In::Turn(actions) => (),
|
|
||||||
packets::In::Ping() => { self.send_to(i, &packets::Out::Pong()).await; }
|
|
||||||
packets::In::Pong() => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DataspaceMessage::Leave(i) => self.remove(i),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,12 +246,6 @@ impl Dataspace {
|
||||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
// let i = Index::new();
|
// let i = Index::new();
|
||||||
|
|
||||||
// Unlike std channels, a zero buffer is not supported
|
|
||||||
let (tx, rx) = channel(100); // but ugh a big buffer is needed to avoid deadlocks???
|
|
||||||
tokio::spawn(async {
|
|
||||||
Dataspace::new(rx).run().await;
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut id = 0;
|
let mut id = 0;
|
||||||
|
|
||||||
let port = 8001;
|
let port = 8001;
|
||||||
|
@ -254,11 +253,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
println!("Listening on port {}", port);
|
println!("Listening on port {}", port);
|
||||||
loop {
|
loop {
|
||||||
let (stream, addr) = listener.accept().await?;
|
let (stream, addr) = listener.accept().await?;
|
||||||
let tx = tx.clone();
|
|
||||||
let connid = id;
|
let connid = id;
|
||||||
id = id + 1;
|
id = id + 1;
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
match Peer::new(connid, tx, stream).await.run().await {
|
match Peer::new(connid, stream).await.run().await {
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(e) => println!("Connection {:?} died with {:?}", addr, e),
|
Err(e) => println!("Connection {:?} died with {:?}", addr, e),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue