use std::sync::{Arc, OnceLock};
use account_management_sdk::{IdpPluginClient, IdpPluginSpecV1};
use async_trait::async_trait;
use toolkit::Gear;
use toolkit::client_hub::ClientScope;
use toolkit::context::GearCtx;
use toolkit::gts::PluginV1;
use tracing::{info, warn};
use types_registry_sdk::{RegisterResult, TypesRegistryClient};
use crate::config::StaticIdpPluginConfig;
use crate::domain::Service;
#[toolkit::gear(
name = "static-idp-plugin",
deps = ["types-registry"]
)]
pub struct StaticIdpPlugin {
service: OnceLock<Arc<Service>>,
}
impl Default for StaticIdpPlugin {
fn default() -> Self {
Self {
service: OnceLock::new(),
}
}
}
#[async_trait]
impl Gear for StaticIdpPlugin {
async fn init(&self, ctx: &GearCtx) -> anyhow::Result<()> {
warn!(
"Static IdP plugin is running in echo mode - every provision/deprovision \
succeeds without contacting a real IdP. Do NOT use this plugin in production."
);
let cfg: StaticIdpPluginConfig = ctx.config_or_default()?;
info!(
vendor = %cfg.vendor,
priority = cfg.priority,
"Loaded plugin configuration"
);
let service = Arc::new(Service::new());
let (instance_id, instance_json) = PluginV1::<IdpPluginSpecV1>::build_registration(
"cf.builtin.static_idp.plugin.v1",
cfg.vendor.clone(),
cfg.priority,
)?;
let registry = ctx.client_hub().get::<dyn TypesRegistryClient>()?;
let results = registry.register(vec![instance_json.clone()]).await?;
for result in &results {
if let RegisterResult::Err { error, .. } = result {
if error.is_already_exists() {
let existing =
registry
.get_instance(instance_id.as_ref())
.await
.map_err(|e| {
anyhow::anyhow!("static-idp-plugin: verify existing instance: {e}")
})?;
if existing.object != instance_json {
return Err(anyhow::anyhow!(
"static-idp-plugin: instance `{instance_id}` already registered \
with a different spec",
));
}
} else {
return Err(anyhow::anyhow!(
"static-idp-plugin: registration failed: {error}"
));
}
}
}
self.service
.set(service.clone())
.map_err(|_| anyhow::anyhow!("{} gear already initialized", Self::MODULE_NAME))?;
let api: Arc<dyn IdpPluginClient> = service;
ctx.client_hub()
.register_scoped::<dyn IdpPluginClient>(ClientScope::gts_id(&instance_id), api);
info!(instance_id = %instance_id);
Ok(())
}
}