starlane_core/
template.rs

1use std::collections::{HashMap, HashSet};
2use std::convert::{TryFrom, TryInto};
3
4use serde::{Deserialize, Serialize};
5
6use crate::error::Error;
7
8use crate::proto::ProtoStarKey;
9
10use crate::star::{ServerKindExt, StarKey, StarKind, StarSubGraphKey, StarTemplateId};
11
12pub type StarKeyConstellationIndex = u16;
13
14#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)]
15pub struct ConstellationTemplate {
16    pub stars: Vec<StarTemplate>,
17}
18
19impl ConstellationTemplate {
20    pub fn new() -> Self {
21        ConstellationTemplate { stars: vec![] }
22    }
23
24    pub fn next_index(&self) -> StarKeyConstellationIndex {
25        (self.stars.len() + 1) as StarKeyConstellationIndex
26    }
27
28    pub fn new_basic() -> Self {
29        let mut template = ConstellationTemplate { stars: vec![] };
30
31        let mut central = StarTemplate::new(
32            StarKeyTemplate::central(),
33            StarKind::Central,
34            "central".into(),
35        );
36
37        let mut mesh = StarTemplate::new(
38            StarKeyTemplate::central_geodesic(1),
39            StarKind::Mesh,
40            "mesh".into(),
41        );
42        let mut space_host = StarTemplate::new(
43            StarKeyTemplate::central_geodesic(2),
44            StarKind::Space,
45            "space_host".into(),
46        );
47        let mut app_host = StarTemplate::new(
48            StarKeyTemplate::central_geodesic(3),
49            StarKind::App,
50            "app_host".into(),
51        );
52        let mut actor_host = StarTemplate::new(
53            StarKeyTemplate::central_geodesic(4),
54            StarKind::Mechtron,
55            "actor_host".into(),
56        );
57        let mut file_store = StarTemplate::new(
58            StarKeyTemplate::central_geodesic(5),
59            StarKind::FileStore,
60            "file_store".into(),
61        );
62        let mut web_host = StarTemplate::new(
63            StarKeyTemplate::central_geodesic(6),
64            StarKind::Web,
65            "web_host".into(),
66        );
67        let mut gateway = StarTemplate::new(
68            StarKeyTemplate::central_geodesic(7),
69            StarKind::Gateway,
70            "gateway".into(),
71        );
72        let mut artifact_store = StarTemplate::new(
73            StarKeyTemplate::central_geodesic(8),
74            StarKind::ArtifactStore,
75            "artifact_store".into(),
76        );
77
78        ConstellationTemplate::connect(&mut central, &mut mesh);
79        ConstellationTemplate::connect(&mut space_host, &mut mesh);
80        ConstellationTemplate::connect(&mut app_host, &mut mesh);
81        ConstellationTemplate::connect(&mut actor_host, &mut mesh);
82        ConstellationTemplate::connect(&mut file_store, &mut mesh);
83        ConstellationTemplate::connect(&mut web_host, &mut mesh);
84        ConstellationTemplate::connect(&mut gateway, &mut mesh);
85        ConstellationTemplate::connect(&mut artifact_store, &mut mesh);
86
87        template.add_star(central);
88        template.add_star(mesh);
89        template.add_star(space_host);
90        template.add_star(app_host);
91        template.add_star(actor_host);
92        template.add_star(file_store);
93        template.add_star(web_host);
94        template.add_star(gateway);
95        template.add_star(artifact_store);
96
97        template
98    }
99
100    pub fn new_basic_with(star_templates: Vec<StarTemplate>) -> Self {
101        let mut standalone = Self::new_basic();
102        let mut mesh = standalone.get_star("mesh".into()).cloned().unwrap();
103        for mut star_template in star_templates {
104            star_template.key = StarKeyTemplate::central_geodesic(standalone.next_index());
105            ConstellationTemplate::connect(&mut star_template, &mut mesh);
106            standalone.add_star(star_template);
107        }
108
109        standalone
110    }
111
112    pub fn new_basic_with_external() -> Self {
113        let external = StarTemplate::new(
114            StarKeyTemplate::central_geodesic(10),
115            StarKind::K8s,
116            "database".into(),
117        );
118        Self::new_basic_with(vec![external])
119    }
120
121    pub fn new_client(gateway_machine: MachineName) -> Self {
122        let mut template = ConstellationTemplate { stars: vec![] };
123
124        let _subgraph_data_key = "client".to_string();
125
126        let request_from_constellation =
127            ConstellationSelector::AnyWithGatewayInsideMachine(gateway_machine.clone());
128
129        let mut client = StarTemplate::new(
130            StarKeyTemplate::subgraph_data_key(request_from_constellation, 1),
131            StarKind::Client,
132            "client".into(),
133        );
134
135        let mut lane = LaneTemplate::new(StarInConstellationTemplateSelector {
136            constellation: ConstellationSelector::AnyWithGatewayInsideMachine(gateway_machine),
137            star: StarTemplateSelector::Kind(StarKind::Gateway),
138        });
139        lane.as_key_requestor();
140
141        client.add_lane(lane);
142
143        template.add_star(client);
144
145        template
146    }
147
148    pub fn connect(a: &mut StarTemplate, b: &mut StarTemplate) {
149        a.add_lane(LaneTemplate::new(StarInConstellationTemplateSelector {
150            constellation: ConstellationSelector::Local,
151            star: StarTemplateSelector::Handle(b.handle.clone()),
152        }));
153        b.add_lane(LaneTemplate::new(StarInConstellationTemplateSelector {
154            constellation: ConstellationSelector::Local,
155            star: StarTemplateSelector::Handle(a.handle.clone()),
156        }));
157    }
158
159    pub fn add_star(&mut self, star: StarTemplate) {
160        self.stars.push(star);
161    }
162
163    pub fn get_star(&self, handle: StarTemplateHandle) -> Option<&StarTemplate> {
164        for star in &self.stars {
165            if star.handle == handle {
166                return Option::Some(star);
167            }
168        }
169        Option::None
170    }
171}
172
173pub type ConstellationTemplateHandle = String;
174
175#[derive(Hash, PartialEq, Eq, Debug, Clone, Serialize, Deserialize, Ord, PartialOrd)]
176pub struct StarInConstellationTemplateHandle {
177    pub constellation: ConstellationTemplateHandle,
178    pub star: StarTemplateHandle,
179}
180
181impl ToString for StarInConstellationTemplateHandle {
182    fn to_string(&self) -> String {
183        format!(
184            "{}::{}",
185            self.constellation.to_string(),
186            self.star.to_string()
187        )
188    }
189}
190
191impl StarInConstellationTemplateHandle {
192    pub fn new(constellation: ConstellationTemplateHandle, star: StarTemplateHandle) -> Self {
193        Self {
194            constellation,
195            star,
196        }
197    }
198}
199
200#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)]
201pub enum StarSelector {
202    Any,
203    StarInConstellationTemplate(StarInConstellationTemplateSelector),
204}
205
206#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Serialize, Deserialize)]
207pub enum ConstellationSelector {
208    Local,
209    Named(ConstellationName),
210    AnyWithGatewayInsideMachine(MachineName),
211}
212
213#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)]
214pub struct StarInConstellationTemplateSelector {
215    pub constellation: ConstellationSelector,
216    pub star: StarTemplateSelector,
217}
218
219#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)]
220pub enum StarTemplateSelector {
221    Handle(StarTemplateHandle),
222    Kind(StarKind),
223}
224
225#[derive(Hash, PartialEq, Eq, Debug, Clone, Serialize, Deserialize, Ord, PartialOrd)]
226pub struct StarTemplateHandle {
227    pub name: String,
228    pub index: Option<usize>,
229}
230
231impl StarTemplateHandle {
232    pub fn new(name: String) -> Self {
233        Self {
234            name,
235            index: Option::None,
236        }
237    }
238
239    pub fn with_index(name: String, index: usize) -> Self {
240        Self {
241            name,
242            index: Option::Some(index),
243        }
244    }
245}
246
247impl ToString for StarTemplateHandle {
248    fn to_string(&self) -> String {
249        match self.index {
250            None => self.name.clone(),
251            Some(index) => {
252                format!("{}[{}]", self.name, index)
253            }
254        }
255    }
256}
257
258impl From<&str> for StarTemplateHandle {
259    fn from(name: &str) -> Self {
260        Self::new(name.to_string())
261    }
262}
263
264pub struct ProtoConstellationLayout {
265    pub handles_to_machine: HashMap<StarTemplateHandle, MachineName>,
266    pub template: ConstellationTemplate,
267    pub machine_to_host: HashMap<MachineName, String>,
268}
269
270impl ProtoConstellationLayout {
271    pub fn new(template: ConstellationTemplate) -> Self {
272        Self {
273            handles_to_machine: HashMap::new(),
274            template,
275            machine_to_host: HashMap::new(),
276        }
277    }
278
279    pub fn set_default_machine(&mut self, machine: MachineName) {
280        for star in &self.template.stars {
281            if !self.handles_to_machine.contains_key(&star.handle) {
282                self.handles_to_machine
283                    .insert(star.handle.clone(), machine.clone());
284            }
285        }
286    }
287
288    pub fn set_machine_for_handle(&mut self, machine: MachineName, handle: StarTemplateHandle) {
289        self.handles_to_machine
290            .insert(handle.clone(), machine.clone());
291    }
292}
293
294pub struct ConstellationLayout {
295    pub handles_to_machine: HashMap<StarTemplateHandle, MachineName>,
296    pub template: ConstellationTemplate,
297    pub machine_to_host_address: HashMap<MachineName, String>,
298}
299
300impl ConstellationLayout {
301    pub fn standalone() -> Result<Self, Error> {
302        let mut standalone = ProtoConstellationLayout::new(ConstellationTemplate::new_basic());
303        standalone.set_default_machine("server".to_string());
304        standalone.try_into()
305    }
306
307    pub fn standalone_with_external() -> Result<Self, Error> {
308        let mut standalone =
309            ProtoConstellationLayout::new(ConstellationTemplate::new_basic_with_external());
310        standalone.set_default_machine("server".to_string());
311        standalone.try_into()
312    }
313
314    pub fn client(gateway_machine: MachineName) -> Result<Self, Error> {
315        let mut standalone =
316            ProtoConstellationLayout::new(ConstellationTemplate::new_client(gateway_machine));
317        standalone.set_default_machine("client".to_string());
318        standalone.try_into()
319    }
320
321    pub fn set_machine_host_address(&mut self, machine: MachineName, host_address: String) {
322        self.machine_to_host_address.insert(machine, host_address);
323    }
324
325    pub fn get_machine_host_adddress(&self, machine: MachineName) -> String {
326        self.machine_to_host_address
327            .get(&machine)
328            .unwrap_or(&format!(
329                "starlane-{}:{}",
330                machine,
331                crate::starlane::DEFAULT_PORT.clone()
332            ))
333            .clone()
334    }
335}
336
337impl TryFrom<ProtoConstellationLayout> for ConstellationLayout {
338    type Error = Error;
339
340    fn try_from(value: ProtoConstellationLayout) -> Result<Self, Self::Error> {
341        for star in &value.template.stars {
342            if !value.handles_to_machine.contains_key(&star.handle) {
343                return Err(format!(
344                    "missing machine for star handle: {}",
345                    star.handle.to_string()
346                )
347                .into());
348            }
349        }
350        Ok(Self {
351            handles_to_machine: value.handles_to_machine,
352            template: value.template,
353            machine_to_host_address: value.machine_to_host,
354        })
355    }
356}
357
358pub struct ConstellationData {
359    pub exclude_handles: HashSet<String>,
360    pub subgraphs: HashMap<String, Vec<StarSubGraphKey>>,
361}
362
363impl ConstellationData {
364    pub fn new() -> Self {
365        ConstellationData {
366            exclude_handles: HashSet::new(),
367            subgraphs: HashMap::new(),
368        }
369    }
370}
371
372#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Serialize, Deserialize)]
373pub struct StarKeyTemplate {
374    pub subgraph: StarKeySubgraphTemplate,
375    pub index: StarKeyConstellationIndexTemplate,
376}
377
378impl StarKeyTemplate {
379    pub fn central_geodesic(index: StarKeyConstellationIndex) -> Self {
380        StarKeyTemplate {
381            subgraph: StarKeySubgraphTemplate::Core,
382            index: StarKeyConstellationIndexTemplate::Exact(index),
383        }
384    }
385
386    pub fn central() -> Self {
387        StarKeyTemplate {
388            subgraph: StarKeySubgraphTemplate::Core,
389            index: StarKeyConstellationIndexTemplate::Central,
390        }
391    }
392
393    pub fn subgraph_data_key(
394        request_from_constellation: ConstellationSelector,
395        index: StarKeyConstellationIndex,
396    ) -> Self {
397        StarKeyTemplate {
398            subgraph: StarKeySubgraphTemplate::RequestStarSubGraphKeyFromConstellation(
399                request_from_constellation,
400            ),
401            index: StarKeyConstellationIndexTemplate::Exact(index),
402        }
403    }
404
405    pub fn create(&self) -> ProtoStarKey {
406        let index = match self.index {
407            StarKeyConstellationIndexTemplate::Central => 0,
408            StarKeyConstellationIndexTemplate::Exact(index) => index,
409        };
410
411        let subgraph = match &self.subgraph {
412            StarKeySubgraphTemplate::Core => {
413                vec![]
414            }
415            StarKeySubgraphTemplate::RequestStarSubGraphKeyFromConstellation(_) => {
416                return ProtoStarKey::RequestSubKeyExpansion(index)
417            }
418        };
419
420        ProtoStarKey::Key(StarKey::new_with_subgraph(subgraph, index))
421    }
422}
423
424pub type MachineName = String;
425pub type ConstellationName = String;
426
427#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Serialize, Deserialize)]
428pub enum StarKeySubgraphTemplate {
429    Core,
430    RequestStarSubGraphKeyFromConstellation(ConstellationSelector),
431    //    Path(Vec<StarSubGraphKey>),
432}
433
434#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Serialize, Deserialize)]
435pub enum StarKeyConstellationIndexTemplate {
436    Central,
437    Exact(StarKeyConstellationIndex),
438}
439
440#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)]
441pub struct StarTemplate {
442    pub key: StarKeyTemplate,
443    pub lanes: Vec<LaneTemplate>,
444    pub kind: StarKind,
445    pub handle: StarTemplateHandle,
446}
447
448impl StarTemplate {
449    pub fn new(key: StarKeyTemplate, kind: StarKind, handle: StarTemplateHandle) -> Self {
450        StarTemplate {
451            key: key,
452            kind: kind,
453            lanes: vec![],
454            handle: handle,
455        }
456    }
457
458    pub fn add_lane(&mut self, lane: LaneTemplate) -> Result<(), Error> {
459        if lane.key_requestor {
460            for lane in &self.lanes {
461                if lane.key_requestor {
462                    error!("a star template can only have one key_requestor lane");
463                    return Err("a star template can only have one key_requestor lane".into());
464                }
465            }
466        }
467
468        self.lanes.push(lane);
469
470        Ok(())
471    }
472}
473
474#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)]
475pub struct LaneTemplate {
476    pub star_selector: StarInConstellationTemplateSelector,
477    pub key_requestor: bool,
478}
479
480impl LaneTemplate {
481    pub fn new(star_selector: StarInConstellationTemplateSelector) -> Self {
482        Self {
483            star_selector: star_selector,
484            key_requestor: false,
485        }
486    }
487
488    pub fn as_key_requestor(&mut self) {
489        self.key_requestor = true;
490    }
491}
492
493#[cfg(test)]
494mod test {
495    use crate::template::ConstellationTemplate;
496
497    #[test]
498    pub fn standalone() {
499        ConstellationTemplate::new_basic();
500    }
501}