1use crate::{BootError, BootRequest, HttpMethod, Result, SerializationOptions};
2use serde::de::DeserializeOwned;
3use serde_json::Value;
4use std::collections::BTreeMap;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum ExecutionProtocol {
9 Http,
10 WebSocket,
11 Transport,
12}
13
14impl ExecutionProtocol {
15 pub fn as_str(self) -> &'static str {
16 match self {
17 Self::Http => "http",
18 Self::WebSocket => "websocket",
19 Self::Transport => "transport",
20 }
21 }
22}
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum ExecutionTransportKind {
27 RequestResponse,
28 Event,
29}
30
31impl ExecutionTransportKind {
32 pub fn as_str(self) -> &'static str {
33 match self {
34 Self::RequestResponse => "request-response",
35 Self::Event => "event",
36 }
37 }
38}
39
40#[derive(Debug, Clone, PartialEq, Eq)]
42pub struct WebSocketExecutionContext {
43 pub gateway_path: String,
44 pub event: String,
45 pub namespace: Option<String>,
46}
47
48#[derive(Debug, Clone, PartialEq, Eq)]
50pub struct TransportExecutionContext {
51 pub pattern: String,
52 pub kind: ExecutionTransportKind,
53}
54
55#[derive(Debug, Clone)]
57pub struct ExecutionContext {
58 pub protocol: ExecutionProtocol,
59 pub method: HttpMethod,
60 pub request_path: String,
61 pub route_path: String,
62 pub module_name: Option<String>,
63 pub controller_prefix: Option<String>,
64 pub serialization: SerializationOptions,
65 pub metadata: BTreeMap<String, Value>,
66 pub request: BootRequest,
67 pub websocket: Option<WebSocketExecutionContext>,
68 pub transport: Option<TransportExecutionContext>,
69}
70
71impl ExecutionContext {
72 pub(crate) fn new(
73 request: BootRequest,
74 route_path: String,
75 module_name: Option<String>,
76 controller_prefix: Option<String>,
77 serialization: SerializationOptions,
78 metadata: BTreeMap<String, Value>,
79 ) -> Self {
80 Self {
81 protocol: ExecutionProtocol::Http,
82 method: request.method,
83 request_path: request.path.clone(),
84 route_path,
85 module_name,
86 controller_prefix,
87 serialization,
88 metadata,
89 request,
90 websocket: None,
91 transport: None,
92 }
93 }
94
95 pub(crate) fn websocket(
96 request: BootRequest,
97 gateway_path: String,
98 event: String,
99 namespace: Option<String>,
100 module_name: Option<String>,
101 metadata: BTreeMap<String, Value>,
102 ) -> Self {
103 Self {
104 protocol: ExecutionProtocol::WebSocket,
105 method: request.method,
106 request_path: request.path.clone(),
107 route_path: gateway_path.clone(),
108 module_name,
109 controller_prefix: None,
110 serialization: SerializationOptions::default(),
111 metadata,
112 request,
113 websocket: Some(WebSocketExecutionContext {
114 gateway_path,
115 event,
116 namespace,
117 }),
118 transport: None,
119 }
120 }
121
122 pub(crate) fn transport(
123 request: BootRequest,
124 pattern: String,
125 kind: ExecutionTransportKind,
126 module_name: Option<String>,
127 metadata: BTreeMap<String, Value>,
128 ) -> Self {
129 Self {
130 protocol: ExecutionProtocol::Transport,
131 method: HttpMethod::Post,
132 request_path: pattern.clone(),
133 route_path: pattern.clone(),
134 module_name,
135 controller_prefix: None,
136 serialization: SerializationOptions::default(),
137 metadata,
138 request,
139 websocket: None,
140 transport: Some(TransportExecutionContext { pattern, kind }),
141 }
142 }
143
144 pub fn protocol(&self) -> ExecutionProtocol {
145 self.protocol
146 }
147
148 pub fn websocket_context(&self) -> Option<&WebSocketExecutionContext> {
149 self.websocket.as_ref()
150 }
151
152 pub fn transport_context(&self) -> Option<&TransportExecutionContext> {
153 self.transport.as_ref()
154 }
155
156 pub fn metadata_value(&self, key: &str) -> Option<&Value> {
157 self.metadata.get(key)
158 }
159
160 pub fn metadata_as<T>(&self, key: &str) -> Result<Option<T>>
161 where
162 T: DeserializeOwned,
163 {
164 let Some(value) = self.metadata.get(key) else {
165 return Ok(None);
166 };
167
168 serde_json::from_value(value.clone())
169 .map(Some)
170 .map_err(|error| {
171 BootError::Internal(format!(
172 "failed to deserialize execution context metadata `{key}`: {error}"
173 ))
174 })
175 }
176}