Skip to main content

folk_ext/
registry.rs

1//! In-process plugin method registry.
2//!
3//! Replaces the old Unix-socket RPC registry. Plugins register handlers
4//! during boot (same API), and PHP code calls them via `folk_call()`.
5
6use std::collections::HashMap;
7use std::sync::Arc;
8
9use anyhow::Result;
10use async_trait::async_trait;
11use bytes::Bytes;
12use folk_api::{RpcHandler, RpcRegistrar};
13use tokio::sync::RwLock;
14use tracing::debug;
15
16/// In-process registry that stores plugin method handlers.
17/// Accessible from PHP via `folk_call()`.
18#[derive(Clone)]
19pub struct InProcessRegistry {
20    handlers: Arc<RwLock<HashMap<String, RpcHandler>>>,
21}
22
23impl InProcessRegistry {
24    pub fn new() -> Arc<Self> {
25        Arc::new(Self {
26            handlers: Arc::new(RwLock::new(HashMap::new())),
27        })
28    }
29
30    /// Call a registered method. Used by the PHP bridge.
31    pub async fn call(&self, method: &str, payload: Bytes) -> Result<Bytes> {
32        let handlers = self.handlers.read().await;
33        let handler = handlers
34            .get(method)
35            .ok_or_else(|| anyhow::anyhow!("method not found: {method}"))?
36            .clone();
37        drop(handlers);
38
39        handler(payload).await
40    }
41
42    /// List registered methods.
43    pub async fn methods(&self) -> Vec<String> {
44        self.handlers.read().await.keys().cloned().collect()
45    }
46}
47
48#[async_trait]
49impl RpcRegistrar for InProcessRegistry {
50    async fn register_raw(&self, name: String, handler: RpcHandler) {
51        debug!(method = %name, "registered plugin method");
52        self.handlers.write().await.insert(name, handler);
53    }
54}