cosmic_space/config/
bind.rs

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        /*        match self.path.is_match(&wave.core().uri.path()) {
318                   true => Ok(()),
319                   false => Err(()),
320               }
321
322        */
323    }
324}