feat(plugins): scaffold wasm runtime and wire core hook lifecycle
This commit is contained in:
committed by
Argenis
parent
c3dbd9a7a7
commit
1d6afe792b
@@ -0,0 +1 @@
|
||||
pub mod observer;
|
||||
@@ -0,0 +1,71 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::observability::traits::ObserverMetric;
|
||||
use crate::observability::{Observer, ObserverEvent};
|
||||
|
||||
pub struct ObserverBridge {
|
||||
inner: Arc<dyn Observer>,
|
||||
}
|
||||
|
||||
impl ObserverBridge {
|
||||
pub fn new(inner: Arc<dyn Observer>) -> Self {
|
||||
Self { inner }
|
||||
}
|
||||
}
|
||||
|
||||
impl Observer for ObserverBridge {
|
||||
fn record_event(&self, event: &ObserverEvent) {
|
||||
self.inner.record_event(event);
|
||||
}
|
||||
|
||||
fn record_metric(&self, metric: &ObserverMetric) {
|
||||
self.inner.record_metric(metric);
|
||||
}
|
||||
|
||||
fn flush(&self) {
|
||||
self.inner.flush();
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
"observer-bridge"
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
#[derive(Default)]
|
||||
struct DummyObserver {
|
||||
events: Mutex<u64>,
|
||||
}
|
||||
|
||||
impl Observer for DummyObserver {
|
||||
fn record_event(&self, _event: &ObserverEvent) {
|
||||
*self.events.lock() += 1;
|
||||
}
|
||||
|
||||
fn record_metric(&self, _metric: &ObserverMetric) {}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
"dummy"
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bridge_forwards_events() {
|
||||
let inner: Arc<dyn Observer> = Arc::new(DummyObserver::default());
|
||||
let bridge = ObserverBridge::new(Arc::clone(&inner));
|
||||
bridge.record_event(&ObserverEvent::HeartbeatTick);
|
||||
assert_eq!(bridge.name(), "observer-bridge");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct HotReloadConfig {
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
impl Default for HotReloadConfig {
|
||||
fn default() -> Self {
|
||||
Self { enabled: false }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct HotReloadManager {
|
||||
config: HotReloadConfig,
|
||||
}
|
||||
|
||||
impl HotReloadManager {
|
||||
pub fn new(config: HotReloadConfig) -> Self {
|
||||
Self { config }
|
||||
}
|
||||
|
||||
pub fn enabled(&self) -> bool {
|
||||
self.config.enabled
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn hot_reload_disabled_by_default() {
|
||||
let manager = HotReloadManager::new(HotReloadConfig::default());
|
||||
assert!(!manager.enabled());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use super::manifest::PluginManifest;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct PluginRuntime;
|
||||
|
||||
impl PluginRuntime {
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
|
||||
pub fn load_manifest(&self, manifest: PluginManifest) -> Result<PluginManifest> {
|
||||
if !manifest.is_valid() {
|
||||
anyhow::bail!("invalid plugin manifest")
|
||||
}
|
||||
Ok(manifest)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn runtime_rejects_invalid_manifest() {
|
||||
let runtime = PluginRuntime::new();
|
||||
assert!(runtime.load_manifest(PluginManifest::default()).is_err());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user