use bus::Bus; use parking_lot::Mutex; use serde_derive::{Deserialize, Serialize}; use slog::{error, Logger}; use std::marker::PhantomData; use std::sync::Arc; use types::{Attestation, Epoch, EthSpec, Hash256, SignedBeaconBlock, SignedBeaconBlockHash}; pub use websocket_server::WebSocketSender; pub trait EventHandler: Sized + Send + Sync { fn register(&self, kind: EventKind) -> Result<(), String>; } pub struct NullEventHandler(PhantomData); impl EventHandler for WebSocketSender { fn register(&self, kind: EventKind) -> Result<(), String> { self.send_string( serde_json::to_string(&kind) .map_err(|e| format!("Unable to serialize event: {:?}", e))?, ) } } pub struct ServerSentEvents { // Bus<> is itself Sync + Send. We use Mutex<> here only because of the surrounding code does // not enforce mutability statically (i.e. relies on interior mutability). head_changed_queue: Arc>>, log: Logger, _phantom: PhantomData, } impl ServerSentEvents { pub fn new(log: Logger) -> (Self, Arc>>) { let bus = Bus::new(T::slots_per_epoch() as usize); let mutex = Mutex::new(bus); let arc = Arc::new(mutex); let this = Self { head_changed_queue: arc.clone(), log, _phantom: PhantomData, }; (this, arc) } } impl EventHandler for ServerSentEvents { fn register(&self, kind: EventKind) -> Result<(), String> { match kind { EventKind::BeaconHeadChanged { current_head_beacon_block_root, .. } => { let mut guard = self.head_changed_queue.lock(); if guard .try_broadcast(current_head_beacon_block_root.into()) .is_err() { error!( self.log, "Head change streaming queue full"; "dropped_change" => format!("{}", current_head_beacon_block_root), ); } Ok(()) } _ => Ok(()), } } } // An event handler that pushes events to both the websockets handler and the SSE handler. // Named after the unix `tee` command. Meant as a temporary solution before ditching WebSockets // completely once SSE functions well enough. pub struct TeeEventHandler { websockets_handler: WebSocketSender, sse_handler: ServerSentEvents, } impl TeeEventHandler { #[allow(clippy::type_complexity)] pub fn new( log: Logger, websockets_handler: WebSocketSender, ) -> Result<(Self, Arc>>), String> { let (sse_handler, bus) = ServerSentEvents::new(log); let result = Self { websockets_handler, sse_handler, }; Ok((result, bus)) } } impl EventHandler for TeeEventHandler { fn register(&self, kind: EventKind) -> Result<(), String> { self.websockets_handler.register(kind.clone())?; self.sse_handler.register(kind)?; Ok(()) } } impl EventHandler for NullEventHandler { fn register(&self, _kind: EventKind) -> Result<(), String> { Ok(()) } } impl Default for NullEventHandler { fn default() -> Self { NullEventHandler(PhantomData) } } #[derive(Debug, Serialize, Deserialize, Clone)] #[serde( bound = "T: EthSpec", rename_all = "snake_case", tag = "event", content = "data" )] pub enum EventKind { BeaconHeadChanged { reorg: bool, current_head_beacon_block_root: Hash256, previous_head_beacon_block_root: Hash256, }, BeaconFinalization { epoch: Epoch, root: Hash256, }, BeaconBlockImported { block_root: Hash256, block: Box>, }, BeaconBlockRejected { reason: String, block: Box>, }, BeaconAttestationImported { attestation: Box>, }, BeaconAttestationRejected { reason: String, attestation: Box>, }, }