From 76407018d099437f8ef33531c5101a6f881dbd72 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Mon, 5 Feb 2024 15:50:22 -0600 Subject: [PATCH 01/11] subscriber: initial version compiles --- desk/app/groups.hoon | 82 +++++++++++++++++++++++++++------------- desk/lib/subscriber.hoon | 30 +++++++++++++++ 2 files changed, 85 insertions(+), 27 deletions(-) create mode 100644 desk/lib/subscriber.hoon diff --git a/desk/app/groups.hoon b/desk/app/groups.hoon index bf87f3a21f..167eea8933 100644 --- a/desk/app/groups.hoon +++ b/desk/app/groups.hoon @@ -2,7 +2,7 @@ /- meta /- e=epic /+ default-agent, verb, dbug -/+ v=volume +/+ v=volume, s=subscriber /+ of /+ epos-lib=saga :: performance, keep warm @@ -14,18 +14,19 @@ +$ card card:agent:gall ++ import-epoch ~2022.10.11 +$ current-state - $: %2 + $: %3 groups=net-groups:g :: $= volume $: base=level:v area=(map flag:g level:v) :: override per group - chan=(map nest:g level:v) :: override per channel + chan=(map nest:g level:v) :: override per channel == :: xeno=gangs:g :: graph -> agent shoal=(map flag:g dude:gall) + =^subs:s == :: -- @@ -288,12 +289,13 @@ ?- -.old %0 $(old (state-0-to-1 old)) %1 $(old (state-1-to-2 old)) - :: - %2 + %2 $(old (state-2-to-3 old)) + :: + %3 =. state old =. cor restore-missing-subs =. cor (emit %pass /groups/role %agent [our.bowl dap.bowl] %poke noun+!>(%verify-cabals)) - =. cor watch-contact + =. cor (watch-contact |) ?: =(okay:g cool) cor =. cor (emil (drop load:epos)) =/ groups ~(tap in ~(key by groups)) @@ -304,7 +306,7 @@ go-abet:go-upgrade:(go-abed:group-core i.groups) $(groups t.groups) == - +$ versioned-state $%(current-state state-1 state-0) + +$ versioned-state $%(current-state state-2 state-1 state-0) +$ state-0 $: %0 groups=net-groups:zero @@ -327,6 +329,20 @@ shoal=(map flag:zero dude:gall) == :: + +$ state-2 + $: %2 + groups=net-groups:g + :: + $= volume + $: base=level:v + area=(map flag:g level:v) :: override per group + chan=(map nest:g level:v) :: override per channel + == + :: + xeno=gangs:g + :: graph -> agent + shoal=(map flag:g dude:gall) + == ++ state-0-to-1 |= state-0 ^- state-1 @@ -334,9 +350,14 @@ :: ++ state-1-to-2 |= state-1 - ^- current-state + ^- state-2 [%2 (groups-1-to-2 groups) volume xeno shoal] :: + ++ state-2-to-3 + |= state-2 + ^- current-state + [%3 groups volume xeno shoal ~] + :: ++ groups-1-to-2 |= groups=net-groups:zero ^- net-groups:g @@ -588,6 +609,14 @@ ^+ cor !! :: +++ subscribe + |= [=wire =dock =path] + |= delay=? + =^ card=(unit card) subs + (~(subscribe s [subs bowl]) wire dock path delay) + ?~ card cor + (emit u.card) +:: ++ cast |= [grp=flag:g gra=flag:g] ^+ cor @@ -632,13 +661,13 @@ == :: ++ watch-contact - (emit %pass /contact %agent [our.bowl %contacts] %watch /contact) + (subscribe /contact [our.bowl %contacts] /contact) :: ++ take-contact |= =sign:agent:gall ?+ -.sign cor %kick - watch-contact + (watch-contact &) :: %watch-ack cor @@ -653,20 +682,20 @@ == :: ++ watch-epic - |= her=ship + |= [her=ship delay=?] ^+ cor =/ =wire /epic =/ =dock [her dap.bowl] ?: (~(has by wex.bowl) [wire dock]) cor - (emit %pass wire %agent [her dap.bowl] %watch /epic) + ((subscribe wire dock wire) delay) :: ++ take-epic |= =sign:agent:gall ^+ cor ?+ -.sign cor %kick - (watch-epic src.bowl) + (watch-epic src.bowl &) :: %fact ?. =(%epic p.cage.sign) @@ -928,18 +957,16 @@ ^+ go-core ?: |(go-has-sub =(our.bowl p.flag)) go-core - (go-sub init) + (go-sub init |) :: ++ go-sub - |= init=_| + |= [init=_| delay=?] ^+ go-core =/ =time ?.(?=(%sub -.net) *time p.net) =/ base=wire (snoc go-area %updates) =/ =path (snoc base ?:(init %init (scot %da time))) - =/ =card - [%pass base %agent [p.flag dap.bowl] %watch path] - =. cor (emit card) + =. cor ((subscribe base [p.flag dap.bowl] path) delay) go-core :: ++ go-watch @@ -1082,11 +1109,11 @@ ++ go-take-update |= =sign:agent:gall ^+ go-core - ?+ -.sign (go-sub |) + ?+ -.sign (go-sub | &) %kick ?> ?=(%sub -.net) ?. ?=(%chi -.saga.net) go-core - (go-sub !load.net) + (go-sub !load.net &) :: %watch-ack =? cor (~(has by xeno) flag) @@ -1119,7 +1146,7 @@ go-core ~& "took lev epic: {}" =. saga.net lev/~ - =. cor (watch-epic p.flag) + =. cor (watch-epic p.flag |) go-core :: ++ go-make-chi @@ -1791,8 +1818,9 @@ =/ =action:g [flag now.bowl %cordon %shut %del-ships %ask ships] (poke-host /rescind act:mar:g !>(action)) ++ get-preview - =/ =task:agent:gall [%watch /groups/(scot %p p.flag)/[q.flag]/preview] - (pass-host /preview task) + %^ subscribe (welp ga-area /preview) + [p.flag dap.bowl] + /groups/(scot %p p.flag)/[q.flag]/preview -- ++ ga-start-join ^+ ga-core @@ -1816,7 +1844,7 @@ ++ ga-watch |= =(pole knot) ^+ ga-core - =. cor (emit get-preview:ga-pass) + =. cor (get-preview:ga-pass |) ga-core :: ++ ga-give-update @@ -1869,7 +1897,7 @@ %kick ?. (~(has by xeno) flag) ga-core ?^ pev.gang ga-core - ga-core(cor (emit get-preview:ga-pass)) + ga-core(cor (get-preview:ga-pass &)) == :: [%join %add ~] @@ -1885,7 +1913,7 @@ =. groups (~(put by groups) flag net group) :: =. cor - go-abet:(go-sub:(go-abed:group-core flag) &) + go-abet:(go-sub:(go-abed:group-core flag) & |) ga-core [%knock ~] ?> ?=(%poke-ack -.sign) @@ -1920,7 +1948,7 @@ ++ ga-invite |= =invite:g =. vit.gang `invite - =. cor (emit get-preview:ga-pass) + =. cor (get-preview:ga-pass |) =. cor ga-give-update ga-core :: diff --git a/desk/lib/subscriber.hoon b/desk/lib/subscriber.hoon new file mode 100644 index 0000000000..458160a323 --- /dev/null +++ b/desk/lib/subscriber.hoon @@ -0,0 +1,30 @@ +=< subscriber +|% ++$ sub + $: =dock + =path + == +:: ++$ subs (map wire sub) +:: +++ subscriber + |_ [=subs bowl:gall] + ++ interval ~s30 + ++ handle-wakeup + |= =wire + ^- [(unit card:agent:gall) _subs] + ?> ?=([%~.~ %retry *] wire) + =/ sub (~(get by subs) t.t.wire) + ?~ sub [~ subs] + :- `[%pass t.wire %agent dock.u.sub %watch path.u.sub] + (~(del by subs) t.t.wire) + ++ subscribe + |= [=wire =dock =path delay=?] + ^- [(unit card:agent:gall) _subs] + ?: (~(has by subs) wire) + ((slog 'Duplicate subscription' >[wire dock]< ~) [~ subs]) + ?. delay [`[%pass wire %agent dock %watch path] subs] + :_ (~(put by subs) wire [dock path]) + `[%pass (weld /~/retry wire) %arvo %b %wait (add now interval)] + -- +-- \ No newline at end of file From d5f258b23e77469d73e1131827248c672716b662 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Tue, 6 Feb 2024 17:52:15 -0600 Subject: [PATCH 02/11] subscriber: adding testing hooks --- desk/app/groups.hoon | 35 +++++++++++++++++++++++++++++++++-- desk/lib/subscriber.hoon | 19 ++++++++++++++++--- 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/desk/app/groups.hoon b/desk/app/groups.hoon index 167eea8933..b2c7396433 100644 --- a/desk/app/groups.hoon +++ b/desk/app/groups.hoon @@ -102,6 +102,8 @@ ?+ q.vase !! %reset-all-perms reset-all-perms %verify-cabals verify-cabals + %test-loop test-loop + %cancel-loop cancel-loop == :: %reset-group-perms @@ -279,6 +281,25 @@ =/ cmd=c-channels:d [%channel nest %del-writers diff] =/ cage [%channel-command !>(cmd)] cr(cards [[%pass /groups/role %agent [p.q.nest %channels-server] %poke cage] cards.cr]) +++ test-loop + =/ =wire /test-loop + =/ =dock [our.bowl dap.bowl] + (emit [%pass wire %agent dock %watch wire]) +++ take-loop + |= =sign:agent:gall + ^+ cor + ?+ -.sign cor + %kick + ((subscribe /test-loop [our.bowl dap.bowl] /test-loop) &) + :: + %watch-ack + cor + == +++ cancel-loop + =^ card=(unit card) subs + (~(cancel s [subs bowl]) /test-loop) + ?~ card cor + (emit u.card) :: :: +load: load next state ++ load @@ -411,6 +432,7 @@ [%groups ~] cor [%groups %ui ~] cor [%gangs %updates ~] cor + [%test-loop ~] (give %kick ~[/test-loop] ~) :: [%epic ~] (give %fact ~ epic+!>(okay:g)) :: @@ -566,6 +588,7 @@ [%epic ~] (take-epic sign) [%helm *] cor [%groups %role ~] cor + [%test-loop ~] (take-loop sign) [?(%hark %groups %chat %heap %diary) ~] cor [%cast ship=@ name=@ ~] (take-cast [(slav %p ship.pole) name.pole] sign) :: @@ -605,9 +628,17 @@ == :: ++ arvo - |= [=wire sign=sign-arvo] + |= [=(pole knot) sign=sign-arvo] ^+ cor - !! + ?+ pole ~|(bad-arvo-take/pole !!) + [%~.~ %cancel-retry rest=*] cor + :: + [%~.~ %retry rest=*] + =^ card=(unit card) subs + (~(handle-wakeup s [subs bowl]) pole) + ?~ card cor + (emit u.card) + == :: ++ subscribe |= [=wire =dock =path] diff --git a/desk/lib/subscriber.hoon b/desk/lib/subscriber.hoon index 458160a323..19c06a1f4e 100644 --- a/desk/lib/subscriber.hoon +++ b/desk/lib/subscriber.hoon @@ -3,6 +3,7 @@ +$ sub $: =dock =path + fires-at=@da == :: +$ subs (map wire sub) @@ -14,9 +15,10 @@ |= =wire ^- [(unit card:agent:gall) _subs] ?> ?=([%~.~ %retry *] wire) + :: ~& ['waking up' wire] =/ sub (~(get by subs) t.t.wire) ?~ sub [~ subs] - :- `[%pass t.wire %agent dock.u.sub %watch path.u.sub] + :- `[%pass t.t.wire %agent dock.u.sub %watch path.u.sub] (~(del by subs) t.t.wire) ++ subscribe |= [=wire =dock =path delay=?] @@ -24,7 +26,18 @@ ?: (~(has by subs) wire) ((slog 'Duplicate subscription' >[wire dock]< ~) [~ subs]) ?. delay [`[%pass wire %agent dock %watch path] subs] - :_ (~(put by subs) wire [dock path]) - `[%pass (weld /~/retry wire) %arvo %b %wait (add now interval)] + :: ~& ['subscribing with delay' wire] + =/ fires-at (add now interval) + :_ (~(put by subs) wire [dock path fires-at]) + `[%pass (weld /~/retry wire) %arvo %b %wait fires-at] + ++ cancel + |= =wire + ^- [(unit card:agent:gall) _subs] + =/ sub (~(get by subs) wire) + ?~ sub + ((slog 'No such subscription' >[wire]< ~) [~ subs]) + :: ~& ['cancelling' wire] + :_ (~(del by subs) wire) + `[%pass (weld /~/cancel-retry wire) %arvo %b %rest fires-at.u.sub] -- -- \ No newline at end of file From 867fffd88ebf0f58980968786a862e619fa34e08 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Wed, 7 Feb 2024 18:58:48 -0600 Subject: [PATCH 03/11] subscriber: adding tests to verify --- desk/app/groups.hoon | 23 ----------------------- desk/tests/app/groups.hoon | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 23 deletions(-) create mode 100644 desk/tests/app/groups.hoon diff --git a/desk/app/groups.hoon b/desk/app/groups.hoon index b2c7396433..5248dccae3 100644 --- a/desk/app/groups.hoon +++ b/desk/app/groups.hoon @@ -102,8 +102,6 @@ ?+ q.vase !! %reset-all-perms reset-all-perms %verify-cabals verify-cabals - %test-loop test-loop - %cancel-loop cancel-loop == :: %reset-group-perms @@ -281,25 +279,6 @@ =/ cmd=c-channels:d [%channel nest %del-writers diff] =/ cage [%channel-command !>(cmd)] cr(cards [[%pass /groups/role %agent [p.q.nest %channels-server] %poke cage] cards.cr]) -++ test-loop - =/ =wire /test-loop - =/ =dock [our.bowl dap.bowl] - (emit [%pass wire %agent dock %watch wire]) -++ take-loop - |= =sign:agent:gall - ^+ cor - ?+ -.sign cor - %kick - ((subscribe /test-loop [our.bowl dap.bowl] /test-loop) &) - :: - %watch-ack - cor - == -++ cancel-loop - =^ card=(unit card) subs - (~(cancel s [subs bowl]) /test-loop) - ?~ card cor - (emit u.card) :: :: +load: load next state ++ load @@ -432,7 +411,6 @@ [%groups ~] cor [%groups %ui ~] cor [%gangs %updates ~] cor - [%test-loop ~] (give %kick ~[/test-loop] ~) :: [%epic ~] (give %fact ~ epic+!>(okay:g)) :: @@ -588,7 +566,6 @@ [%epic ~] (take-epic sign) [%helm *] cor [%groups %role ~] cor - [%test-loop ~] (take-loop sign) [?(%hark %groups %chat %heap %diary) ~] cor [%cast ship=@ name=@ ~] (take-cast [(slav %p ship.pole) name.pole] sign) :: diff --git a/desk/tests/app/groups.hoon b/desk/tests/app/groups.hoon new file mode 100644 index 0000000000..5fbaa4fed8 --- /dev/null +++ b/desk/tests/app/groups.hoon @@ -0,0 +1,32 @@ +/- g=groups +/+ *test-agent +/= groups-agent /app/groups +|% +++ dap %groups-test +++ the-wire /groups/(scot %p ~zod)/test/updates +++ the-path (weld the-wire /init) +++ the-dock [~zod dap] +++ the-group [%test 'test' '' '' '' [%open ~ ~] ~ |] +++ retry (weld /~/retry the-wire) +++ test-subscription-loop + %- eval-mare + =/ m (mare ,~) + :: init and add group + ;< * bind:m (do-init %groups-test groups-agent) + ;< * bind:m (jab-bowl |=(b=bowl b(our ~dev, src ~dev))) + ;< * bind:m (do-poke %group-join !>([[~zod %test] &])) + ;< * bind:m (jab-bowl |=(b=bowl b(our ~dev, src ~zod))) + ;< * bind:m (do-agent /gangs/(scot %p ~zod)/test/join/add the-dock %poke-ack ~) + ;< * bind:m (do-agent the-wire the-dock %watch-ack ~) + ;< bw=bowl bind:m get-bowl + =/ now=time now.bw + :: kick & resubscribe with delay + ;< caz=(list card) bind:m (do-agent the-wire the-dock %kick ~) + =/ next=time (add now ~s30) + ;< * bind:m + (ex-cards caz (ex-arvo retry %b %wait next) ~) + ;< * bind:m (jab-bowl |=(b=bowl b(now next))) + :: wakeup & resubscribe no delay + ;< caz=(list card) bind:m (do-arvo retry %behn %wake ~) + (ex-cards caz (ex-task the-wire the-dock %watch the-path) ~) +-- \ No newline at end of file From 3ff34a1e8ee9390fc156fd3b8b4ae85eb7f7f017 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Mon, 12 Feb 2024 11:26:49 -0600 Subject: [PATCH 04/11] subscriber: added to channels --- desk/app/channels.hoon | 75 ++++++++++++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 21 deletions(-) diff --git a/desk/app/channels.hoon b/desk/app/channels.hoon index 1a444e9127..c568df10c3 100644 --- a/desk/app/channels.hoon +++ b/desk/app/channels.hoon @@ -8,7 +8,7 @@ /- c=channels, g=groups, ha=hark /- meta /+ default-agent, verb, dbug, sparse, neg=negotiate -/+ utils=channel-utils, volume +/+ utils=channel-utils, volume, s=subscriber :: performance, keep warm /+ channel-json :: @@ -24,7 +24,7 @@ |% +$ card card:agent:gall +$ current-state - $: %2 + $: %3 =v-channels:c voc=(map [nest:c plan:c] (unit said:c)) pins=(list nest:c) ::TODO vestigial, in groups-ui now, remove me @@ -33,6 +33,8 @@ :: .pending-ref-edits: for migration, see also +poke %negotiate-notif :: pending-ref-edits=(jug ship [=kind:c name=term]) + :: delayed resubscribes + =^subs:s == -- =| current-state @@ -99,9 +101,13 @@ :: ++ safe-watch |= [=wire =dock =path] + |= delay=? ^+ cor ?: (~(has by wex.bowl) wire dock) cor - (emit %pass wire %agent dock %watch path) + =^ card=(unit card) subs + (~(subscribe s [subs bowl]) wire dock path delay) + ?~ card cor + (emit u.card) :: ++ load |= =vase @@ -109,13 +115,25 @@ =+ !<(old=versioned-state vase) =? old ?=(%0 -.old) (state-0-to-1 old) =? old ?=(%1 -.old) (state-1-to-2 old) - ?> ?=(%2 -.old) + =? old ?=(%2 -.old) (state-2-to-3 old) + ?> ?=(%3 -.old) =. state old inflate-io :: - +$ versioned-state $%(state-2 state-1 state-0) - +$ state-2 current-state + +$ versioned-state $%(state-3 state-2 state-1 state-0) + +$ state-3 current-state :: + +$ state-2 + $: %2 + =v-channels:c + voc=(map [nest:c plan:c] (unit said:c)) + pins=(list nest:c) ::TODO vestigial, in groups-ui now, remove me + hidden-posts=(set id-post:c) + :: + :: .pending-ref-edits: for migration, see also +poke %negotiate-notif + :: + pending-ref-edits=(jug ship [=kind:c name=term]) + == +$ state-1 $: %1 v-channels=(map nest:c v-channel-1) @@ -123,6 +141,12 @@ pins=(list nest:c) hidden-posts=(set id-post:c) == + ++ state-2-to-3 + |= s=state-2 + ^- state-3 + %= s - %3 + pending-ref-edits [pending-ref-edits.s ~] + == ++ v-channel-1 |^ ,[global local] +$ global @@ -289,13 +313,13 @@ :: :: watch all the subscriptions we expect to have :: - =. cor watch-groups + =. cor (watch-groups |) :: =. cor %+ roll ~(tap by v-channels) |= [[=nest:c *] core=_cor] - ca-abet:ca-safe-sub:(ca-abed:ca-core:core nest) + ca-abet:(ca-safe-sub:(ca-abed:ca-core:core nest) |) :: cor :: @@ -411,7 +435,7 @@ |= [=nest:c =plan:c] ?. (~(has by v-channels) nest) =/ wire (said-wire nest plan) - (safe-watch wire [ship.nest server] wire) + ((safe-watch wire [ship.nest server] wire) |) ::TODO not guaranteed to resolve, we might have partial backlog ca-abet:(ca-said:(ca-abed:ca-core nest) plan) :: @@ -476,7 +500,7 @@ :: [%groups ~] ?+ -.sign !! - %kick watch-groups + %kick (watch-groups &) %watch-ack ?~ p.sign cor @@ -566,8 +590,11 @@ ++ emit |=(=card ca-core(cor (^emit card))) ++ emil |=(caz=(list card) ca-core(cor (^emil caz))) ++ give |=(=gift:agent:gall ca-core(cor (^give gift))) - ++ safe-watch |=([=wire =dock =path] ca-core(cor (^safe-watch +<))) ++ ca-perms ~(. perms:utils our.bowl now.bowl nest group.perm.perm.channel) + ++ safe-watch + |= [=wire =dock =path] + |= delay=? + ca-core(cor ((^safe-watch wire dock path) delay)) ++ ca-abet %_ cor v-channels @@ -608,7 +635,7 @@ =. last-read.remark.channel now.bowl =. ca-core ca-give-unread =. ca-core (ca-response %join group) - ca-safe-sub + (ca-safe-sub |) :: :: handle an action from the client :: @@ -687,9 +714,11 @@ (~(has by wex.bowl) [ca-sub-wire ship.nest dap.bowl]) :: ++ ca-safe-sub + |= delay=? ?: ca-has-sub ca-core - ?^ posts.channel ca-start-updates + ?^ posts.channel (ca-start-updates delay) =. load.net.channel | + %. delay %^ safe-watch (weld ca-area /checkpoint) [ship.nest server] ?. =(our.bowl ship.nest) =/ count ?:(=(%diary kind.nest) '20' '100') @@ -697,9 +726,11 @@ /[kind.nest]/[name.nest]/checkpoint/time-range/(scot %da *@da) :: ++ ca-start-updates + |= delay=? :: not most optimal time, should maintain last heard time instead =/ tim=(unit time) (bind (ram:on-v-posts:c posts.channel) head) + %. delay %^ safe-watch ca-sub-wire [ship.nest server] /[kind.nest]/[name.nest]/updates/(scot %da (fall tim *@da)) :: @@ -726,7 +757,7 @@ =/ =wire (weld ca-area /create) (emit %pass wire %agent [our.bowl server] %watch path) :: - %kick ca-safe-sub + %kick (ca-safe-sub &) %watch-ack ?~ p.sign ca-core %- (slog leaf+"{}: Failed creation" u.p.sign) @@ -741,14 +772,14 @@ =. ca-core ca-give-unread =. ca-core (emit %pass (weld ca-area /create) %agent [ship.nest server] %leave ~) - ca-safe-sub + (ca-safe-sub |) == :: ++ ca-take-update |= =sign:agent:gall ^+ ca-core ?+ -.sign ca-core - %kick ca-safe-sub + %kick (ca-safe-sub &) %watch-ack ?~ p.sign ca-core %- (slog leaf+"{}: Failed subscription" u.p.sign) @@ -767,7 +798,7 @@ ^+ ca-core ?+ -.sign ca-core :: only if kicked prematurely - %kick ?:(load.net.channel ca-core ca-safe-sub) + %kick ?:(load.net.channel ca-core (ca-safe-sub &)) %watch-ack ?~ p.sign ca-core %- (slog leaf+"{}: Failed partial checkpoint" u.p.sign) @@ -786,7 +817,7 @@ ^+ ca-core ?+ -.sign ca-core :: only hit if kicked prematurely (we %leave after the first %fact) - %kick ca-sync-backlog + %kick (ca-sync-backlog &) %watch-ack ?~ p.sign ca-core %- (slog leaf+"{}: Failed backlog" u.p.sign) @@ -805,9 +836,9 @@ ^+ ca-core =. load.net.channel & =. ca-core (ca-apply-checkpoint chk &) - =. ca-core ca-start-updates + =. ca-core (ca-start-updates |) =. ca-core (ca-fetch-contacts chk) - =. ca-core ca-sync-backlog + =. ca-core (ca-sync-backlog |) =/ wire (weld ca-area /checkpoint) (emit %pass wire %agent [ship.nest server] %leave ~) :: @@ -848,8 +879,10 @@ ca-core :: ++ ca-sync-backlog + |= delay=? =/ checkpoint-start (pry:on-v-posts:c posts.channel) ?~ checkpoint-start ca-core + %. delay %^ safe-watch (weld ca-area /backlog) [ship.nest server] %+ welp /[kind.nest]/[name.nest]/checkpoint/time-range @@ -1565,7 +1598,7 @@ ++ ca-recheck |= sects=(set sect:g) :: if our read permissions restored, re-subscribe - ?: (can-read:ca-perms our.bowl) ca-safe-sub + ?: (can-read:ca-perms our.bowl) (ca-safe-sub |) ca-core :: :: assorted helpers From 979b16be80b94089c2befa24ccb65a643c92883c Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Mon, 12 Feb 2024 19:16:38 -0600 Subject: [PATCH 05/11] channels: adding test for core subscriptions --- desk/app/channels.hoon | 18 ++++++++- desk/tests/app/channels.hoon | 78 ++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 desk/tests/app/channels.hoon diff --git a/desk/app/channels.hoon b/desk/app/channels.hoon index c568df10c3..666697e01b 100644 --- a/desk/app/channels.hoon +++ b/desk/app/channels.hoon @@ -85,8 +85,9 @@ ++ on-arvo |= [=wire sign=sign-arvo] ^- (quip card _this) - ~& strange-diary-arvo+wire - `this + =^ cards state + abet:(arvo:cor wire sign) + [cards this] -- |_ [=bowl:gall cards=(list card)] ++ abet [(flop cards) state] @@ -569,6 +570,19 @@ ``loob+!>((~(has by v-channels) kind.pole ship name.pole)) == :: +++ arvo + |= [=(pole knot) sign=sign-arvo] + ^+ cor + ?+ pole ~|(bad-arvo-take/pole !!) + [%~.~ %cancel-retry rest=*] cor + :: + [%~.~ %retry rest=*] + =^ card=(unit card) subs + (~(handle-wakeup s [subs bowl]) pole) + ?~ card cor + (emit u.card) + == +:: ++ unreads ^- unreads:c %- ~(gas by *unreads:c) diff --git a/desk/tests/app/channels.hoon b/desk/tests/app/channels.hoon new file mode 100644 index 0000000000..416d90d6e1 --- /dev/null +++ b/desk/tests/app/channels.hoon @@ -0,0 +1,78 @@ +/- g=groups, c=channels +/+ *test-agent +/= channels-agent /app/channels +|% +++ dap %channels-test +++ server-dap %channels-test-server +++ negotiate /~/negotiate/inner-watch/~zod/[server-dap] +++ sub-wire /chat/(scot %p ~zod)/test +++ negotiate-wire (weld negotiate /chat/(scot %p ~zod)/test) +++ chk-wire (weld negotiate-wire /checkpoint) +++ chk-path /chat/test/checkpoint/before/100 +++ the-dock [~zod server-dap] +++ the-nest [%chat ~zod %test] +++ the-group [~zod %test] +++ test-checkpoint-sub + %- eval-mare + =/ m (mare ,~) + ;< * bind:m channel-join + =/ retry (weld /~/retry (weld sub-wire /checkpoint)) + (check-subscription-loop chk-wire chk-wire the-dock chk-path retry) +++ test-updates-sub + %- eval-mare + =/ m (mare ,~) + ;< * bind:m channel-join + :: get checkpoint and start updates + =/ =cage [%channel-checkpoint !>(*u-checkpoint:c)] + ;< * bind:m (do-agent chk-wire the-dock %fact cage) + =/ updates-wire (weld negotiate-wire /updates) + :: kicking updates retries back to checkpoint + =/ updates-retry (weld /~/retry (weld sub-wire /checkpoint)) + ;< * bind:m (do-agent updates-wire the-dock %watch-ack ~) + (check-subscription-loop updates-wire chk-wire the-dock chk-path updates-retry) +++ test-backlog-sub + %- eval-mare + =/ m (mare ,~) + ;< * bind:m channel-join + ;< bw=bowl bind:m get-bowl + :: get checkpoint and start updates + =/ last-post-time (add now.bw 1) + =/ last-post=v-post:c + :- [last-post-time ~ ~] + [0 [[~ ~dev last-post-time] %chat ~]] + =/ posts=v-posts:c + (gas:on-v-posts:c *v-posts:c ~[[last-post-time `last-post]]) + =/ checkpoint *u-checkpoint:c + =/ =cage [%channel-checkpoint !>(checkpoint(posts posts))] + ;< * bind:m (do-agent chk-wire the-dock %fact cage) + =/ backlog-wire (weld negotiate-wire /backlog) + =/ backlog-path + %+ welp /chat/test/checkpoint/time-range + /(scot %da *@da)/(scot %da last-post-time) + =/ backlog-retry (weld /~/retry (weld sub-wire /backlog)) + ;< * bind:m (do-agent backlog-wire the-dock %watch-ack ~) + (check-subscription-loop backlog-wire backlog-wire the-dock backlog-path backlog-retry) +++ check-subscription-loop + |= [sub=wire resub=wire =dock =path retry-wire=wire] + =/ m (mare ,~) + ^- form:m + ;< bw=bowl bind:m get-bowl + =/ now=time now.bw + :: kick & resubscribe with delay + ;< caz=(list card) bind:m (do-agent sub dock %kick ~) + =/ next=time (add now ~s30) + ;< * bind:m + (ex-cards caz (ex-arvo retry-wire %b %wait next) ~) + ;< * bind:m (jab-bowl |=(b=bowl b(now next))) + :: wakeup & resubscribe no delay + ;< caz=(list card) bind:m (do-arvo retry-wire %behn %wake ~) + (ex-cards caz (ex-task resub dock %watch path) ~) +++ channel-join + =/ m (mare ,(list card)) + ^- form:m + :: join channel + ;< * bind:m (do-init dap channels-agent) + ;< * bind:m (jab-bowl |=(b=bowl b(our ~dev, src ~dev))) + ;< * bind:m (do-poke %channel-action !>([%channel the-nest %join the-group])) + (do-agent chk-wire the-dock %watch-ack ~) +-- \ No newline at end of file From 51b0581cb4721eb9a06fd4c26e0b40229ea3840b Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Thu, 15 Feb 2024 11:22:16 -0600 Subject: [PATCH 06/11] subscriber: correct unsubscribe behavior --- desk/lib/subscriber.hoon | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/desk/lib/subscriber.hoon b/desk/lib/subscriber.hoon index 19c06a1f4e..6f2f1fb4bb 100644 --- a/desk/lib/subscriber.hoon +++ b/desk/lib/subscriber.hoon @@ -8,6 +8,7 @@ :: +$ subs (map wire sub) :: +++ verb | ++ subscriber |_ [=subs bowl:gall] ++ interval ~s30 @@ -15,7 +16,7 @@ |= =wire ^- [(unit card:agent:gall) _subs] ?> ?=([%~.~ %retry *] wire) - :: ~& ['waking up' wire] + ~? verb ['waking up' wire] =/ sub (~(get by subs) t.t.wire) ?~ sub [~ subs] :- `[%pass t.t.wire %agent dock.u.sub %watch path.u.sub] @@ -26,18 +27,20 @@ ?: (~(has by subs) wire) ((slog 'Duplicate subscription' >[wire dock]< ~) [~ subs]) ?. delay [`[%pass wire %agent dock %watch path] subs] - :: ~& ['subscribing with delay' wire] + ~? verb ['subscribing with delay' wire] =/ fires-at (add now interval) :_ (~(put by subs) wire [dock path fires-at]) `[%pass (weld /~/retry wire) %arvo %b %wait fires-at] - ++ cancel + ++ unsubscribe |= =wire - ^- [(unit card:agent:gall) _subs] + ^- [(list card:agent:gall) _subs] =/ sub (~(get by subs) wire) ?~ sub ((slog 'No such subscription' >[wire]< ~) [~ subs]) - :: ~& ['cancelling' wire] + ~? verb ['cancelling' wire] :_ (~(del by subs) wire) - `[%pass (weld /~/cancel-retry wire) %arvo %b %rest fires-at.u.sub] + :~ [%pass (weld /~/cancel-retry wire) %arvo %b %rest fires-at.u.sub] + [%pass wire %agent dock.u.sub %leave ~] + == -- -- \ No newline at end of file From 85f5c1ed5cb68f854af494a716f5929db4d51d07 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Fri, 16 Feb 2024 15:25:29 -0600 Subject: [PATCH 07/11] subscriber: add unsubscribe usage and test --- desk/app/channels.hoon | 12 +++++------- desk/app/groups.hoon | 20 +++++++++---------- desk/lib/subscriber.hoon | 17 ++++++++-------- desk/tests/app/groups.hoon | 40 +++++++++++++++++++++++++++++++------- 4 files changed, 57 insertions(+), 32 deletions(-) diff --git a/desk/app/channels.hoon b/desk/app/channels.hoon index 666697e01b..8c414c23d2 100644 --- a/desk/app/channels.hoon +++ b/desk/app/channels.hoon @@ -105,10 +105,9 @@ |= delay=? ^+ cor ?: (~(has by wex.bowl) wire dock) cor - =^ card=(unit card) subs + =^ caz=(list card) subs (~(subscribe s [subs bowl]) wire dock path delay) - ?~ card cor - (emit u.card) + (emil caz) :: ++ load |= =vase @@ -146,7 +145,7 @@ |= s=state-2 ^- state-3 %= s - %3 - pending-ref-edits [pending-ref-edits.s ~] + pending-ref-edits [pending-ref-edits.s *^subs:^s] == ++ v-channel-1 |^ ,[global local] @@ -577,10 +576,9 @@ [%~.~ %cancel-retry rest=*] cor :: [%~.~ %retry rest=*] - =^ card=(unit card) subs + =^ caz=(list card) subs (~(handle-wakeup s [subs bowl]) pole) - ?~ card cor - (emit u.card) + (emil caz) == :: ++ unreads diff --git a/desk/app/groups.hoon b/desk/app/groups.hoon index 5248dccae3..0db8164da1 100644 --- a/desk/app/groups.hoon +++ b/desk/app/groups.hoon @@ -356,7 +356,7 @@ ++ state-2-to-3 |= state-2 ^- current-state - [%3 groups volume xeno shoal ~] + [%3 groups volume xeno shoal *^subs:s] :: ++ groups-1-to-2 |= groups=net-groups:zero @@ -611,19 +611,17 @@ [%~.~ %cancel-retry rest=*] cor :: [%~.~ %retry rest=*] - =^ card=(unit card) subs + =^ caz=(list card) subs (~(handle-wakeup s [subs bowl]) pole) - ?~ card cor - (emit u.card) + (emil caz) == :: ++ subscribe |= [=wire =dock =path] |= delay=? - =^ card=(unit card) subs + =^ caz=(list card) subs (~(subscribe s [subs bowl]) wire dock path delay) - ?~ card cor - (emit u.card) + (emil caz) :: ++ cast |= [grp=flag:g gra=flag:g] @@ -818,7 +816,7 @@ (~(del by groups) flag) (~(put by groups) flag net group) ?. gone cor - =? cor !=(p.flag our.bowl) (emit leave:go-pass) + =? cor !=(p.flag our.bowl) (emil leave:go-pass) =/ =action:g [flag now.bowl %del ~] (give %fact ~[/groups/ui] act:mar:g !>(action)) ++ go-abed @@ -868,10 +866,12 @@ ++ go-pass |% ++ leave - ^- card + ^- (list card) =/ =wire (snoc go-area %updates) =/ =dock [p.flag dap.bowl] - [%pass wire %agent dock %leave ~] + =^ caz=(list card) subs + (~(unsubscribe s [subs bowl]) wire dock) + caz :: ++ remove-self ^- card diff --git a/desk/lib/subscriber.hoon b/desk/lib/subscriber.hoon index 6f2f1fb4bb..62c3737fe7 100644 --- a/desk/lib/subscriber.hoon +++ b/desk/lib/subscriber.hoon @@ -14,33 +14,34 @@ ++ interval ~s30 ++ handle-wakeup |= =wire - ^- [(unit card:agent:gall) _subs] + ^- [(list card:agent:gall) _subs] ?> ?=([%~.~ %retry *] wire) ~? verb ['waking up' wire] =/ sub (~(get by subs) t.t.wire) ?~ sub [~ subs] - :- `[%pass t.t.wire %agent dock.u.sub %watch path.u.sub] + :- ~[[%pass t.t.wire %agent dock.u.sub %watch path.u.sub]] (~(del by subs) t.t.wire) ++ subscribe |= [=wire =dock =path delay=?] - ^- [(unit card:agent:gall) _subs] + ^- [(list card:agent:gall) _subs] ?: (~(has by subs) wire) ((slog 'Duplicate subscription' >[wire dock]< ~) [~ subs]) - ?. delay [`[%pass wire %agent dock %watch path] subs] + ?. delay [~[[%pass wire %agent dock %watch path]] subs] ~? verb ['subscribing with delay' wire] =/ fires-at (add now interval) :_ (~(put by subs) wire [dock path fires-at]) - `[%pass (weld /~/retry wire) %arvo %b %wait fires-at] + ~[[%pass (weld /~/retry wire) %arvo %b %wait fires-at]] ++ unsubscribe - |= =wire + |= [=wire =dock] ^- [(list card:agent:gall) _subs] + =/ leave [%pass wire %agent dock %leave ~] =/ sub (~(get by subs) wire) ?~ sub ((slog 'No such subscription' >[wire]< ~) [~ subs]) ~? verb ['cancelling' wire] :_ (~(del by subs) wire) - :~ [%pass (weld /~/cancel-retry wire) %arvo %b %rest fires-at.u.sub] - [%pass wire %agent dock.u.sub %leave ~] + :~ [%pass (weld /~/retry wire) %arvo %b %rest fires-at.u.sub] + leave == -- -- \ No newline at end of file diff --git a/desk/tests/app/groups.hoon b/desk/tests/app/groups.hoon index 5fbaa4fed8..e81dbe2dfe 100644 --- a/desk/tests/app/groups.hoon +++ b/desk/tests/app/groups.hoon @@ -3,30 +3,56 @@ /= groups-agent /app/groups |% ++ dap %groups-test -++ the-wire /groups/(scot %p ~zod)/test/updates -++ the-path (weld the-wire /init) +++ the-wire /groups/(scot %p ~zod)/test +++ updates-wire (weld the-wire /updates) +++ the-path (weld updates-wire /init) ++ the-dock [~zod dap] ++ the-group [%test 'test' '' '' '' [%open ~ ~] ~ |] -++ retry (weld /~/retry the-wire) +++ flag [~zod %test] +++ retry (weld /~/retry updates-wire) ++ test-subscription-loop %- eval-mare =/ m (mare ,~) :: init and add group ;< * bind:m (do-init %groups-test groups-agent) ;< * bind:m (jab-bowl |=(b=bowl b(our ~dev, src ~dev))) - ;< * bind:m (do-poke %group-join !>([[~zod %test] &])) + ;< * bind:m (do-poke %group-join !>([flag &])) ;< * bind:m (jab-bowl |=(b=bowl b(our ~dev, src ~zod))) ;< * bind:m (do-agent /gangs/(scot %p ~zod)/test/join/add the-dock %poke-ack ~) - ;< * bind:m (do-agent the-wire the-dock %watch-ack ~) + ;< * bind:m (do-agent updates-wire the-dock %watch-ack ~) ;< bw=bowl bind:m get-bowl =/ now=time now.bw :: kick & resubscribe with delay - ;< caz=(list card) bind:m (do-agent the-wire the-dock %kick ~) + ;< caz=(list card) bind:m (do-agent updates-wire the-dock %kick ~) =/ next=time (add now ~s30) ;< * bind:m (ex-cards caz (ex-arvo retry %b %wait next) ~) ;< * bind:m (jab-bowl |=(b=bowl b(now next))) :: wakeup & resubscribe no delay ;< caz=(list card) bind:m (do-arvo retry %behn %wake ~) - (ex-cards caz (ex-task the-wire the-dock %watch the-path) ~) + (ex-cards caz (ex-task updates-wire the-dock %watch the-path) ~) +++ test-unsubscribe + %- eval-mare + =/ m (mare ,~) + :: init and add group + ;< * bind:m (do-init %groups-test groups-agent) + ;< * bind:m (jab-bowl |=(b=bowl b(our ~dev, src ~dev))) + ;< * bind:m (do-poke %group-join !>([flag &])) + ;< * bind:m (jab-bowl |=(b=bowl b(our ~dev, src ~zod))) + ;< * bind:m (do-agent /gangs/(scot %p ~zod)/test/join/add the-dock %poke-ack ~) + ;< * bind:m (do-agent updates-wire the-dock %watch-ack ~) + ;< bw=bowl bind:m get-bowl + =/ now=time now.bw + :: kick & resubscribe with delay + ;< caz=(list card) bind:m (do-agent updates-wire the-dock %kick ~) + =/ next=time (add now ~s30) + ;< caz=(list card) bind:m (do-poke %group-leave !>(flag)) + =/ remove-vase !>([flag now %fleet (silt ~dev ~) %del ~]) + %+ ex-cards caz + :~ (ex-poke (weld the-wire /proxy) the-dock act:mar:g remove-vase) + (ex-fact ~[/groups /groups/ui] %group-leave !>(flag)) + (ex-arvo retry %b %rest next) + (ex-task updates-wire the-dock %leave ~) + (ex-fact ~[/groups/ui] act:mar:g !>([flag now %del ~])) + == -- \ No newline at end of file From 8355629d857cb1f3cf9c933a26e7e122eaec931e Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Fri, 16 Feb 2024 15:33:34 -0600 Subject: [PATCH 08/11] groups: remove whitespace --- desk/app/groups.hoon | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/desk/app/groups.hoon b/desk/app/groups.hoon index 0db8164da1..f889939eac 100644 --- a/desk/app/groups.hoon +++ b/desk/app/groups.hoon @@ -20,7 +20,7 @@ $= volume $: base=level:v area=(map flag:g level:v) :: override per group - chan=(map nest:g level:v) :: override per channel + chan=(map nest:g level:v) :: override per channel == :: xeno=gangs:g @@ -336,7 +336,7 @@ $= volume $: base=level:v area=(map flag:g level:v) :: override per group - chan=(map nest:g level:v) :: override per channel + chan=(map nest:g level:v) :: override per channel == :: xeno=gangs:g From 13d776ebf1e2c91d8f29c7c3afa6a519c9288500 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Tue, 20 Feb 2024 15:35:45 -0600 Subject: [PATCH 09/11] subscriber: make sure we still pass leave in no sub case --- desk/lib/subscriber.hoon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desk/lib/subscriber.hoon b/desk/lib/subscriber.hoon index 62c3737fe7..51c89583ae 100644 --- a/desk/lib/subscriber.hoon +++ b/desk/lib/subscriber.hoon @@ -37,7 +37,7 @@ =/ leave [%pass wire %agent dock %leave ~] =/ sub (~(get by subs) wire) ?~ sub - ((slog 'No such subscription' >[wire]< ~) [~ subs]) + ((slog 'No such subscription' >[wire]< ~) [~[leave] subs]) ~? verb ['cancelling' wire] :_ (~(del by subs) wire) :~ [%pass (weld /~/retry wire) %arvo %b %rest fires-at.u.sub] From 9e5357aed5081847b69badcaf2b6ec562c3fb822 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Wed, 21 Feb 2024 14:12:33 -0600 Subject: [PATCH 10/11] channels: using subscriber library --- desk/app/channels.hoon | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/desk/app/channels.hoon b/desk/app/channels.hoon index 8c414c23d2..57eedfe901 100644 --- a/desk/app/channels.hoon +++ b/desk/app/channels.hoon @@ -266,6 +266,12 @@ :: happen. that way, local subs get established without issue. inflate-io :: +++ unsubscribe + |= [=wire =dock] + ^+ cor + =^ caz=(list card) subs + (~(unsubscribe s [subs bowl]) wire dock) + (emil caz) ++ inflate-io :: initiate version negotiation with our own channels-server :: @@ -309,7 +315,7 @@ =(wire path) == ?: keep cor - (emit %pass pole %agent [sub-ship dude] %leave ~) + (unsubscribe pole [sub-ship dude]) :: :: watch all the subscriptions we expect to have :: @@ -607,6 +613,9 @@ |= [=wire =dock =path] |= delay=? ca-core(cor ((^safe-watch wire dock path) delay)) + ++ unsubscribe + |= [=wire =dock] + ca-core(cor (^unsubscribe wire dock)) ++ ca-abet %_ cor v-channels @@ -767,7 +776,7 @@ ~ =/ =path /[kind.nest]/[name.nest]/create =/ =wire (weld ca-area /create) - (emit %pass wire %agent [our.bowl server] %watch path) + ((safe-watch wire [our.bowl server] path) |) :: %kick (ca-safe-sub &) %watch-ack @@ -782,8 +791,7 @@ =+ !<(=update:c q.cage) =. ca-core (ca-u-channels update) =. ca-core ca-give-unread - =. ca-core - (emit %pass (weld ca-area /create) %agent [ship.nest server] %leave ~) + =. ca-core (unsubscribe (weld ca-area /create) [ship.nest server]) (ca-safe-sub |) == :: @@ -852,7 +860,7 @@ =. ca-core (ca-fetch-contacts chk) =. ca-core (ca-sync-backlog |) =/ wire (weld ca-area /checkpoint) - (emit %pass wire %agent [ship.nest server] %leave ~) + (unsubscribe wire [ship.nest server]) :: ++ ca-fetch-contacts |= chk=u-checkpoint:c @@ -905,7 +913,7 @@ |= chk=u-checkpoint:c =. ca-core (ca-apply-checkpoint chk |) =/ wire (weld ca-area /backlog) - (emit %pass wire %agent [ship.nest server] %leave ~) + (unsubscribe wire [ship.nest server]) :: ++ ca-apply-logs |= =log:c @@ -1128,7 +1136,7 @@ =/ =rope:ha (ca-rope -.kind-data.post id-post ~) ?: (was-mentioned:utils content.post our.bowl) ?. (want-hark %mention) - ca-core + ca-core =/ cs=(list content:ha) ~[[%ship author.post] ' mentioned you: ' (flatten:utils content.post)] (emit (pass-hark (ca-spin rope cs ~))) @@ -1620,7 +1628,7 @@ :: leave the subscription only :: ++ ca-simple-leave - (emit %pass ca-sub-wire %agent [ship.nest server] %leave ~) + (unsubscribe ca-sub-wire [ship.nest server]) :: :: Leave the subscription, tell people about it, and delete our local :: state for the channel From e8233e7f3c6fbef5724b9510725d97452cb0a61e Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Wed, 21 Feb 2024 14:42:40 -0600 Subject: [PATCH 11/11] subscriber: adding comments clarifying intentions --- desk/app/channels.hoon | 3 +++ desk/app/groups.hoon | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/desk/app/channels.hoon b/desk/app/channels.hoon index 57eedfe901..571658bd0a 100644 --- a/desk/app/channels.hoon +++ b/desk/app/channels.hoon @@ -5,6 +5,9 @@ :: XX chat thread entries can no longer be edited. maybe fix before :: release? :: +:: note: all subscriptions are handled by the subscriber library so +:: we can have resubscribe loop protection. +:: /- c=channels, g=groups, ha=hark /- meta /+ default-agent, verb, dbug, sparse, neg=negotiate diff --git a/desk/app/groups.hoon b/desk/app/groups.hoon index f889939eac..8affdd7860 100644 --- a/desk/app/groups.hoon +++ b/desk/app/groups.hoon @@ -1,3 +1,8 @@ +:: groups: agent for managing group membership, metadata and permissions +:: +:: note: all subscriptions are handled by the subscriber library so +:: we can have resubscribe loop protection. +:: /- g=groups, zero=groups-0, ha=hark, h=heap, d=channels, c=chat, tac=contacts /- meta /- e=epic