daemon/dec.bend

cswap-bend-cli@0.1.0.0 · 101 lines · 19 definitions

1import Base
2import cswap-bend-cli@0.1.0.0/json.bend as Json
3import cswap-bend-cli@0.1.0.0/swlive.bend as L
4import cswap-bend-cli@0.1.0.0/store/base.bend as SBase
5import cswap-bend-cli@0.1.0.0/store/seq.bend as SSeq
6import cswap-bend-cli@0.1.0.0/clock.bend as Clock
7import cswap-bend-cli@0.1.0.0/daemon/events.bend as Ev
8import cswap-bend-cli@0.1.0.0/daemon/cadence.bend as Cad
9import cswap-bend-cli@0.1.0.0/daemon/config.bend as Cfg
10
11# The decision the daemon acts on, what a tick answers, and the result
12# builders for the outcomes that need no switch. Kept apart from `apply` so
13# the policy side of a tick never imports the switch modules.
14
15type Dec is Data:
16  DNone{reason: String, detail: String}
17  DExhausted{earliest: Maybe<&2, U32>}
18  DGo{to: String, to_email: String, trigger: String, left_headroom: Maybe<&2, U32>, left_recovery: Maybe<&2, U32>}
19
20# The events of one tick, in order, and the sleeper's facts.
21type TickRes is Data:
22  TickRes{info: Cad.Info, events: List<&2, Json.Json>}
23
24# What `tick` was handed besides the decision.
25type Ctx is Data:
26  Ctx{ctx: SBase.Ctx, dry_run: Bool, cfg: Cfg.Cfg, now: U32, ts: String, opts: L.Opts, active: Json.Json, next_poll: Maybe<&2, U32>}
27
28def sel_o(+c: Bool, x: Cad.Outcome, y: Cad.Outcome) -> Cad.Outcome:
29  match c:
30    case True{}:
31      x
32    case False{}:
33      y
34
35def blocked_reason(+r: String) -> Bool:
36  String.eq(r, "no-candidates") || String.eq(r, "no-comparison") || String.eq(r, "no-qualifying-candidate") || String.eq(r, "no-viable-target") || String.eq(r, "all-exhausted")
37
38def info(o: Cad.Outcome, +until: Maybe<&2, U32>, +long: Bool, +idle: Bool, +np: Maybe<&2, U32>) -> Cad.Info:
39  Cad.Info{o, until, long, idle, np}
40
41def one(i: Cad.Info, +e: Json.Json) -> TickRes:
42  TickRes{i, [e]}
43
44def iso_opt(+m: Maybe<&2, U32>) -> Maybe<&2, String>:
45  match m:
46    case None{}:
47      None{}
48    case Some{t}:
49      Some{Clock.iso8601_utc(t)}
50
51def ctx_ts(+c: Ctx) -> String:
52  match c:
53    case Ctx{x, d, cf, n, ts, o, a, np}:
54      ts
55
56def ctx_np(+c: Ctx) -> Maybe<&2, U32>:
57  match c:
58    case Ctx{x, d, cf, n, ts, o, a, np}:
59      np
60
61def none_res(+c: Ctx, +reason: String, +detail: String) -> TickRes:
62  one(info(sel_o(blocked_reason(reason), Cad.Blocked{}, Cad.NoAction{}), None{}, String.eq(reason, "no-candidates"), String.eq(reason, "active-idle"), ctx_np(c)), Ev.no_switch(ctx_ts(c), reason, detail))
63
64def exhausted_res(+c: Ctx, +earliest: Maybe<&2, U32>) -> TickRes:
65  one(info(Cad.Blocked{}, earliest, False{}, False{}, ctx_np(c)), Ev.all_exhausted(ctx_ts(c), iso_opt(earliest)))
66
67# A failed tick: the error as an event, exit 1.
68def error_res(+c: Ctx, +msg: String) -> TickRes:
69  one(info(Cad.Failed{}, None{}, False{}, False{}, ctx_np(c)), Ev.error(ctx_ts(c), msg, True{}))
70
71# ---- the switch itself ----------------------------------------------------------------------
72
73def ctx_now(+c: Ctx) -> U32:
74  match c:
75    case Ctx{x, d, cf, n, ts, o, a, np}:
76      n
77
78def ctx_cfg(+c: Ctx) -> Cfg.Cfg:
79  match c:
80    case Ctx{x, d, cf, n, ts, o, a, np}:
81      cf
82
83def ctx_store(+c: Ctx) -> SBase.Ctx:
84  match c:
85    case Ctx{x, d, cf, n, ts, o, a, np}:
86      x
87
88def ctx_opts(+c: Ctx) -> L.Opts:
89  match c:
90    case Ctx{x, d, cf, n, ts, o, a, np}:
91      o
92
93def ctx_active(+c: Ctx) -> Json.Json:
94  match c:
95    case Ctx{x, d, cf, n, ts, o, a, np}:
96      a
97
98def ctx_dry(+c: Ctx) -> Bool:
99  match c:
100    case Ctx{x, d, cf, n, ts, o, a, np}:
101      d