platform_module/
linked.rs1use crate::binding::{EventHandlerRegistrationContext, ModuleBinding};
4use platform_core::{EventHandler, EventHandlerRegistry};
5use platform_http::ApiOpenApiRouter;
6use platform_runtime::{FunctionRegistry, RuntimeDescriptor};
7use std::sync::Arc;
8
9pub type LinkedHttpRouteMerger = fn(ApiOpenApiRouter) -> ApiOpenApiRouter;
10
11#[derive(Debug, Clone, Copy)]
12pub struct LinkedHttpContribution {
13 pub public_prefixes: &'static [&'static str],
14 pub merge: LinkedHttpRouteMerger,
15}
16
17#[derive(Debug)]
21pub struct LinkedBinding {
22 pub runtime: RuntimeDescriptor,
23 pub event_handlers: Vec<Arc<dyn EventHandler>>,
24 pub http: Option<LinkedHttpContribution>,
25}
26
27impl LinkedBinding {
28 #[must_use]
30 pub fn builder() -> LinkedBindingBuilder {
31 LinkedBindingBuilder {
32 runtime: RuntimeDescriptor::default(),
33 event_handlers: Vec::new(),
34 http: None,
35 }
36 }
37}
38
39impl ModuleBinding for LinkedBinding {
40 fn register_functions(&self, registry: &mut FunctionRegistry) {
41 self.runtime.register_into(registry);
42 }
43
44 fn register_event_handlers(
45 &self,
46 registry: &mut EventHandlerRegistry,
47 _context: &EventHandlerRegistrationContext,
48 ) {
49 registry.register_all(self.event_handlers.clone());
50 }
51}
52
53#[derive(Debug)]
55pub struct LinkedBindingBuilder {
56 runtime: RuntimeDescriptor,
57 event_handlers: Vec<Arc<dyn EventHandler>>,
58 http: Option<LinkedHttpContribution>,
59}
60
61impl LinkedBindingBuilder {
62 #[must_use]
64 pub fn runtime(mut self, runtime: RuntimeDescriptor) -> Self {
65 self.runtime = runtime;
66 self
67 }
68
69 #[must_use]
71 pub fn event_handlers(mut self, handlers: Vec<Arc<dyn EventHandler>>) -> Self {
72 self.event_handlers = handlers;
73 self
74 }
75
76 #[must_use]
78 pub fn http(mut self, contribution: LinkedHttpContribution) -> Self {
79 self.http = Some(contribution);
80 self
81 }
82
83 #[must_use]
85 pub fn build(self) -> LinkedBinding {
86 LinkedBinding {
87 runtime: self.runtime,
88 event_handlers: self.event_handlers,
89 http: self.http,
90 }
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97 use async_trait::async_trait;
98 use platform_core::{ClaimedOutboxEvent, ExecutionContext};
99 use platform_runtime::{FunctionDefinition, FunctionHandler, RetryPolicy};
100 use serde_json::Value;
101
102 #[derive(Debug)]
104 struct NoopHandler;
105
106 #[async_trait]
107 impl FunctionHandler for NoopHandler {
108 async fn call(
109 &self,
110 _ctx: ExecutionContext,
111 _input: Value,
112 ) -> platform_core::AppResult<Value> {
113 Ok(Value::Null)
114 }
115 }
116
117 #[derive(Debug)]
119 struct NoopEventHandler;
120
121 #[async_trait]
122 impl EventHandler for NoopEventHandler {
123 fn event_name(&self) -> &str {
124 "test.event"
125 }
126
127 async fn handle(&self, _event: &ClaimedOutboxEvent) -> platform_core::AppResult<()> {
128 Ok(())
129 }
130 }
131
132 #[test]
133 fn linked_binding_registers_its_functions() {
134 let runtime = RuntimeDescriptor {
135 module: "test",
136 functions: vec![FunctionDefinition {
137 name: "test.noop".to_owned(),
138 version: 1,
139 queue: "test".to_owned(),
140 retry_policy: RetryPolicy::default(),
141 handler: Arc::new(NoopHandler),
142 }],
143 ..RuntimeDescriptor::default()
144 };
145 let binding = LinkedBinding::builder().runtime(runtime).build();
146
147 let mut registry = FunctionRegistry::default();
148 binding.register_functions(&mut registry);
149
150 assert!(registry.get("test.noop").is_some());
151 }
152
153 #[test]
154 fn linked_binding_registers_its_event_handlers() {
155 let binding = LinkedBinding::builder()
156 .event_handlers(vec![Arc::new(NoopEventHandler)])
157 .build();
158
159 let mut registry = EventHandlerRegistry::default();
160 binding.register_event_handlers(&mut registry, &EventHandlerRegistrationContext::empty());
161
162 assert_eq!(registry.handler_count("test.event"), 1);
163 }
164}