1use std::convert::TryInto;
2
3use crate::Bin;
4use regex::Regex;
5use serde::{Deserialize, Serialize};
6
7use crate::command::direct::Cmd;
8use crate::err::SpaceErr;
9use crate::loc::Topic;
10use crate::parse::model::{
11 BindScope, MethodScope, PipelineSegment, PipelineSegmentDef, PipelineVar, RouteScope,
12 ScopeFilters, WaveScope,
13};
14use crate::parse::{bind_config, Env};
15use crate::point::{Point, PointCtx, PointVar};
16use crate::selector::PayloadBlock;
17use crate::selector::PayloadBlockDef;
18use crate::substance::{Call, CallDef, Substance, SubstancePattern};
19use crate::util::{ToResolved, ValueMatcher, ValuePattern};
20use crate::wave::core::{DirectedCore, MethodKind, MethodPattern};
21use crate::wave::{DirectedWave, Ping, RecipientSelector, SingularDirectedWave, Wave};
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
24pub enum WaveDirection {
25 Direct,
26 Reflect,
27}
28
29#[derive(Clone)]
30pub struct BindConfig {
31 scopes: Vec<BindScope>,
32}
33
34impl BindConfig {
35 pub fn new(scopes: Vec<BindScope>) -> Self {
36 Self { scopes }
37 }
38
39 pub fn route_scopes(&self) -> Vec<&RouteScope> {
40 let mut scopes = vec![];
41 for scope in &self.scopes {
42 if let BindScope::RequestScope(request_scope) = &scope {
43 scopes.push(request_scope);
44 }
45 }
46 scopes
47 }
48
49 pub fn select(&self, directed: &DirectedWave) -> Result<&MethodScope, SpaceErr> {
50 for route_scope in self.route_scopes() {
51 if route_scope.selector.is_match(directed).is_ok() {
52 for message_scope in &route_scope.block {
53 if message_scope.selector.is_match(directed).is_ok() {
54 for method_scope in &message_scope.block {
55 if method_scope.selector.is_match(directed).is_ok() {
56 return Ok(method_scope);
57 }
58 }
59 }
60 }
61 }
62 }
63 Err(SpaceErr::Status {
64 status: 404,
65 message: format!(
66 "no route matches {}<{}>{}",
67 directed.kind().to_string(),
68 directed.core().method.to_string(),
69 directed.core().uri.path().to_string()
70 ),
71 })
72 }
73}
74
75impl TryFrom<Vec<u8>> for BindConfig {
76 type Error = SpaceErr;
77
78 fn try_from(doc: Vec<u8>) -> Result<Self, Self::Error> {
79 let doc = String::from_utf8(doc)?;
80 bind_config(doc.as_str())
81 }
82}
83
84impl TryFrom<Bin> for BindConfig {
85 type Error = SpaceErr;
86
87 fn try_from(doc: Bin) -> Result<Self, Self::Error> {
88 let doc = String::from_utf8((*doc).clone())?;
89 bind_config(doc.as_str())
90 }
91}
92
93pub struct Cursor {}
94
95#[derive(Debug, Clone, Serialize, Deserialize)]
96pub struct ConfigScope<T, E> {
97 pub scope_type: T,
98 pub elements: Vec<E>,
99}
100
101impl<T, E> ConfigScope<T, E> {
102 pub fn new(scope_type: T, elements: Vec<E>) -> Self {
103 Self {
104 scope_type,
105 elements,
106 }
107 }
108}
109
110pub type Pipeline = PipelineDef<Point>;
111pub type PipelineCtx = PipelineDef<PointCtx>;
112
113#[derive(Debug, Clone)]
114pub struct PipelineDef<Pnt> {
115 pub segments: Vec<PipelineSegmentDef<Pnt>>,
116}
117
118impl<Pnt> PipelineDef<Pnt> {
119 pub fn new() -> Self {
120 Self { segments: vec![] }
121 }
122
123 pub fn consume(&mut self) -> Option<PipelineSegmentDef<Pnt>> {
124 if self.segments.is_empty() {
125 Option::None
126 } else {
127 Option::Some(self.segments.remove(0))
128 }
129 }
130}
131
132pub type PipelineStepVar = PipelineStepDef<PointVar>;
133pub type PipelineStepCtx = PipelineStepDef<PointCtx>;
134pub type PipelineStep = PipelineStepDef<Point>;
135
136#[derive(Debug, Clone)]
137pub struct PipelineStepDef<Pnt> {
138 pub entry: WaveDirection,
139 pub exit: WaveDirection,
140 pub blocks: Vec<PayloadBlockDef<Pnt>>,
141}
142
143impl<Pnt> PipelineStepDef<Pnt> {
144 pub fn direct() -> Self {
145 Self {
146 entry: WaveDirection::Direct,
147 exit: WaveDirection::Direct,
148 blocks: vec![],
149 }
150 }
151
152 pub fn rtn() -> Self {
153 Self {
154 entry: WaveDirection::Reflect,
155 exit: WaveDirection::Reflect,
156 blocks: vec![],
157 }
158 }
159}
160
161impl ToResolved<PipelineStep> for PipelineStepCtx {
162 fn to_resolved(self, env: &Env) -> Result<PipelineStep, SpaceErr> {
163 let mut blocks = vec![];
164 for block in self.blocks {
165 blocks.push(block.to_resolved(env)?);
166 }
167
168 Ok(PipelineStep {
169 entry: self.entry,
170 exit: self.exit,
171 blocks,
172 })
173 }
174}
175
176impl ToResolved<PipelineStepCtx> for PipelineStepVar {
177 fn to_resolved(self, env: &Env) -> Result<PipelineStepCtx, SpaceErr> {
178 let mut blocks = vec![];
179 for block in self.blocks {
180 blocks.push(block.to_resolved(env)?);
181 }
182
183 Ok(PipelineStepCtx {
184 entry: self.entry,
185 exit: self.exit,
186 blocks,
187 })
188 }
189}
190
191impl PipelineStep {
192 pub fn new(entry: WaveDirection, exit: WaveDirection) -> Self {
193 Self {
194 entry,
195 exit,
196 blocks: vec![],
197 }
198 }
199}
200
201pub type PatternBlock = ValuePattern<SubstancePattern>;
202
203pub type PipelineStopCtx = PipelineStopDef<PointCtx>;
204pub type PipelineStopVar = PipelineStopDef<PointVar>;
205pub type PipelineStop = PipelineStopDef<Point>;
206
207#[derive(Debug, Clone)]
208pub enum PipelineStopDef<Pnt> {
209 Core,
210 Call(CallDef<Pnt>),
211 Reflect,
212 Point(Pnt),
213 Err { status: u16, msg: String },
214}
215
216impl ToResolved<PipelineStop> for PipelineStopVar {
217 fn to_resolved(self, env: &Env) -> Result<PipelineStop, SpaceErr> {
218 let stop: PipelineStopCtx = self.to_resolved(env)?;
219 stop.to_resolved(env)
220 }
221}
222
223impl ToResolved<PipelineStop> for PipelineStopCtx {
224 fn to_resolved(self, env: &Env) -> Result<PipelineStop, SpaceErr> {
225 Ok(match self {
226 PipelineStopCtx::Core => PipelineStop::Core,
227 PipelineStopCtx::Call(call) => PipelineStop::Call(call.to_resolved(env)?),
228 PipelineStopCtx::Reflect => PipelineStop::Reflect,
229 PipelineStopCtx::Point(point) => PipelineStop::Point(point.to_resolved(env)?),
230 PipelineStopCtx::Err { status, msg } => PipelineStop::Err { status, msg },
231 })
232 }
233}
234
235impl ToResolved<PipelineStopCtx> for PipelineStopVar {
236 fn to_resolved(self, env: &Env) -> Result<PipelineStopCtx, SpaceErr> {
237 Ok(match self {
238 PipelineStopVar::Core => PipelineStopCtx::Core,
239 PipelineStopVar::Call(call) => PipelineStopCtx::Call(call.to_resolved(env)?),
240 PipelineStopVar::Reflect => PipelineStopCtx::Reflect,
241 PipelineStopVar::Point(point) => PipelineStopCtx::Point(point.to_resolved(env)?),
242 PipelineStopVar::Err { status, msg } => PipelineStopCtx::Err { status, msg },
243 })
244 }
245}
246
247pub enum Whitelist {
248 Any,
249 None,
250 Enumerated(Vec<CallPattern>),
251}
252
253pub enum CallPattern {
254 Any,
255 Call,
256}
257
258#[derive(Clone)]
259pub struct RouteSelector {
260 pub topic: Option<ValuePattern<Topic>>,
261 pub method: ValuePattern<MethodPattern>,
262 pub path: Regex,
263 pub filters: ScopeFilters,
264}
265
266impl ToString for RouteSelector {
267 fn to_string(&self) -> String {
268 format!("{}", self.method.to_string())
269 }
270}
271
272impl RouteSelector {
273 pub fn new(
274 topic: Option<ValuePattern<Topic>>,
275 method: ValuePattern<MethodPattern>,
276 path: Regex,
277 filters: ScopeFilters,
278 ) -> Self {
279 Self {
280 topic,
281 method,
282 path,
283 filters,
284 }
285 }
286
287 pub fn any() -> Self {
288 Self {
289 topic: None,
290 method: ValuePattern::Any,
291 path: Regex::new("/.*").unwrap(),
292 filters: Default::default(),
293 }
294 }
295
296 pub fn from_method(method: ValuePattern<MethodPattern>) -> Self {
297 Self {
298 topic: None,
299 method,
300 path: Regex::new("/.*").unwrap(),
301 filters: Default::default(),
302 }
303 }
304
305 pub fn with_topic(self, topic: Topic) -> Self {
306 Self {
307 topic: Some(ValuePattern::Pattern(topic)),
308 method: self.method,
309 path: self.path,
310 filters: self.filters,
311 }
312 }
313
314 pub fn is_match<'a>(&self, wave: &'a DirectedWave) -> Result<(), ()> {
315 self.method.is_match(&wave.core().method)?;
316 Ok(())
317 }
324}