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 }
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}