1use super::*;
2
3impl WasmHost {
4 pub fn prepare_page_invocation(
5 &self,
6 execution: &RequestExecution,
7 ) -> Result<Option<InvocationPlan>, WasmModelError> {
8 let method = http_method_to_wasm(execution.method);
9 let input = InvocationInput::Page(PageInvocation::new(
10 invocation_surface_path(execution),
11 method,
12 )?);
13 let context = self.request_context(execution, input)?;
14 self.registry.prepare_page_invocation(
15 invocation_surface_path(execution).as_str(),
16 method,
17 context,
18 )
19 }
20
21 pub fn begin_page_invocation(
22 &self,
23 execution: &RequestExecution,
24 ) -> Result<Option<WasmExecutionSession>, WasmModelError> {
25 Ok(self
26 .prepare_page_invocation(execution)?
27 .map(|plan| plan.begin_execution_with_executor(self.host_service_executor.clone())))
28 }
29
30 pub fn prepare_api_invocation(
31 &self,
32 execution: &RequestExecution,
33 ) -> Result<Option<InvocationPlan>, WasmModelError> {
34 let method = http_method_to_wasm(execution.method);
35 let input = InvocationInput::Api(ApiInvocation::new(
36 invocation_surface_path(execution),
37 method,
38 )?);
39 let context = self.request_context(execution, input)?;
40 self.registry.prepare_api_invocation(
41 invocation_surface_path(execution).as_str(),
42 method,
43 context,
44 )
45 }
46
47 pub fn begin_api_invocation(
48 &self,
49 execution: &RequestExecution,
50 ) -> Result<Option<WasmExecutionSession>, WasmModelError> {
51 Ok(self
52 .prepare_api_invocation(execution)?
53 .map(|plan| plan.begin_execution_with_executor(self.host_service_executor.clone())))
54 }
55
56 pub fn prepare_leased_job_invocation(
57 &self,
58 lease: &JobLease,
59 ) -> Result<Option<InvocationPlan>, WasmModelError> {
60 let trace_id = format!("job:{}", lease.record.spec.job_id.as_str());
61 let principal = ExtensionPrincipal::service_account("runtime.jobs");
62 let attempts = lease.record.attempts.saturating_add(1);
63 let job_name = lease.record.spec.job_name.as_str();
64
65 if let Some(declared_job) = job_name.strip_prefix("event-handler:") {
66 return self.prepare_job_invocation(declared_job, attempts, trace_id, principal);
67 }
68
69 match self
70 .registered_jobs
71 .iter()
72 .find(|definition| definition.contract.name == job_name)
73 .map(|definition| definition.contract.trigger)
74 {
75 Some(JobTriggerKind::Scheduled) => {
76 self.prepare_scheduled_job_invocation(job_name, trace_id, principal)
77 }
78 _ => self.prepare_job_invocation(job_name, attempts, trace_id, principal),
79 }
80 }
81
82 pub fn begin_leased_job_invocation(
83 &self,
84 lease: &JobLease,
85 ) -> Result<Option<WasmExecutionSession>, WasmModelError> {
86 Ok(self
87 .prepare_leased_job_invocation(lease)?
88 .map(|plan| plan.begin_execution_with_executor(self.host_service_executor.clone())))
89 }
90
91 pub fn prepare_job_invocation(
92 &self,
93 job_name: &str,
94 attempt: u32,
95 trace_id: impl Into<String>,
96 principal: ExtensionPrincipal,
97 ) -> Result<Option<InvocationPlan>, WasmModelError> {
98 let input = InvocationInput::Job(JobInvocation::new(job_name.to_string(), attempt)?);
99 let context = self.async_context(trace_id.into(), principal, input)?;
100 self.registry.prepare_job_invocation(job_name, context)
101 }
102
103 pub fn begin_job_invocation(
104 &self,
105 job_name: &str,
106 attempt: u32,
107 trace_id: impl Into<String>,
108 principal: ExtensionPrincipal,
109 ) -> Result<Option<WasmExecutionSession>, WasmModelError> {
110 Ok(self
111 .prepare_job_invocation(job_name, attempt, trace_id, principal)?
112 .map(|plan| plan.begin_execution_with_executor(self.host_service_executor.clone())))
113 }
114
115 pub fn prepare_scheduled_job_invocation(
116 &self,
117 job_name: &str,
118 trace_id: impl Into<String>,
119 principal: ExtensionPrincipal,
120 ) -> Result<Option<InvocationPlan>, WasmModelError> {
121 let input =
122 InvocationInput::ScheduledJob(ScheduledJobInvocation::new(job_name.to_string())?);
123 let context = self.async_context(trace_id.into(), principal, input)?;
124 self.registry
125 .prepare_scheduled_job_invocation(job_name, context)
126 }
127
128 pub fn begin_scheduled_job_invocation(
129 &self,
130 job_name: &str,
131 trace_id: impl Into<String>,
132 principal: ExtensionPrincipal,
133 ) -> Result<Option<WasmExecutionSession>, WasmModelError> {
134 Ok(self
135 .prepare_scheduled_job_invocation(job_name, trace_id, principal)?
136 .map(|plan| plan.begin_execution_with_executor(self.host_service_executor.clone())))
137 }
138
139 pub fn prepare_webhook_invocation(
140 &self,
141 source: &str,
142 event: &str,
143 verified: bool,
144 replay_protected: bool,
145 trace_id: impl Into<String>,
146 principal: ExtensionPrincipal,
147 ) -> Result<Option<InvocationPlan>, WasmModelError> {
148 let input = InvocationInput::Webhook(WebhookInvocation::new(
149 source.to_string(),
150 event.to_string(),
151 verified,
152 replay_protected,
153 )?);
154 let context = self.async_context(trace_id.into(), principal, input)?;
155 let prepared = self
156 .registry
157 .prepare_webhook_invocation(source, event, context.clone());
158 if let Err(error) = &prepared {
159 let status = match error {
160 WasmModelError::UnverifiedWebhook { .. } => {
161 Some(services::WebhookObservationStatus::VerificationFailed)
162 }
163 WasmModelError::ReplayUnsafeWebhook { .. } => {
164 Some(services::WebhookObservationStatus::ReplayRejected)
165 }
166 _ => None,
167 };
168 if let Some(status) = status {
169 let _ = self.host_services.record_webhook_observation(
170 source,
171 event,
172 status,
173 &context,
174 Some(error.to_string()),
175 );
176 }
177 }
178 prepared
179 }
180
181 pub fn begin_webhook_invocation(
182 &self,
183 source: &str,
184 event: &str,
185 verified: bool,
186 replay_protected: bool,
187 trace_id: impl Into<String>,
188 principal: ExtensionPrincipal,
189 ) -> Result<Option<WasmExecutionSession>, WasmModelError> {
190 Ok(self
191 .prepare_webhook_invocation(
192 source,
193 event,
194 verified,
195 replay_protected,
196 trace_id,
197 principal,
198 )?
199 .map(|plan| plan.begin_execution_with_executor(self.host_service_executor.clone())))
200 }
201
202 pub fn prepare_admin_widget_invocations(
203 &self,
204 slot: &str,
205 execution: &RequestExecution,
206 ) -> Result<Vec<InvocationPlan>, WasmModelError> {
207 let input = InvocationInput::AdminWidget(AdminWidgetInvocation::new(slot.to_string())?);
208 let context = self.request_context(execution, input)?;
209 self.registry
210 .prepare_admin_widget_invocations(slot, context)
211 }
212
213 pub fn begin_admin_widget_invocations(
214 &self,
215 slot: &str,
216 execution: &RequestExecution,
217 ) -> Result<Vec<WasmExecutionSession>, WasmModelError> {
218 Ok(self
219 .prepare_admin_widget_invocations(slot, execution)?
220 .into_iter()
221 .map(|plan| plan.begin_execution_with_executor(self.host_service_executor.clone()))
222 .collect())
223 }
224
225 pub fn prepare_render_hook_invocations(
226 &self,
227 slot: &str,
228 execution: &RequestExecution,
229 ) -> Result<Vec<InvocationPlan>, WasmModelError> {
230 let input = InvocationInput::RenderHook(RenderHookInvocation::new(slot.to_string())?);
231 let context = self.request_context(execution, input)?;
232 self.registry.prepare_render_hook_invocations(slot, context)
233 }
234
235 pub fn begin_render_hook_invocations(
236 &self,
237 slot: &str,
238 execution: &RequestExecution,
239 ) -> Result<Vec<WasmExecutionSession>, WasmModelError> {
240 Ok(self
241 .prepare_render_hook_invocations(slot, execution)?
242 .into_iter()
243 .map(|plan| plan.begin_execution_with_executor(self.host_service_executor.clone()))
244 .collect())
245 }
246}