warn.bend
cswap-bend-cli@0.1.0.0 · 182 lines · 33 definitions
1import Base
2import cswap-bend-cli@0.1.0.0/pollrow.bend as Pollrow
3import cswap-bend-cli@0.1.0.0/usage/gate.bend as UGate
4import cswap-bend-cli@0.1.0.0/store/seq.bend as SSeq
5import cswap-bend-cli@0.1.0.0/json.bend as Json
6import cswap-bend-cli@0.1.0.0/view.bend as View
7import cswap-bend-cli@0.1.0.0/collect.bend as Collect
8
9
10
11
12
13def dash() -> String:
14 " \u{2014} "
15
16type Seen is Data:
17 Seen{key: String, slot: String}
18
19def seen.pick(hit: Bool, s: String, rest: Maybe<&2, String>) -> Maybe<&2, String>:
20 match hit:
21 case True{}:
22 Some{s}
23 case False{}:
24 rest
25
26def seen_find(+key: String, xs: List<&2, Seen>) -> Maybe<&2, String>:
27 match xs:
28 case Nil{}:
29 None{}
30 case Con{Seen{k, s}, t}:
31 seen.pick(String.eq(k, key), s, seen_find(key, t))
32
33def append_str(xs: List<&2, String>, +x: String) -> List<&2, String>:
34 List.append(&2, String, xs, [x])
35
36def win_key2(p: Maybe<&2, Json.Json>, r: Maybe<&2, Json.Json>) -> Maybe<&2, String>:
37 match p r:
38 case Some{Json.JNum{t}} Some{Json.JStr{s}}:
39 Some{t ++ "@" ++ s}
40 case _ _:
41 None{}
42
43def win_key(+w: Json.Json) -> Maybe<&2, String>:
44 win_key2(Json.get("pct", w), Json.get("resets_at", w))
45
46def key3(a: Maybe<&2, String>, b: Maybe<&2, String>) -> Maybe<&2, String>:
47 match a b:
48 case Some{x} Some{y}:
49 Some{x ++ "|" ++ y}
50 case _ _:
51 None{}
52
53def key2(a: Maybe<&2, Json.Json>, b: Maybe<&2, Json.Json>) -> Maybe<&2, String>:
54 match a b:
55 case Some{x} Some{y}:
56 key3(win_key(x), win_key(y))
57 case _ _:
58 None{}
59
60def usage_key(+u: Json.Json) -> Maybe<&2, String>:
61 key2(Json.get("five_hour", u), Json.get("seven_day", u))
62
63type LS is Data:
64 LS{seen: List<&2, Seen>, msgs: List<&2, String>}
65
66def ls_seen(ls: LS) -> List<&2, Seen>:
67 match ls:
68 case LS{s, m}:
69 s
70
71def lock.seen(other: Maybe<&2, String>, +k: String, +slot: String, ls: LS) -> LS:
72 match other ls:
73 case Some{o} LS{s, msgs}:
74 LS{s, append_str(msgs, "Account-" ++ o ++ " and Account-" ++ slot ++ " report identical usage and reset times" ++ dash() ++ "they may be the same account (issue #117). If it persists, log in with the missing account and re-add it: cswap add --slot N")}
75 case None{} LS{s, msgs}:
76 LS{Seen{k, slot} <> s, msgs}
77
78def lock.step(m: Maybe<&2, String>, +slot: String, +ls: LS) -> LS:
79 match m:
80 case None{}:
81 ls
82 case Some{+k}:
83 lock.seen(seen_find(k, ls_seen(ls)), k, slot, ls)
84
85def lock.live(sentinel: Maybe<&2, String>, +row: Pollrow.Row, +slot: String, models: List<&2, String>, +now: U32, ls: LS) -> LS:
86 match sentinel:
87 case Some{s}:
88 ls
89 case None{}:
90 lock.step(usage_key(Pollrow.decision_usage(row, models, now)), slot, ls)
91
92def lock.acct(+a: View.Acct, models: List<&2, String>, +now: U32, ls: LS) -> LS:
93 match a:
94 case View.Acct{num, email, org_name, org_uuid, active, alias, disabled, login, sentinel, row}:
95 lock.live(sentinel, row, U32.show(num), models, now, ls)
96
97def lock.go(as: List<&2, View.Acct>, +models: List<&2, String>, +now: U32, ls: LS) -> LS:
98 match as:
99 case Nil{}:
100 ls
101 case Con{h, t}:
102 lock.go(t, models, now, lock.acct(h, models, now, ls))
103
104def msgs_of(ls: LS) -> List<&2, String>:
105 match ls:
106 case LS{s, m}:
107 m
108
109
110def lockstep(as: List<&2, View.Acct>, models: List<&2, String>, +now: U32) -> List<&2, String>:
111 msgs_of(lock.go(as, models, now, LS{[], []}))
112
113type DS is Data:
114 DS{fps: List<&2, Seen>, ids: List<&2, Seen>, msgs: List<&2, String>}
115
116def uuid_of(+seq: Json.Json, +slot: String) -> String:
117 String.trim(Maybe.default(&2, String, Json.as_string(Maybe.default(&2, Json.Json, Maybe.bind(&2, Json.Json, Json.Json, SSeq.slot_record(seq, slot), r => Json.get("uuid", r)), Json.JNull{})), ""))
118
119def ds_fps(ds: DS) -> List<&2, Seen>:
120 match ds:
121 case DS{f, i, m}:
122 f
123
124def dup.fp3(other: Maybe<&2, String>, +fp: String, +slot: String, +email: String, ds: DS) -> DS:
125 match other ds:
126 case Some{o} DS{f, i, m}:
127 DS{f, i, append_str(m, "Account-" ++ o ++ " and Account-" ++ slot ++ " hold the same credential (" ++ email ++ ")" ++ dash() ++ "one slot's backup was overwritten. Log in with the missing account and re-add it: cswap add --slot N")}
128 case None{} DS{f, i, m}:
129 DS{Seen{fp, slot} <> f, i, m}
130
131def dup.fp2(has: Bool, +fp: String, +slot: String, +email: String, +ds: DS) -> DS:
132 match has:
133 case False{}:
134 ds
135 case True{}:
136 dup.fp3(seen_find(fp, ds_fps(ds)), fp, slot, email, ds)
137
138def dup.fp(+creds: String, +slot: String, +email: String, ds: DS) -> DS:
139 dup.fp2(Bool.not(String.is_empty(creds)), UGate.fp(creds), slot, email, ds)
140
141def ds_ids(ds: DS) -> List<&2, Seen>:
142 match ds:
143 case DS{f, i, m}:
144 i
145
146def dup.id3(other: Maybe<&2, String>, +key: String, +slot: String, +email: String, ds: DS) -> DS:
147 match other ds:
148 case Some{o} DS{f, i, m}:
149 DS{f, i, append_str(m, "Account-" ++ o ++ " and Account-" ++ slot ++ " both authenticate as " ++ email ++ dash() ++ "remove or re-login one of them.")}
150 case None{} DS{f, i, m}:
151 DS{f, Seen{key, slot} <> i, m}
152
153def dup.id2(has: Bool, +key: String, +slot: String, +email: String, +ds: DS) -> DS:
154 match has:
155 case False{}:
156 ds
157 case True{}:
158 dup.id3(seen_find(key, ds_ids(ds)), key, slot, email, ds)
159
160def dup.id(+uuid: String, +org: String, +slot: String, +email: String, ds: DS) -> DS:
161 dup.id2(Bool.not(String.is_empty(uuid)), uuid ++ "@" ++ org, slot, email, ds)
162
163def dup.info(+i: Collect.Info, +seq: Json.Json, ds: DS) -> DS:
164 match i:
165 case Collect.Info{num, email, org_name, org_uuid, alias, disabled, active, creds}:
166 dup.id(uuid_of(seq, U32.show(num)), org_uuid, U32.show(num), email, dup.fp(creds, U32.show(num), email, ds))
167
168def dup.go(xs: List<&2, Collect.Info>, +seq: Json.Json, ds: DS) -> DS:
169 match xs:
170 case Nil{}:
171 ds
172 case Con{h, t}:
173 dup.go(t, seq, dup.info(h, seq, ds))
174
175def ds_msgs(ds: DS) -> List<&2, String>:
176 match ds:
177 case DS{f, i, m}:
178 m
179
180
181def duplicates(infos: List<&2, Collect.Info>, +seq: Json.Json) -> List<&2, String>:
182 ds_msgs(dup.go(infos, seq, DS{[], [], []}))