#![warn(missing_docs)]
use std::collections::HashMap;
use std::collections::VecDeque;
use std::ops::Deref;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::RwLock;
use bytes::Bytes;
use rings_core::dht::Did;
use super::Ctx;
use super::Envelope;
use super::Inbound;
use super::Interpret;
use super::MaybeSend;
use super::Protocol;
use super::Reject;
use super::Transition;
use super::Wire;
use crate::error::Error;
use crate::error::Result;
use crate::processor::Processor;
const MAX_FIXPOINT_STEPS: u32 = 1024;
#[cfg(not(feature = "browser"))]
pub(crate) type DynHandler = dyn Handler + Send + Sync;
#[cfg(feature = "browser")]
pub(crate) type DynHandler = dyn Handler;
type HandlerMap = RwLock<HashMap<String, Arc<DynHandler>>>;
#[cfg_attr(feature = "browser", async_trait::async_trait(?Send))]
#[cfg_attr(not(feature = "browser"), async_trait::async_trait)]
pub(crate) trait Handler {
async fn handle(&self, core: &Core, from: Did, payload: Bytes) -> Result<Vec<Inbound>>;
}
#[derive(Clone)]
pub(crate) struct Core {
processor: Arc<Processor>,
handlers: Arc<HandlerMap>,
}
impl Core {
pub fn did(&self) -> Did {
self.processor.did()
}
pub async fn send(&self, to: Did, namespace: &str, payload: Bytes) -> Result<()> {
let envelope = Envelope::new(namespace, payload);
self.processor.send_envelope(to, &envelope).await?;
Ok(())
}
pub async fn inject(&self, namespace: &str, payload: Bytes) -> Result<()> {
self.dispatch(self.did(), Envelope::new(namespace, payload))
.await
}
pub(crate) async fn dispatch(&self, from: Did, envelope: Envelope) -> Result<()> {
let mut queue: VecDeque<Inbound> = VecDeque::new();
queue.push_back(Inbound {
namespace: envelope.namespace,
from,
payload: envelope.payload,
});
let mut budget = MAX_FIXPOINT_STEPS;
while let Some(Inbound {
namespace,
from,
payload,
}) = queue.pop_front()
{
if budget == 0 {
return Err(Error::ExtensionError(format!(
"fixpoint budget ({MAX_FIXPOINT_STEPS}) exhausted; last namespace {namespace:?}"
)));
}
budget -= 1;
match self.handler(namespace.as_str()) {
Some(handler) => queue.extend(handler.handle(self, from, payload).await?),
None => tracing::debug!(
"no protocol registered for namespace {:?}, dropping",
namespace
),
}
}
Ok(())
}
fn handler(&self, namespace: &str) -> Option<Arc<DynHandler>> {
self.handlers.read().ok()?.get(namespace).map(Arc::clone)
}
}
#[derive(Clone)]
pub struct Scope {
core: Core,
namespace: String,
}
impl Scope {
pub(crate) fn new(core: Core, namespace: String) -> Self {
Self { core, namespace }
}
pub fn did(&self) -> Did {
self.core.did()
}
pub fn namespace(&self) -> &str {
self.namespace.as_str()
}
pub async fn send(&self, to: Did, payload: Bytes) -> Result<()> {
self.core.send(to, self.namespace.as_str(), payload).await
}
pub(crate) async fn inject(&self, payload: Bytes) -> Result<()> {
self.core.inject(self.namespace.as_str(), payload).await
}
}
struct Runner<P: Protocol, I> {
protocol: P,
interpret: I,
state: Mutex<P::State>,
}
#[cfg_attr(feature = "browser", async_trait::async_trait(?Send))]
#[cfg_attr(not(feature = "browser"), async_trait::async_trait)]
impl<P, I> Handler for Runner<P, I>
where
P: Protocol + MaybeSend + 'static,
P::State: MaybeSend + 'static,
P::Effect: MaybeSend,
I: Interpret<Effect = P::Effect> + MaybeSend + 'static,
{
async fn handle(&self, core: &Core, from: Did, payload: Bytes) -> Result<Vec<Inbound>> {
let event = match self.protocol.decode(Wire {
from,
me: core.did(),
payload: payload.as_ref(),
}) {
Ok(event) => event,
Err(Reject(why)) => {
tracing::debug!("drop on {}: {why}", self.protocol.namespace());
return Ok(Vec::new());
}
};
let effects = {
let mut guard = self.state.lock().map_err(|_| Error::Lock)?;
let Transition { state, effects } = self.protocol.step(
Ctx {
did: core.did(),
state: guard.deref(),
},
event,
);
*guard = state;
effects
};
let namespace = self.protocol.namespace().to_string();
let scope = Scope::new(core.clone(), namespace.clone());
let mut reinjected = Vec::new();
for effect in effects {
for payload in self.interpret.run(&scope, effect).await? {
reinjected.push(Inbound {
namespace: namespace.clone(),
from: core.did(),
payload,
});
}
}
Ok(reinjected)
}
}
#[derive(Clone)]
pub struct Extensions {
core: Core,
}
impl Extensions {
pub fn new(processor: Arc<Processor>) -> Self {
Self {
core: Core {
processor,
handlers: Arc::new(RwLock::new(HashMap::new())),
},
}
}
pub(crate) fn core(&self) -> Core {
self.core.clone()
}
pub fn register<P, I>(&self, protocol: P, interpret: I) -> Result<()>
where
P: Protocol + MaybeSend + 'static,
P::State: MaybeSend + 'static,
P::Effect: MaybeSend,
I: Interpret<Effect = P::Effect> + MaybeSend + 'static,
{
self.insert(protocol, interpret, false)
}
pub fn replace<P, I>(&self, protocol: P, interpret: I) -> Result<()>
where
P: Protocol + MaybeSend + 'static,
P::State: MaybeSend + 'static,
P::Effect: MaybeSend,
I: Interpret<Effect = P::Effect> + MaybeSend + 'static,
{
self.insert(protocol, interpret, true)
}
pub fn register_many<P, I>(&self, items: Vec<(P, I)>) -> Result<()>
where
P: Protocol + MaybeSend + 'static,
P::State: MaybeSend + 'static,
P::Effect: MaybeSend,
I: Interpret<Effect = P::Effect> + MaybeSend + 'static,
{
let prepared: Vec<(String, Arc<DynHandler>)> = items
.into_iter()
.map(|(protocol, interpret)| {
let namespace = protocol.namespace().to_string();
let state = Mutex::new(protocol.init());
let runner: Arc<DynHandler> = Arc::new(Runner {
protocol,
interpret,
state,
});
(namespace, runner)
})
.collect();
let mut handlers = self.core.handlers.write().map_err(|_| Error::Lock)?;
for (index, (namespace, _)) in prepared.iter().enumerate() {
let duplicate_in_batch = prepared
.iter()
.take(index)
.any(|(seen, _)| seen == namespace);
if duplicate_in_batch || handlers.contains_key(namespace) {
return Err(Error::ExtensionError(format!(
"namespace {namespace:?} is already registered"
)));
}
}
for (namespace, runner) in prepared {
handlers.insert(namespace, runner);
}
Ok(())
}
fn insert<P, I>(&self, protocol: P, interpret: I, replace: bool) -> Result<()>
where
P: Protocol + MaybeSend + 'static,
P::State: MaybeSend + 'static,
P::Effect: MaybeSend,
I: Interpret<Effect = P::Effect> + MaybeSend + 'static,
{
let namespace = protocol.namespace().to_string();
let state = Mutex::new(protocol.init());
let runner: Arc<DynHandler> = Arc::new(Runner {
protocol,
interpret,
state,
});
let mut handlers = self.core.handlers.write().map_err(|_| Error::Lock)?;
if !replace && handlers.contains_key(&namespace) {
return Err(Error::ExtensionError(format!(
"namespace {namespace:?} is already registered"
)));
}
handlers.insert(namespace, runner);
Ok(())
}
pub fn contains(&self, namespace: &str) -> bool {
self.core
.handlers
.read()
.map(|h| h.contains_key(namespace))
.unwrap_or(false)
}
pub(crate) async fn dispatch(&self, from: Did, envelope: Envelope) -> Result<()> {
self.core.dispatch(from, envelope).await
}
}