1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
//! Service shapes migrate absent construction fields on read.
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
/// Where a service stands.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ServiceState {
/// Registered, not running: created, or exited without being asked.
Asleep,
/// Contracts are approved; construction has not completed.
Building,
/// Its worker registered its subjects.
Live,
/// Stopped by a holder; woken by one.
Held,
/// Stopped for good; kept with its history.
Retired,
}
/// One change of state, with who made it and when.
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Transition {
/// The state before.
pub from: ServiceState,
/// The state after.
pub to: ServiceState,
/// The Lys holder that asked, or `process` for the service's own exit.
pub holder: String,
/// Milliseconds since the epoch.
pub at_ms: u64,
/// What happened beside the state, such as an exit status.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub note: Option<String>,
}
/// One service, as kept.
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ServiceRecord {
/// Its id, which is also its `liminal.service` id in Lys.
pub id: String,
/// The name it was created with, one segment.
pub name: String,
/// The template it runs.
#[serde(default)]
pub template: Option<String>,
/// Exact serving subjects. Configuration creates each root with the name;
/// construction keeps its promised subject identifiers unchanged.
pub subjects: Vec<String>,
/// Approved purpose, absent on records migrated from configuration services.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub purpose: Option<String>,
/// Exact input/output promises, empty on pre-construction records.
#[serde(default)]
pub contracts: BTreeMap<String, super::site::Contract>,
/// The sole builder, kept after completion for attribution.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub builder: Option<String>,
/// Grant ids retained even after revocation for the audit history.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub builder_grants: Option<super::site::BuilderGrants>,
/// Whether the binding still admits construction writes.
#[serde(default)]
pub builder_bound: bool,
/// Immutable actual site approvers from the approval connector, or `lys` for an act Lys
/// answered outright.
#[serde(default)]
pub approved_by: Vec<String>,
/// The person answerable for the site: the responsible person of the pass that created it.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub responsible: Option<String>,
/// Retained plan and its complete write history.
#[serde(default)]
pub plan: super::plan::Plan,
/// Approval receipts retained alongside this service's transitions.
#[serde(default)]
pub approvals: Vec<super::site::Approval>,
/// Where it stands.
pub state: ServiceState,
/// The holder that created it.
pub created_by: String,
/// Every transition, oldest first.
pub transitions: Vec<Transition>,
}
impl std::fmt::Debug for ServiceRecord {
fn fmt(&self, out: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
out.debug_struct("ServiceRecord")
.field("state", &self.state)
.field("transitions", &self.transitions.len())
.finish_non_exhaustive()
}
}