Skip to main content

static_credstore_plugin/
module.rs

1use std::sync::{Arc, OnceLock};
2
3use async_trait::async_trait;
4use credstore_sdk::{CredStorePluginClientV1, CredStorePluginSpecV1};
5use modkit::Module;
6use modkit::client_hub::ClientScope;
7use modkit::context::ModuleCtx;
8use modkit::gts::BaseModkitPluginV1;
9use tracing::info;
10use types_registry_sdk::{RegisterResult, TypesRegistryClient};
11
12use crate::config::StaticCredStorePluginConfig;
13use crate::domain::Service;
14
15/// Static credstore plugin module.
16///
17/// Serves pre-configured secrets from YAML configuration for development and testing.
18#[modkit::module(
19    name = "static-credstore-plugin",
20    deps = ["types-registry"]
21)]
22pub struct StaticCredStorePlugin {
23    service: OnceLock<Arc<Service>>,
24}
25
26impl Default for StaticCredStorePlugin {
27    fn default() -> Self {
28        Self {
29            service: OnceLock::new(),
30        }
31    }
32}
33
34#[async_trait]
35impl Module for StaticCredStorePlugin {
36    async fn init(&self, ctx: &ModuleCtx) -> anyhow::Result<()> {
37        // Load configuration
38        let cfg: StaticCredStorePluginConfig = ctx.config()?;
39
40        info!(
41            vendor = %cfg.vendor,
42            priority = cfg.priority,
43            secret_count = cfg.secrets.len(),
44            "Loaded plugin configuration"
45        );
46
47        // Generate plugin instance ID
48        let instance_id =
49            CredStorePluginSpecV1::gts_make_instance_id("x.core._.static_credstore.v1");
50
51        // Create service from config (validate early, before registration)
52        let service = Arc::new(Service::from_config(&cfg)?);
53
54        // Register plugin instance in types-registry
55        let registry = ctx.client_hub().get::<dyn TypesRegistryClient>()?;
56        let instance = BaseModkitPluginV1::<CredStorePluginSpecV1> {
57            id: instance_id.clone(),
58            vendor: cfg.vendor.clone(),
59            priority: cfg.priority,
60            properties: CredStorePluginSpecV1,
61        };
62        let instance_json = serde_json::to_value(&instance)?;
63
64        let results = registry.register(vec![instance_json]).await?;
65        RegisterResult::ensure_all_ok(&results)?;
66
67        // All fallible steps done — commit service to shared state
68        self.service
69            .set(service.clone())
70            .map_err(|_| anyhow::anyhow!("{} module already initialized", Self::MODULE_NAME))?;
71
72        // Register scoped client in ClientHub
73        let api: Arc<dyn CredStorePluginClientV1> = service;
74        ctx.client_hub()
75            .register_scoped::<dyn CredStorePluginClientV1>(ClientScope::gts_id(&instance_id), api);
76
77        info!(instance_id = %instance_id);
78        Ok(())
79    }
80}