daemon/rows.bend
cswap-bend-cli@0.1.0.0 · 135 lines · 23 definitions
1import Base
2import cswap-bend-cli@0.1.0.0/json.bend as Json
3import cswap-bend-cli@0.1.0.0/clock.bend as Clock
4import cswap-bend-cli@0.1.0.0/policy/types.bend as T
5import cswap-bend-cli@0.1.0.0/daemon/config.bend as Cfg
6
7
8
9
10def nat_opt(+m: Maybe<&2, U32>) -> Maybe<&2, Nat>:
11 match m:
12 case None{}:
13 None{}
14 case Some{n}:
15 Some{U32.to_nat(n)}
16
17
18def epoch_text(+t: String) -> Maybe<&2, U32>:
19 Cfg.read_u32(Maybe.default(&2, String, List.head(&2, String, String.split(t, '.')), ""))
20
21def num_text(+m: Maybe<&2, Json.Json>) -> Maybe<&2, String>:
22 match m:
23 case Some{Json.JNum{t}}:
24 Some{t}
25 case _:
26 None{}
27
28def str_text(+m: Maybe<&2, Json.Json>) -> Maybe<&2, String>:
29 match m:
30 case Some{Json.JStr{s}}:
31 Some{s}
32 case _:
33 None{}
34
35def bind_s(+m: Maybe<&2, String>, f: String -> Maybe<&2, U32>) -> Maybe<&2, U32>:
36 match m:
37 case None{}:
38 None{}
39 case Some{s}:
40 f(s)
41
42def epoch_of(+j: Json.Json, +key: String) -> Maybe<&2, Nat>:
43 nat_opt(bind_s(num_text(Json.get(key, j)), t => epoch_text(t)))
44
45def pct_of(+j: Json.Json) -> Maybe<&2, Nat>:
46 nat_opt(bind_s(num_text(Json.get("pct", j)), t => Cfg.centi(t)))
47
48def iso_of(+j: Json.Json) -> Maybe<&2, Nat>:
49 nat_opt(bind_s(str_text(Json.get("resets_at", j)), t => Clock.parse_iso8601(t)))
50
51def or_null(+m: Maybe<&2, Json.Json>) -> Json.Json:
52 match m:
53 case Some{w}:
54 w
55 case None{}:
56 Json.JNull{}
57
58def win(+j: Json.Json, +key: String) -> Json.Json:
59 or_null(Json.get(key, j))
60
61
62
63def scoped2(+name: Maybe<&2, String>, +pct: Maybe<&2, Nat>, +reset: Maybe<&2, Nat>) -> Maybe<&2, T.Scoped>:
64 match name pct:
65 case Some{n} Some{p}:
66 Some{T.Scoped{n, p, reset}}
67 case _ _:
68 None{}
69
70def scoped_one(+s: Json.Json) -> Maybe<&2, T.Scoped>:
71 scoped2(str_text(Json.get("name", s)), pct_of(s), iso_of(s))
72
73def scoped_push(+m: Maybe<&2, T.Scoped>, +rest: List<&2, T.Scoped>) -> List<&2, T.Scoped>:
74 match m:
75 case Some{s}:
76 s <> rest
77 case None{}:
78 rest
79
80def scoped_chain(+items: Json.Json) -> List<&2, T.Scoped>:
81 match items:
82 case Json.JCons{h, t}:
83 scoped_push(scoped_one(h), scoped_chain(t))
84 case _:
85 []
86
87def unwrap_arr(+j: Json.Json) -> Json.Json:
88 match j:
89 case Json.JArr{items}:
90 items
91 case _:
92 Json.JNil{}
93
94def scoped_of(+good: Json.Json) -> List<&2, T.Scoped>:
95 scoped_chain(unwrap_arr(win(good, "scoped")))
96
97
98
99def err2(+is429: Bool) -> T.ErrKind:
100 match is429:
101 case True{}:
102 T.ErrHttp429{}
103 case False{}:
104 T.ErrOther{}
105
106def err_kind(+m: Maybe<&2, String>) -> T.ErrKind:
107 match m:
108 case None{}:
109 T.ErrNone{}
110 case Some{e}:
111 err2(String.eq(e, "http-429"))
112
113def zero_or(+m: Maybe<&2, Nat>) -> Nat:
114 match m:
115 case None{}:
116 0n
117 case Some{n}:
118 n
119
120def u32_field(+j: Json.Json, +key: String) -> Nat:
121 zero_or(nat_opt(bind_s(num_text(Json.get(key, j)), t => Cfg.read_u32(Maybe.default(&2, String, List.head(&2, String, String.split(t, '.')), "")))))
122
123def usage2(+slot: Nat, +row: Json.Json, +good: Json.Json, +sentinel: T.Sentinel) -> T.Usage:
124 T.Usage{slot, pct_of(win(good, "five_hour")), iso_of(win(good, "five_hour")), pct_of(win(good, "seven_day")), iso_of(win(good, "seven_day")),
125 scoped_of(good), epoch_of(row, "fetchedAt"), u32_field(row, "backoffUntil"), err_kind(str_text(Json.get("lastError", row))), u32_field(row, "consecutiveFailures"),
126 epoch_of(row, "nextPollAt"), u32_field(row, "pollIntervalS"), u32_field(row, "authDeadStrikes"), u32_field(row, "heldUntil"), u32_field(row, "claimUntil"), sentinel}
127
128
129
130
131def usage_of(+slot: Nat, +row: Json.Json, +sentinel: T.Sentinel) -> T.Usage:
132 usage2(slot, row, win(row, "lastGood"), sentinel)
133
134def empty_usage(+slot: Nat, +sentinel: T.Sentinel) -> T.Usage:
135 usage_of(slot, Json.JNull{}, sentinel)