use std::any::Any;
use crate::state::MutationBatch;
use awaken_runtime_contract::registry_spec::AgentSpec;
use awaken_runtime_contract::{PluginConfigKey, StateError};
use super::{PluginDescriptor, PluginRegistrar};
pub struct ConfigSchema {
pub key: &'static str,
pub json_schema: serde_json::Value,
pub display_name: Option<&'static str>,
pub description: Option<&'static str>,
pub category: Option<&'static str>,
pub editor: Option<&'static str>,
pub default_value: serde_json::Value,
pub ui_schema: serde_json::Value,
}
impl ConfigSchema {
pub fn for_key<K: PluginConfigKey>() -> Self {
Self {
key: K::KEY,
json_schema: serde_json::to_value(schemars::schema_for!(K::Config)).unwrap_or_default(),
display_name: None,
description: None,
category: None,
editor: None,
default_value: serde_json::to_value(K::Config::default()).unwrap_or_default(),
ui_schema: serde_json::Value::Object(Default::default()),
}
}
#[must_use]
pub fn with_display_name(mut self, display_name: &'static str) -> Self {
self.display_name = Some(display_name);
self
}
#[must_use]
pub fn with_description(mut self, description: &'static str) -> Self {
self.description = Some(description);
self
}
#[must_use]
pub fn with_category(mut self, category: &'static str) -> Self {
self.category = Some(category);
self
}
#[must_use]
pub fn with_editor(mut self, editor: &'static str) -> Self {
self.editor = Some(editor);
self
}
#[must_use]
pub fn with_ui_schema(mut self, ui_schema: serde_json::Value) -> Self {
self.ui_schema = ui_schema;
self
}
}
pub trait Plugin: Send + Sync + Any + 'static {
fn descriptor(&self) -> PluginDescriptor;
fn bind_runtime_context(
&self,
_store: &crate::state::StateStore,
_owner_inbox: Option<&crate::inbox::InboxSender>,
) {
}
fn register(&self, _registrar: &mut PluginRegistrar) -> Result<(), StateError> {
Ok(())
}
fn config_schemas(&self) -> Vec<ConfigSchema> {
Vec::new()
}
fn on_activate(
&self,
_agent_spec: &AgentSpec,
_patch: &mut MutationBatch,
) -> Result<(), StateError> {
Ok(())
}
fn on_deactivate(&self, _patch: &mut MutationBatch) -> Result<(), StateError> {
Ok(())
}
}
#[cfg(any(feature = "background", test))]
impl dyn Plugin {
pub(crate) fn as_any(&self) -> &dyn Any {
self
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde::{Deserialize, Serialize};
#[derive(Clone, Default, Serialize, Deserialize, schemars::JsonSchema)]
struct TestConfig {
value: String,
}
struct TestConfigKey;
impl PluginConfigKey for TestConfigKey {
const KEY: &'static str = "test";
type Config = TestConfig;
}
#[test]
fn config_schema_for_key_uses_typed_key_and_config() {
let schema = ConfigSchema::for_key::<TestConfigKey>();
assert_eq!(schema.key, TestConfigKey::KEY);
assert_eq!(schema.json_schema["type"], "object");
assert!(schema.json_schema["properties"].get("value").is_some());
assert_eq!(schema.default_value, serde_json::json!({"value": ""}));
}
}