use std::sync::Mutex;
use khive_runtime::{KhiveRuntime, NamespaceToken, RuntimeError};
use khive_types::{HandlerDef, Pack};
use khive_brain_core::BrainState;
use crate::handlers::BRAIN_HANDLERS;
use crate::persist;
pub const ENTITY_CACHE_CAPACITY: usize = 10_000;
#[cfg(test)]
pub(crate) struct DispatchHook {
pub reached_tx: tokio::sync::oneshot::Sender<()>,
pub proceed_rx: tokio::sync::oneshot::Receiver<()>,
}
#[cfg(test)]
pub(crate) static DISPATCH_INTERLEAVE_HOOK: std::sync::Mutex<Option<DispatchHook>> =
std::sync::Mutex::new(None);
#[cfg(test)]
pub(crate) fn set_dispatch_interleave_hook(hook: DispatchHook) {
*DISPATCH_INTERLEAVE_HOOK.lock().unwrap() = Some(hook);
}
#[cfg(test)]
pub(crate) fn clear_dispatch_interleave_hook() {
*DISPATCH_INTERLEAVE_HOOK.lock().unwrap() = None;
}
pub(crate) fn sync_balanced_recall_record(state: &mut BrainState) {
let total_ev = state.balanced_recall.total_events;
let snap_val = serde_json::to_value(state.balanced_recall.to_snapshot()).ok();
if let Some(record) = state.profiles.get_mut("balanced-recall-v1") {
record.total_events = total_ev;
record.state_snapshot = snap_val;
}
}
pub struct BrainPack {
pub(crate) runtime: KhiveRuntime,
pub(crate) state: Mutex<BrainState>,
pub(crate) persistence: Mutex<persist::PersistenceTracker>,
pub(crate) dispatch_gate: tokio::sync::Mutex<()>,
}
impl Pack for BrainPack {
const NAME: &'static str = "brain";
const NOTE_KINDS: &'static [&'static str] = &[];
const ENTITY_KINDS: &'static [&'static str] = &[];
const HANDLERS: &'static [HandlerDef] = BRAIN_HANDLERS;
const REQUIRES: &'static [&'static str] = &["kg"];
}
impl BrainPack {
pub fn new(runtime: KhiveRuntime) -> Self {
let state = BrainState::new(ENTITY_CACHE_CAPACITY);
Self {
runtime,
state: Mutex::new(state),
persistence: Mutex::new(persist::PersistenceTracker::new()),
dispatch_gate: tokio::sync::Mutex::new(()),
}
}
#[cfg(test)]
pub fn activate_namespace_for_test(&self, namespace: &str) {
self.persistence
.lock()
.unwrap()
.mark_loaded(namespace.into());
}
pub(crate) async fn ensure_loaded(&self, token: &NamespaceToken) -> Result<(), RuntimeError> {
persist::ensure_loaded(
&self.runtime,
token,
&self.persistence,
&self.state,
ENTITY_CACHE_CAPACITY,
)
.await
}
pub fn snapshot(&self) -> khive_brain_core::BrainStateSnapshot {
self.state.lock().unwrap().to_snapshot()
}
#[cfg(test)]
pub fn cold_namespace_total_events(&self, namespace: &str) -> Option<u64> {
self.persistence.lock().unwrap().total_events_for(namespace)
}
}
struct BrainPackFactory;
impl khive_runtime::PackFactory for BrainPackFactory {
fn name(&self) -> &'static str {
"brain"
}
fn requires(&self) -> &'static [&'static str] {
&["kg"]
}
fn create(&self, runtime: KhiveRuntime) -> Box<dyn khive_runtime::pack::PackRuntime> {
Box::new(BrainPack::new(runtime))
}
fn create_install(&self, runtime: KhiveRuntime) -> khive_runtime::PackInstall {
let brain = std::sync::Arc::new(BrainPack::new(runtime));
khive_runtime::PackInstall {
runtime: Box::new(BrainPackRuntime(std::sync::Arc::clone(&brain))),
resolver: None,
dispatch_hook: Some(brain),
}
}
}
struct BrainPackRuntime(std::sync::Arc<BrainPack>);
#[async_trait::async_trait]
impl khive_runtime::pack::PackRuntime for BrainPackRuntime {
fn name(&self) -> &str {
self.0.name()
}
fn note_kinds(&self) -> &'static [&'static str] {
self.0.note_kinds()
}
fn entity_kinds(&self) -> &'static [&'static str] {
self.0.entity_kinds()
}
fn handlers(&self) -> &'static [khive_runtime::HandlerDef] {
self.0.handlers()
}
fn edge_rules(&self) -> &'static [khive_types::EdgeEndpointRule] {
self.0.edge_rules()
}
fn requires(&self) -> &'static [&'static str] {
self.0.requires()
}
fn note_kind_specs(&self) -> &'static [khive_runtime::NoteKindSpec] {
self.0.note_kind_specs()
}
fn kind_hook(&self, kind: &str) -> Option<std::sync::Arc<dyn khive_runtime::KindHook>> {
self.0.kind_hook(kind)
}
fn schema_plan(&self) -> khive_runtime::SchemaPlan {
self.0.schema_plan()
}
fn validation_rules(&self) -> &'static [khive_runtime::ValidationRule] {
self.0.validation_rules()
}
fn register_embedders(&self, runtime: &KhiveRuntime) {
self.0.register_embedders(runtime)
}
fn register_entity_type_validator_with_types(
&self,
runtime: &KhiveRuntime,
pack_entity_types: &[khive_types::EntityTypeDef],
) {
self.0
.register_entity_type_validator_with_types(runtime, pack_entity_types)
}
async fn warm(&self) {
self.0.warm().await
}
async fn dispatch(
&self,
verb: &str,
params: serde_json::Value,
registry: &khive_runtime::VerbRegistry,
token: &NamespaceToken,
) -> Result<serde_json::Value, RuntimeError> {
self.0.dispatch(verb, params, registry, token).await
}
}
inventory::submit! { khive_runtime::PackRegistration(&BrainPackFactory) }