Remove NodeConnector from core for now; only messages from shards until refactor

This commit is contained in:
James Wilson
2021-06-16 14:58:17 +01:00
parent 3a527e69c8
commit 9741b0f910
10 changed files with 6 additions and 255 deletions
-11
View File
@@ -6,7 +6,6 @@ use crate::shard::connector::ShardConnector;
use crate::chain::{self, Chain, ChainId, Label}; use crate::chain::{self, Chain, ChainId, Label};
use crate::feed::connector::{Connected, FeedConnector, FeedId}; use crate::feed::connector::{Connected, FeedConnector, FeedId};
use crate::feed::{self, FeedMessageSerializer}; use crate::feed::{self, FeedMessageSerializer};
use crate::node::connector::NodeConnector;
use common::ws::MuteReason; use common::ws::MuteReason;
use common::shard::ShardConnId; use common::shard::ShardConnId;
use common::types::{ConnId, NodeDetails, BlockHash}; use common::types::{ConnId, NodeDetails, BlockHash};
@@ -131,13 +130,6 @@ pub struct AddNode {
} }
pub enum NodeSource { pub enum NodeSource {
Direct {
/// Connection id used by the node connector for multiplexing parachains
conn_id: ConnId,
/// Address of the NodeConnector actor
node_connector: Addr<NodeConnector>,
},
// TODO
Shard { Shard {
/// `ShardConnId` that identifies the node connection within a shard. /// `ShardConnId` that identifies the node connection within a shard.
sid: ShardConnId, sid: ShardConnId,
@@ -202,9 +194,6 @@ pub struct GetHealth;
impl NodeSource { impl NodeSource {
pub fn mute(&self, reason: MuteReason) { pub fn mute(&self, reason: MuteReason) {
match self { match self {
NodeSource::Direct { node_connector, .. } => {
node_connector.do_send(reason);
},
// TODO // TODO
NodeSource::Shard { shard_connector, .. } => { NodeSource::Shard { shard_connector, .. } => {
// shard_connector.do_send(Mute { reason }); // shard_connector.do_send(Mute { reason });
-9
View File
@@ -247,15 +247,6 @@ pub struct LocateNode {
impl NodeSource { impl NodeSource {
pub fn init(self, nid: NodeId, chain: Addr<Chain>) -> bool { pub fn init(self, nid: NodeId, chain: Addr<Chain>) -> bool {
match self { match self {
NodeSource::Direct { conn_id, node_connector } => {
node_connector
.try_send(crate::node::connector::Initialize {
nid,
conn_id,
chain,
})
.is_ok()
},
NodeSource::Shard { sid, shard_connector } => { NodeSource::Shard { sid, shard_connector } => {
shard_connector shard_connector
.try_send(crate::shard::connector::Initialize { .try_send(crate::shard::connector::Initialize {
+2
View File
@@ -78,6 +78,8 @@ impl FeedConnector {
fn handle_cmd(&mut self, cmd: &str, payload: &str, ctx: &mut <Self as Actor>::Context) { fn handle_cmd(&mut self, cmd: &str, payload: &str, ctx: &mut <Self as Actor>::Context) {
match cmd { match cmd {
"subscribe" => { "subscribe" => {
// Hash the chain label the frontend wants to subscribe to.
// If it's already subscribed to the same chain, nothing to do.
match fnv(payload) { match fnv(payload) {
hash if hash == self.chain_label_hash => return, hash if hash == self.chain_label_hash => return,
hash => self.chain_label_hash = hash, hash => self.chain_label_hash = hash,
+3 -1
View File
@@ -104,8 +104,10 @@ async fn feed_route(
stream: web::Payload, stream: web::Payload,
aggregator: web::Data<Addr<Aggregator>>, aggregator: web::Data<Addr<Aggregator>>,
) -> Result<HttpResponse, Error> { ) -> Result<HttpResponse, Error> {
let aggregator = aggregator.get_ref().clone();
ws::start( ws::start(
FeedConnector::new(aggregator.get_ref().clone()), FeedConnector::new(aggregator),
&req, &req,
stream, stream,
) )
-2
View File
@@ -7,8 +7,6 @@ use common::types::{
use common::util::now; use common::util::now;
use common::node::SystemInterval; use common::node::SystemInterval;
pub mod connector;
/// Minimum time between block below broadcasting updates to the browser gets throttled, in ms. /// Minimum time between block below broadcasting updates to the browser gets throttled, in ms.
const THROTTLE_THRESHOLD: u64 = 100; const THROTTLE_THRESHOLD: u64 = 100;
/// Minimum time of intervals for block updates sent to the browser when throttled, in ms. /// Minimum time of intervals for block updates sent to the browser when throttled, in ms.
-229
View File
@@ -1,229 +0,0 @@
use std::collections::BTreeMap;
use std::net::Ipv4Addr;
use std::time::{Duration, Instant};
use crate::aggregator::{AddNode, Aggregator, NodeSource};
use crate::chain::{Chain, RemoveNode, UpdateNode};
use crate::location::LocateRequest;
use crate::node::NodeId;
use actix::prelude::*;
use actix_web_actors::ws::{self, CloseReason};
use bytes::Bytes;
use common::types::ConnId;
use common::ws::{MultipartHandler, WsMessage, MuteReason};
use common::node::{NodeMessage, Payload};
/// How often heartbeat pings are sent
const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(20);
/// How long before lack of client response causes a timeout
const CLIENT_TIMEOUT: Duration = Duration::from_secs(60);
pub struct NodeConnector {
/// Multiplexing connections by id
multiplex: BTreeMap<ConnId, ConnMultiplex>,
/// Client must send ping at least once every 60 seconds (CLIENT_TIMEOUT),
hb: Instant,
/// Aggregator actor address
aggregator: Addr<Aggregator>,
/// IP address of the node this connector is responsible for
ip: Option<Ipv4Addr>,
/// Actix address of location services
locator: Recipient<LocateRequest>,
/// Helper for handling continuation messages
multipart: MultipartHandler,
}
enum ConnMultiplex {
Connected {
/// Id of the node this multiplex connector is responsible for handling
nid: NodeId,
/// Chain address to which this multiplex connector is delegating messages
chain: Addr<Chain>,
},
Waiting {
/// Backlog of messages to be sent once we get a recipient handle to the chain
backlog: Vec<Payload>,
},
}
impl Default for ConnMultiplex {
fn default() -> Self {
ConnMultiplex::Waiting {
backlog: Vec::new(),
}
}
}
impl Actor for NodeConnector {
type Context = ws::WebsocketContext<Self>;
fn started(&mut self, ctx: &mut Self::Context) {
self.heartbeat(ctx);
}
fn stopped(&mut self, _: &mut Self::Context) {
for mx in self.multiplex.values() {
if let ConnMultiplex::Connected { chain, nid } = mx {
chain.do_send(RemoveNode(*nid));
}
}
}
}
impl NodeConnector {
pub fn new(
aggregator: Addr<Aggregator>,
locator: Recipient<LocateRequest>,
ip: Option<Ipv4Addr>,
) -> Self {
Self {
multiplex: BTreeMap::new(),
hb: Instant::now(),
aggregator,
ip,
locator,
multipart: MultipartHandler::default(),
}
}
fn heartbeat(&self, ctx: &mut <Self as Actor>::Context) {
ctx.run_interval(HEARTBEAT_INTERVAL, |act, ctx| {
// check client heartbeats
if Instant::now().duration_since(act.hb) > CLIENT_TIMEOUT {
// stop actor
ctx.close(Some(CloseReason {
code: ws::CloseCode::Abnormal,
description: Some("Missed heartbeat".into()),
}));
ctx.stop();
}
});
}
fn handle_message(
&mut self,
msg: NodeMessage,
ctx: &mut <Self as Actor>::Context,
) {
let conn_id = msg.id();
let payload = msg.into();
match self.multiplex.entry(conn_id).or_default() {
ConnMultiplex::Connected { nid, chain } => {
chain.do_send(UpdateNode {
nid: *nid,
payload,
});
}
ConnMultiplex::Waiting { backlog } => {
if let Payload::SystemConnected(connected) = payload {
self.aggregator.do_send(AddNode {
node: connected.node,
genesis_hash: connected.genesis_hash,
source: NodeSource::Direct {
conn_id,
node_connector: ctx.address(),
},
});
} else {
if backlog.len() >= 10 {
backlog.remove(0);
}
backlog.push(payload);
}
}
}
}
}
impl Handler<MuteReason> for NodeConnector {
type Result = ();
fn handle(&mut self, msg: MuteReason, ctx: &mut Self::Context) {
log::debug!(target: "NodeConnector::Mute", "Muting a node. Reason: {:?}", msg);
ctx.close(Some(msg.into()));
ctx.stop();
}
}
#[derive(Message)]
#[rtype(result = "()")]
pub struct Initialize {
pub nid: NodeId,
pub conn_id: ConnId,
pub chain: Addr<Chain>,
}
impl Handler<Initialize> for NodeConnector {
type Result = ();
fn handle(&mut self, msg: Initialize, _: &mut Self::Context) {
let Initialize {
nid,
conn_id,
chain,
} = msg;
log::trace!(target: "NodeConnector::Initialize", "Initializing a node, nid={}, on conn_id={}", nid, conn_id);
let mx = self.multiplex.entry(conn_id).or_default();
if let ConnMultiplex::Waiting { backlog } = mx {
for payload in backlog.drain(..) {
chain.do_send(UpdateNode {
nid,
payload,
});
}
*mx = ConnMultiplex::Connected {
nid,
chain: chain.clone(),
};
};
// Acquire the node's physical location
if let Some(ip) = self.ip {
let _ = self.locator.do_send(LocateRequest { ip, nid, chain });
}
}
}
impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for NodeConnector {
fn handle(&mut self, msg: Result<ws::Message, ws::ProtocolError>, ctx: &mut Self::Context) {
self.hb = Instant::now();
let data = match msg.map(|msg| self.multipart.handle(msg)) {
Ok(WsMessage::Nop) => return,
Ok(WsMessage::Ping(msg)) => {
ctx.pong(&msg);
return;
}
Ok(WsMessage::Data(data)) => data,
Ok(WsMessage::Close(reason)) => {
ctx.close(reason);
ctx.stop();
return;
}
Err(error) => {
log::error!("{:?}", error);
ctx.stop();
return;
}
};
match serde_json::from_slice(&data) {
Ok(msg) => self.handle_message(msg, ctx),
#[cfg(debug)]
Err(err) => {
let data: &[u8] = data.get(..512).unwrap_or_else(|| &data);
log::warn!(
"Failed to parse node message: {} {}",
err,
std::str::from_utf8(data).unwrap_or_else(|_| "INVALID UTF8")
)
}
#[cfg(not(debug))]
Err(_) => (),
}
}
}
-1
View File
@@ -1 +0,0 @@
pub mod connector;
+1
View File
@@ -0,0 +1 @@
pub mod connector;
-2
View File
@@ -100,8 +100,6 @@ impl Chain {
payload, payload,
}; };
println!("Serialize {:?}", msg);
let bytes = bincode::options().serialize(&msg).unwrap(); let bytes = bincode::options().serialize(&msg).unwrap();
println!("Sending update: {} bytes", bytes.len()); println!("Sending update: {} bytes", bytes.len());