From 24b4f41a1658219deb34d97ef938c2b26cdb75da Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 9 Apr 2024 15:27:49 +0000 Subject: [PATCH 01/18] update glob: [skip actions] --- desk/desk.docket-0 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desk/desk.docket-0 b/desk/desk.docket-0 index 5798d342..2c7fc72b 100644 --- a/desk/desk.docket-0 +++ b/desk/desk.docket-0 @@ -1,7 +1,7 @@ :~ title+'Landscape' info+'An app launcher for Urbit.' color+0xee.5432 - glob-http+['https://bootstrap.urbit.org/glob-0v2.2j09f.su13i.4sjhg.eihlk.9kn8b.glob' 0v2.2j09f.su13i.4sjhg.eihlk.9kn8b] + glob-http+['https://bootstrap.urbit.org/glob-0v7.the2a.smdhg.89k09.6ar0t.gb5te.glob' 0v7.the2a.smdhg.89k09.6ar0t.gb5te] ::glob-ames+~zod^0v0 base+'landscape' version+[1 25 0] From 1addbe96a61220e941fd5e67fcf4d20cf7eab86b Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Fri, 31 May 2024 12:44:50 -0500 Subject: [PATCH 02/18] Add %settings-data and %credentials to mark-warmer --- desk/lib/mark-warmer.hoon | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/desk/lib/mark-warmer.hoon b/desk/lib/mark-warmer.hoon index 4b482d1f..31b1df55 100644 --- a/desk/lib/mark-warmer.hoon +++ b/desk/lib/mark-warmer.hoon @@ -3,4 +3,6 @@ /$ skeins %hark-skeins %json /$ carpet %hark-carpet %json /$ blanket %hark-blanket %json -~ \ No newline at end of file +/$ settings %settings-data %json +/$ creds %credentials %json +~ From b0aab578225de313ea71e28c1db56fb089694761 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Fri, 31 May 2024 12:47:24 -0500 Subject: [PATCH 03/18] Add %configuration to the mark warmer --- desk/lib/mark-warmer.hoon | 1 + 1 file changed, 1 insertion(+) diff --git a/desk/lib/mark-warmer.hoon b/desk/lib/mark-warmer.hoon index 31b1df55..374b78b3 100644 --- a/desk/lib/mark-warmer.hoon +++ b/desk/lib/mark-warmer.hoon @@ -5,4 +5,5 @@ /$ blanket %hark-blanket %json /$ settings %settings-data %json /$ creds %credentials %json +/% config %configuration %json ~ From bf55d6e32bc0161511376ab729c9fa8cac5c93c4 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Fri, 31 May 2024 12:57:19 -0500 Subject: [PATCH 04/18] fix name issue --- desk/lib/mark-warmer.hoon | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/desk/lib/mark-warmer.hoon b/desk/lib/mark-warmer.hoon index 374b78b3..ca97f1c2 100644 --- a/desk/lib/mark-warmer.hoon +++ b/desk/lib/mark-warmer.hoon @@ -4,6 +4,5 @@ /$ carpet %hark-carpet %json /$ blanket %hark-blanket %json /$ settings %settings-data %json -/$ creds %credentials %json -/% config %configuration %json +/$ creds %update %json ~ From 6cd2dddbd4f247e1e4f90727ddd70632e712cea9 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Fri, 14 Jun 2024 12:29:09 -0500 Subject: [PATCH 05/18] add storage-update to mark warmer --- desk/lib/mark-warmer.hoon | 1 + 1 file changed, 1 insertion(+) diff --git a/desk/lib/mark-warmer.hoon b/desk/lib/mark-warmer.hoon index ca97f1c2..0bf6264f 100644 --- a/desk/lib/mark-warmer.hoon +++ b/desk/lib/mark-warmer.hoon @@ -5,4 +5,5 @@ /$ blanket %hark-blanket %json /$ settings %settings-data %json /$ creds %update %json +/$ storage %storage-update %json ~ From 9bae4ae1127024ceade3915e522eb48067be362e Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Tue, 27 Aug 2024 17:34:27 -0500 Subject: [PATCH 06/18] reel: updating to new flow with tests --- desk/app/reel.hoon | 159 +++++++++++---- desk/lib/test-agent.hoon | 421 +++++++++++++++++++++++++++++++++++++++ desk/sur/reel.hoon | 2 + desk/tests/app/reel.hoon | 120 +++++++++++ 4 files changed, 664 insertions(+), 38 deletions(-) create mode 100644 desk/lib/test-agent.hoon create mode 100644 desk/tests/app/reel.hoon diff --git a/desk/app/reel.hoon b/desk/app/reel.hoon index a51b554e..18fb3c2d 100644 --- a/desk/app/reel.hoon +++ b/desk/app/reel.hoon @@ -7,12 +7,16 @@ state-1 state-2 state-3 + state-4 == :: :: vic: URL of bait service :: civ: @p of bait service -:: our-metadata: map from tokens to their metadata -:: outstanding-pokes: ships we have poked and await a response from +:: our-metadata: a mapping from nonce/token to metadata +:: open-link-requests: open requests for an existing foreign link, DEPRECATED +:: open-describes: attempts to create a link waiting to be assigned a token +:: stable-id: a mapping from something the client can use to identify the +:: metadata to nonce and/or token :: +$ state-0 $: %0 @@ -40,11 +44,21 @@ our-metadata=(map cord metadata:reel) outstanding-pokes=(set (pair ship cord)) == ++$ state-4 + $: %4 + vic=@t + civ=ship + our-metadata=(map cord metadata:reel) + open-link-requests=(set (pair ship cord)) + open-describes=(set cord) + stable-id=(map cord cord) + == +:: url with old style token ++ url-for-token - |= [vic=cord our=ship token=cord] - (crip "{(trip vic)}{(trip (scot %p our))}/{(trip token)}") + |= [vic=cord token=cord] + (cat 3 vic token) -- -=| state-3 +=| state-4 =* state - :: %- agent:dbug @@ -63,14 +77,16 @@ ^- (quip card _this) =/ old !<(versioned-state old-state) ?- -.old - %3 + %4 `this(state old) + %3 + `this(state [%4 vic.old civ.old our-metadata.old outstanding-pokes.old ~ ~]) %2 - `this(state [%3 vic.old civ.old our-metadata.old ~]) + `this(state [%4 vic.old civ.old our-metadata.old ~ ~ ~]) %1 - `this(state [%3 'https://tlon.network/lure/' ~loshut-lonreg ~ ~]) + `this(state [%4 'https://tlon.network/lure/' ~loshut-lonreg ~ ~ ~ ~]) %0 - `this(state [%3 'https://tlon.network/lure/' ~loshut-lonreg ~ ~]) + `this(state [%4 'https://tlon.network/lure/' ~loshut-lonreg ~ ~ ~ ~]) == :: ++ on-poke @@ -85,7 +101,9 @@ :_ this(vic vic.command) ~[[%pass /set-ship %arvo %k %fard q.byk.bowl %reel-set-ship %noun !>(vic.command)]] %set-ship - :_ this(civ civ.command) + :: since we're changing providers, we need to regenerate links + :: we'll use whatever key we currently have as the nonce + :_ this(civ civ.command, open-describes ~(key by our-metadata)) %+ turn ~(tap by our-metadata) |= [token=cord =metadata:reel] ^- card @@ -93,24 +111,61 @@ == :: %reel-bite + ?> =(civ src.bowl) =+ !<(=bite:reel vase) [[%give %fact ~[/bites] mark !>(bite)]~ this] :: %reel-describe + ?> =(our.bowl src.bowl) =+ !<([token=cord =metadata:reel] vase) - :_ this(our-metadata (~(put by our-metadata) token metadata)) - ~[[%pass /describe %agent [civ %bait] %poke %bait-describe !>([token metadata])]] + :: the token here is a temporary identifier for the metadata + :: a new one will be assigned by the bait provider and returned to us + =/ new-fields (~(put by fields.metadata) 'bite-type' '2') + =/ nonce=cord (scot %da now.bowl) + =. our-metadata (~(put by our-metadata) nonce metadata(fields new-fields)) + =. open-describes (~(put in open-describes) nonce) + =. stable-id (~(put by stable-id) token nonce) + :_ this + ~[[%pass /describe %agent [civ %bait] %poke %bait-describe !>([nonce metadata])]] + :: + %reel-confirmation + ?> =(civ src.bowl) + =+ !<(confirmation:reel vase) + =. open-describes (~(del in open-describes) nonce) + ?~ md=(~(get by our-metadata) nonce) + ~|("no metadata for nonce: {}" !!) + =/ ids=(list [id=cord token=cord]) + %+ skim + ~(tap by stable-id) + |= [key=cord token=cord] + =(nonce token) + ?~ ids + ~|("no stable id for nonce: {}" !!) + =* id -<.ids + :: update the token the id points to + =. stable-id (~(put by stable-id) id token) + :: swap out the nonce for the token in our-metadata + =. our-metadata + (~(put by (~(del by our-metadata) nonce)) token u.md) + `this + :: %reel-undescribe + ?> =(our.bowl src.bowl) =+ !<(token=cord vase) + :: the token here should be the actual token given to us by the provider :_ this(our-metadata (~(del by our-metadata) token)) ~[[%pass /undescribe %agent [civ %bait] %poke %bait-undescribe !>(token)]] + :: old pokes for getting links, we no longer use these because all links + :: are unique to that ship/user and can be scried out + :: %reel-want-token-link =+ !<(token=cord vase) :_ this =/ result=(unit [cord cord]) ?. (~(has by our-metadata) token) ~ - `[token (url-for-token vic our.bowl token)] - ~[[%pass [%token-link-want token ~] %agent [src.bowl %reel] %poke %reel-give-token-link !>(result)]] + `[token (url-for-token vic token)] + ~[[%pass [%token-link-want token ~] %agent [src dap]:bowl %poke %reel-give-token-link !>(result)]] + :: %reel-give-token-link =+ !<(result=(unit [cord cord]) vase) ?~ result `this @@ -122,43 +177,69 @@ ++ on-agent |= [=wire =sign:agent:gall] ^- (quip card _this) - ?: ?=([%token-link @ @ ~] wire) + =/ =(pole knot) wire + ?+ pole (on-agent:def wire sign) + [%token-link @ name=@ ~] ?+ -.sign (on-agent:def wire sign) %poke-ack - `this(outstanding-pokes (~(del in outstanding-pokes) [src.bowl i.t.t.wire])) + `this(open-link-requests (~(del in open-link-requests) [src.bowl name.pole])) == - (on-agent:def wire sign) + == :: ++ on-watch - |= =path + |= =(pole knot) ^- (quip card _this) ?> =(our.bowl src.bowl) - ?+ path (on-watch:def path) - [%bites ~] `this - [%token-link @ @ ~] - =/ target (slav %p i.t.path) - =/ group i.t.t.path - ?~ (~(has in outstanding-pokes) [target group]) `this - :_ this(outstanding-pokes (~(put in outstanding-pokes) [target group])) - :~ [%pass path %agent [target %reel] %poke %reel-want-token-link !>(group)] - [%pass /expire/(scot %p our.bowl)/[group] %arvo %b [%wait (add ~h1 now.bowl)]] + =/ any ?(%v0 %v1) + =? pole !?=([any *] pole) + [%v0 pole] + ?+ pole ~|("bad pole: {}" (on-watch:def pole)) + [any %bites ~] `this + :: old subscription for getting links, we no longer use these because all + :: links are unique to that ship/user and can be scried out + :: + [%v0 %token-link ship=@ token=@ ~] + =/ ship (slav %p ship.pole) + =/ key [ship token.pole] + ?~ (~(has in open-link-requests) key) `this + :_ this(open-link-requests (~(put in open-link-requests) key)) + =/ =dock [ship dap.bowl] + =/ =cage reel-want-token-link+!>(token.pole) + :~ [%pass +.pole %agent dock %poke cage] + [%pass /expire/[ship.pole]/[token.pole] %arvo %b [%wait (add ~h1 now.bowl)]] == == :: ++ on-leave on-leave:def ++ on-peek - |= =path + |= =(pole knot) ^- (unit (unit cage)) - ?+ path [~ ~] - [%x %service ~] ``noun+!>(vic) - [%x %bait ~] ``reel-bait+!>([vic civ]) - :: - [%x %outstanding-poke @ @ ~] - ``json+!>([%b (~(has in outstanding-pokes) [(slav %p i.t.t.path) i.t.t.t.path])]) - :: - [%x %metadata @ ~] - =/ =metadata:reel (fall (~(get by our-metadata) i.t.t.path) *metadata:reel) + =/ any ?(%v0 %v1) + =? +.pole !?=([any *] +.pole) + [%v0 +.pole] + ?+ pole [~ ~] + [%x any %service ~] ``noun+!>(vic) + [%x any %bait ~] ``reel-bait+!>([vic civ]) + :: + [%x %v0 %outstanding-poke ship=@ name=@ ~] + =/ has (~(has in open-link-requests) [(slav %p ship.pole) name.pole]) + ``json+!>([%b has]) + :: + [%x any %metadata token=@ ~] + =/ =metadata:reel (fall (~(get by our-metadata) token.pole) *metadata:reel) ``reel-metadata+!>(metadata) + :: + [%x any %token-url token=*] + =/ token (crip (join '/' token.pole)) + =/ url (url-for-token vic token) + ``reel-token-url+!>(url) + :: + [%x %v1 %id-url id=*] + =/ id (crip (join '/' id.pole)) + ?~ token=(~(get by stable-id) id) + ``reel-token-url+!>('') + =/ url (cat 3 vic id) + ``reel-token-url+!>(url) == :: ++ on-arvo @@ -177,7 +258,9 @@ =/ target (slav %p i.t.wire) =/ group i.t.t.wire ?~ error.sign-arvo - `this(outstanding-pokes (~(del in outstanding-pokes) [target group])) + :_ this(open-link-requests (~(del in open-link-requests) [target group])) + =/ path (welp /token-link t.wire) + ~[[%give %kick ~[path] ~]] (on-arvo:def wire sign-arvo) == == diff --git a/desk/lib/test-agent.hoon b/desk/lib/test-agent.hoon new file mode 100644 index 00000000..a2d58ab1 --- /dev/null +++ b/desk/lib/test-agent.hoon @@ -0,0 +1,421 @@ +:: test-agent: testing harness for agents +:: +:: this library helps you write tests for agents in the monadic ;< style. +:: the general concept is that an agent and its bowl are continuously +:: "passed forward" as you perform operations on them. +:: +:: the bowl is partially managed for you by the library: when the agent +:: emits %watch or %leave cards, outgoing subscriptions in wex.bowl are +:: updated. likewise for %watch-ack and %kick calls to +on-agent. incoming +:: subscriptions in sup.bowl are updated in response to %kick cards and +:: calls to +on-watch and +on-leave. +:: +:: an example test arm, which initializes an agent and pokes it, might look +:: something like this (assuming /+ *test-agent): +:: +:: ++ test-example +:: %- eval-mare +:: =/ m (mare ,~) +:: ^- form:m +:: ;< ~ bind:m (set-scry-gate |=(path `!>(%some-noun))) +:: ;< caz=(list card) bind:m (do-init %my-agent-name my-agent-core) +:: ;< ~ bind:m (ex-cards caz ~) +:: ;< ~ bind:m (set-src ~dev) +:: ;< caz=(list card) bind:m (do-poke %noun !>(123)) +:: (ex-cards caz (ex-fact [/echo]~ %noun !>([~dev 123])) ~) +:: +/+ test +!. +:: +=/ drop-verb=? & +:: +|% +:: voodoo basics +:: ++$ agent $+(agent agent:gall) ++$ bowl $+(bowl bowl:gall) ++$ card $+(card card:agent:gall) ++$ scry $-(path (unit vase)) +:: ++$ state [=agent =bowl =scry] :: passed continuously +++ form-raw |$ [a] $-(state (output-raw a)) :: continuation +++ output-raw |$ [a] (each [out=a =state] tang) :: continue or fail +:: +++ mare + |* a=mold + |% + ++ output (output-raw a) + ++ form (form-raw a) + ++ pure + |= arg=a + ^- form + |= =state + [%& arg state] + :: + ++ bind + |* b=mold + |= [m-b=(form-raw b) fun=$-(b form)] + ^- form + |= =state + =/ b-res=(output-raw b) (m-b state) + ?- -.b-res + %& ((fun out.p.b-res) state.p.b-res) + %| [%| p.b-res] + == + -- +:: +++ eval-mare + =/ m (mare ,~) + |= f=form:m + ^- tang + =/ res (f *state) + ?-(-.res %& ~, %| p.res) +:: +:: internal transformations (you shouldn't be calling these directly) +:: +++ play-cards + |= [=bowl cards=(list card)] + ^+ bowl + ?~ cards bowl + =* card i.cards + =* next $(cards t.cards) + ?+ card next + [%pass * %agent * ?(%watch %watch-as %leave) *] + =- =.(wex.bowl - next) + =/ key=[=wire =gill:gall] [p [ship name]:q]:card + ?: ?=(%leave -.task.q.card) + (~(del by wex.bowl) key) + ?. (lien ~(tap by wex.bowl) |=([k=[wire gill:gall] *] =(k key))) + =; =path + (~(put by wex.bowl) key [| path]) + ?- -.task.q.card + %watch path.task.q.card + %watch-as path.task.q.card + == + ~_ 'subscribe wire not unique' ::TODO maybe integrate the test tang instead? + ~| key + !! + :: + [%give %kick *] + =- =.(sup.bowl - next) + %+ roll paths.p.card + |= [=path =_sup.bowl] + %- ~(gas by *bitt:gall) + %+ skip ~(tap by sup) + |= [duct s=ship p=^path] + &(=(p path) |(?=(~ ship.p.card) =(s u.ship.p.card))) + == +:: +++ play-sign + |= [=bowl =wire =gill:gall =sign:agent:gall] + ^+ bowl + =. src.bowl p.gill + ?: ?=(%poke-ack -.sign) bowl + =; =_wex.bowl bowl(wex wex) + ?. (~(has by wex.bowl) [wire gill]) + ~_ leaf+"missing subscription, got %{(trip -.sign)} on {(spud wire)}" + !! + ?+ sign wex.bowl + ?([%watch-ack ~ *] [%kick ~]) + (~(del by wex.bowl) [wire gill]) + :: + [%watch-ack ~] + %+ ~(jab by wex.bowl) [wire gill] + |= [ack=? =path] + ~_ 'duplicate watch-ack' + ?<(ack [& path]) + == +:: +++ do :: execute agent lifecycle step with mocked scry + |= call=$-(state [(list card) agent:gall]) + =/ m (mare ,(list card)) + ^- form:m + |= s=state + =; result=(each [(list card) agent:gall] (list tank)) + ?: ?=(%| -.result) + |+p.result + =^ c agent.s p.result + =. bowl.s (play-cards bowl.s c) + &+[c s] + =; res=toon + ?- -.res + %0 :- %& + ::NOTE we would ;;, but it's too slow. + :: we know for a fact p.res is of the type we expect, + :: so we just play pretend with vases instead. + !< [(list card) agent:gall] + [-:!>(*[(list card) agent:gall]) p.res] + %1 |+~['blocking on scry' >;;(path p.res)<] + %2 |+p.res + == + %+ mock [. !=((call s))] + |= [ref=* pax=*] + ^- (unit (unit *)) + ?> ?=(^ ref) + ?> =(hoon-version -.ref) + =+ ;;(pax=path pax) + =/ res=(unit vase) (scry.s pax) + %. ?~(res ~ ``q.u.res) + :: warn about type mismatches if the tested code expects a result type + :: different from what the mocked scry produces. + :: + ::NOTE we would ;;, but it's too slow. + :: we can safely assume +.ref is indeed a type, + :: so we just play pretend with vases instead. + =+ !<(typ=type [-:!>(*type) +.ref]) + ?. &(?=(^ res) !(~(nest ut typ) | p.u.res)) + same + %- %*(. slog pri 2) + :~ 'mocked scry result mismatches expected type' + >pax< + (~(dunk ut typ) %need) + (~(dunk ut p.u.res) %have) + == +:: +++ jab-state + |= f=$-(state state) + =/ m (mare ,~) + ^- form:m + |= s=state + &+[~ (f s)] +:: +:: managed agent lifecycle +:: +++ do-init + =+ scry-warn=& + |= [dap=term =agent] + =/ m (mare ,(list card)) + ^- form:m + ;< old-scry=scry bind:m |=(s=state &+[scry.s s]) + ;< ~ bind:m %- set-scry-gate + |= p=path + ~? >> scry-warn + ['scrying during +on-init... careful!' p] + (old-scry p) + ;< b=bowl bind:m get-bowl + ;< ~ bind:m (set-bowl %*(. *bowl dap dap, our our.b, src our.b)) + ;< c=(list card) bind:m (do |=(s=state ~(on-init agent bowl.s))) + ;< ~ bind:m (set-scry-gate old-scry) + (pure:m c) +:: +++ do-load + =+ scry-warn=& + |= [=agent vase=(unit vase)] + =/ m (mare ,(list card)) + ^- form:m + ;< old-scry=scry bind:m |=(s=state &+[scry.s s]) + ;< ~ bind:m %- set-scry-gate + |= p=path + ~? >> scry-warn + ['scrying during +on-load... careful!' p] + (old-scry p) + ;< c=(list card) bind:m %- do |= s=state + %- ~(on-load agent bowl.s) + (fall vase ~(on-save agent.s bowl.s)) + ;< ~ bind:m (set-scry-gate old-scry) + (pure:m c) +:: +++ do-poke + |= [=mark =vase] + %- do + |= s=state + (~(on-poke agent.s bowl.s) mark vase) +:: +++ do-watch + |= =path + =/ m (mare ,(list card)) + ^- form:m + |= s=state + =. sup.bowl.s + =/ =duct [%test-sub (scot %p src.bowl.s) path]~ + ~_ leaf+"sub on {(spud path)} already made by {(scow %p src.bowl.s)}" + ?< (~(has by sup.bowl.s) duct) + (~(put by sup.bowl.s) duct [src.bowl.s path]) + %. s %- do + |= s=state + (~(on-watch agent.s bowl.s) path) +:: +++ do-leave + |= =path + =/ m (mare ,(list card)) + ^- form:m + |= s=state + =. sup.bowl.s + =/ =duct [%test-sub (scot %p src.bowl.s) path]~ + ~_ leaf+"sub on {(spud path)} not yet made by {(scow %p src.bowl.s)}" + ?> (~(has by sup.bowl.s) duct) + (~(del by sup.bowl.s) duct [src.bowl.s path]) + %. s %- do + |= s=state + (~(on-leave agent.s bowl.s) path) +:: +++ do-agent + |= [=wire =gill:gall =sign:agent:gall] + =/ m (mare ,(list card)) + ^- form:m + |= s=state + =. bowl.s (play-sign bowl.s wire gill sign) + %. s %- do + |= s=state + (~(on-agent agent.s bowl.s) wire sign) +:: +++ do-arvo + |= [=wire sign=sign-arvo] + %- do + |= s=state + (~(on-arvo agent.s bowl.s) wire sign) +:: +++ do-fail + |= [=term =tang] + %- do + |= s=state + (~(on-fail agent.s bowl.s) term tang) +:: +:: data extraction +:: +++ get-save + =/ m (mare ,vase) + ^- form:m + |= s=state + &+[~(on-save agent.s bowl.s) s] +:: +++ get-peek + |= =path + =/ m (mare ,(unit (unit cage))) + ^- form:m + |= s=state + &+[(~(on-peek agent.s bowl.s) path) s] +:: +++ get-agent + =/ m (mare agent) + ^- form:m + |= s=state + &+[agent.s s] +:: +++ get-bowl + =/ m (mare bowl) + ^- form:m + |= s=state + &+[bowl.s s] +:: +:: bowl modification +:: +++ jab-bowl + |= f=$-(bowl bowl) + =/ m (mare ,~) + ^- form:m + |= s=state + &+[~ s(bowl (f bowl.s))] +:: +++ set-bowl + |=(b=bowl (jab-bowl |=(* b))) +:: +++ set-src + |= src=ship + %- jab-bowl + |=(b=bowl b(src src)) +:: +++ wait + |= d=@dr + %- jab-bowl + |=(b=bowl b(now (add now.b d))) +:: +++ set-scry-gate + |= f=scry + =/ m (mare ,~) + ^- form:m + |= s=state + &+[~ s(scry f)] +:: +:: testing utilities +:: +++ ex-equal + |= [actual=vase expected=vase] ::NOTE reverse order from /lib/test + =/ m (mare ,~) + ^- form:m + |= s=state + =/ =tang (expect-eq:test expected actual) + ?~(tang &+[~ s] |+tang) +:: +++ ex-fail + |= form=(form-raw ,*) + =/ m (mare ,~) + ^- form:m + |= =state + =/ res (form state) + ?-(-.res %| &+[~ state], %& |+['expected failure, but succeeded']~) +:: +++ ex-cards + |= [caz=(list card) exes=(list $-(card tang))] + =? caz drop-verb + :: remove cards unconditionally emitted by /lib/verb + :: + %+ skip caz + |= =card + ?=([%give %fact [[%verb ?(%events %events-plus) ~] ~] *] card) + =/ m (mare ,~) + ^- form:m + |= s=state + =; =tang + ?~(tang &+[~ s] |+tang) + |- ^- tang + ?~ exes + ?~ caz + ~ + ['got more cards than expected' >caz< ~] + ?~ caz + ['expected more cards than got' ~] + %+ weld + (i.exes i.caz) + $(exes t.exes, caz t.caz) +:: +++ ex-card + |= caw=card + |= cav=card + (expect-eq:test !>(caw) !>(cav)) +:: +++ ex-fact + |= [paths=(list path) =mark =vase] + |= car=card + ^- tang + =* nope + %- expect-eq:test + [!>(`card`[%give %fact paths mark vase]) !>(`card`car)] + ?. ?=([%give %fact *] car) nope + ?. =(paths paths.p.car) nope + ?. =(mark p.cage.p.car) nope + =/ =tang (expect-eq:test vase q.cage.p.car) + ?~ tang ~ + ['in %fact vase,' tang] +:: +++ ex-poke + |= [=wire =gill:gall =mark =vase] + |= car=card + ^- tang + =* nope + %- expect-eq:test + [!>(`card`[%pass wire %agent gill %poke mark vase]) !>(`card`car)] + ?. ?=([%pass * %agent * %poke *] car) nope + ?. =(wire p.car) nope + ?. =(gill [ship name]:q.car) nope + ?. =(mark p.cage.task.q.car) nope + =/ =tang (expect-eq:test vase q.cage.task.q.car) + ?~ tang ~ + ['in %poke vase on ,' tang] +:: +++ ex-task + |= [=wire =gill:gall =task:agent:gall] + (ex-card %pass wire %agent gill task) +:: +++ ex-arvo + |= [=wire note=note-arvo] + (ex-card %pass wire %arvo note) +:: +++ ex-scry-result + |= [=path =vase] + =/ m (mare ,~) + ^- form:m + ;< res=(unit (unit cage)) bind:m (get-peek path) + (ex-equal q:(need (need res)) vase) +:: +-- diff --git a/desk/sur/reel.hoon b/desk/sur/reel.hoon index b3fee23d..c54302eb 100644 --- a/desk/sur/reel.hoon +++ b/desk/sur/reel.hoon @@ -7,7 +7,9 @@ +$ bite $% [%bite-0 token=@ta ship=@p] [%bite-1 token=@ta joiner=@p inviter=@p] + [%bite-2 token=cord joiner=@p =metadata] == :: +$ metadata [tag=term fields=(map cord cord)] ++$ confirmation [nonce=cord token=cord] -- diff --git a/desk/tests/app/reel.hoon b/desk/tests/app/reel.hoon new file mode 100644 index 00000000..7da152d4 --- /dev/null +++ b/desk/tests/app/reel.hoon @@ -0,0 +1,120 @@ +/- r=reel +/+ *test-agent +/= reel-agent /app/reel +|% +++ dap %reel-test +++ vic 'https://tlon.network/lure/' +++ civ ~loshut-lonreg +++ token '~bus/reel-test' ++$ reel-state + $: %4 + vic=@t + civ=ship + our-metadata=(map cord metadata:r) + open-link-requests=(set (pair ship cord)) + open-describes=(set cord) + stable-id=(map cord cord) + == +++ test-reel-describe + %- eval-mare + =/ m (mare ,~) + ;< * bind:m (do-init dap reel-agent) + ;< * bind:m (jab-bowl |=(b=bowl b(our ~dev, src ~dev, now *@da))) + =/ =metadata:r [%test (my ['inviter' '~dev'] ~)] + =/ describe [token metadata] + ;< caz=(list card) bind:m (do-poke %reel-describe !>(describe)) + ;< bw=bowl bind:m get-bowl + =/ nonce (scot %da now.bw) + :: make sure we're sending a describe request to the bait provider + ;< * bind:m + %+ ex-cards caz + =/ request [nonce metadata] + ~[(ex-poke /describe [civ %bait] bait-describe+!>(request))] + ;< state=vase bind:m get-save + =/ edited-md [%test (~(put by fields.metadata) 'bite-type' '2')] + =+ !<(reel-state state) + :: ensure link metadata added to our state and has bite-type field + ;< * bind:m (ex-equal !>(our-metadata) !>((my [nonce edited-md] ~))) + :: ensure nonce is added to open-describes set + ;< * bind:m (ex-equal !>(open-describes) !>((sy [nonce] ~))) + :: ensure stable-id has an entry for the token + ;< * bind:m (ex-equal !>(stable-id) !>((my [token nonce] ~))) + :: simulate the bait provider returning the new metadata + ;< bw=bowl bind:m get-bowl + =/ real-token (shax (jam [dap eny.bw])) + ;< * bind:m (jab-bowl |=(b=bowl b(src civ))) + ;< * bind:m (do-poke %reel-confirmation !>([nonce real-token])) + ;< state=vase bind:m get-save + =+ !<(reel-state state) + ;< * bind:m (ex-equal !>(open-describes) !>(~)) + ;< * bind:m (ex-equal !>(stable-id) !>((sy [token real-token] ~))) + (ex-equal !>(our-metadata) !>((my [real-token edited-md] ~))) +:: +:: testing old way of distributing links from requester side +++ test-reel-token-link-requester + %- eval-mare + =/ m (mare ,~) + ;< * bind:m (do-init dap reel-agent) + ;< * bind:m (jab-bowl |=(b=bowl b(our ~dev, src ~dev, now *@da))) + ;< bw=bowl bind:m get-bowl + =/ request-path /token-link/(scot %p ~bus)/[dap] + :: simulate subscription from frontend for link + ;< caz=(list card) bind:m + (do-watch request-path) + =/ next (add now.bw ~h1) + =/ expire=wire /expire/(scot %p ~bus)/[dap] + ;< * bind:m + %+ ex-cards caz + =/ =cage reel-want-token-link+!>(dap) + :~ (ex-poke request-path [~bus dap] cage) + (ex-arvo expire %b %wait next) + == + ;< state=vase bind:m get-save + =+ !<(reel-state state) + =/ new-requests (sy [~bus dap] ~) + :: ensure that the request is in the open-link-requests set + ;< * bind:m (ex-equal !>(open-link-requests) !>(new-requests)) + ;< * bind:m (jab-bowl |=(b=bowl b(now next))) + ;< bw=bowl bind:m get-bowl + :: simulate link request expiring + ;< * bind:m (do-arvo expire %behn %wake ~) + ;< state=vase bind:m get-save + =+ !<(reel-state state) + :: make sure the request is removed from the open-link-requests set + ;< * bind:m (ex-equal !>(open-link-requests) !>(~)) + :: try to get the link again, but this time not expiring + ;< * bind:m (do-watch request-path) + =/ url (cat 3 vic '~bus/reel-test') + =/ response `[dap url] + ;< * bind:m (jab-bowl |=(b=bowl b(src ~bus))) + ;< caz=(list card) bind:m (do-poke %reel-give-token-link !>(response)) + %+ ex-cards caz + ~[(ex-fact ~[request-path] %json !>(s+url))] +:: +:: testing old way of distributing links from dispenser side +++ test-reel-token-link-dispenser + %- eval-mare + =/ m (mare ,~) + ;< * bind:m (do-init dap reel-agent) + ;< * bind:m (jab-bowl |=(b=bowl b(our ~bus, src ~bus))) + :: build state for link + =/ fields=(map cord cord) (my ['inviter' '~zod'] ~) + =/ init-state=vase + !> + :* %4 + vic + civ + (my [token %meta fields] ~) + ~ + ~ + (my [token token] ~) + == + ;< * bind:m (do-load reel-agent `init-state) + ;< * bind:m (jab-bowl |=(b=bowl b(src ~zod))) + :: simulate link request + ;< caz=(list card) bind:m (do-poke %reel-want-token-link !>(token)) + %+ ex-cards caz + =/ url (cat 3 vic '~bus/reel-test') + =/ =cage reel-give-token-link+!>(`[token url]) + ~[(ex-poke /token-link-want/[token] [~zod dap] cage)] +-- \ No newline at end of file From eaa1177fef1499a106474fc705f5b6c3492bc7ea Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Tue, 27 Aug 2024 17:34:27 -0500 Subject: [PATCH 07/18] reel: updating to new flow with tests --- desk/app/reel.hoon | 160 +++++++++++---- desk/lib/test-agent.hoon | 421 +++++++++++++++++++++++++++++++++++++++ desk/sur/reel.hoon | 2 + desk/tests/app/reel.hoon | 120 +++++++++++ 4 files changed, 665 insertions(+), 38 deletions(-) create mode 100644 desk/lib/test-agent.hoon create mode 100644 desk/tests/app/reel.hoon diff --git a/desk/app/reel.hoon b/desk/app/reel.hoon index a51b554e..c0d4df63 100644 --- a/desk/app/reel.hoon +++ b/desk/app/reel.hoon @@ -7,12 +7,16 @@ state-1 state-2 state-3 + state-4 == :: :: vic: URL of bait service :: civ: @p of bait service -:: our-metadata: map from tokens to their metadata -:: outstanding-pokes: ships we have poked and await a response from +:: our-metadata: a mapping from nonce/token to metadata +:: open-link-requests: open requests for an existing foreign link, DEPRECATED +:: open-describes: attempts to create a link waiting to be assigned a token +:: stable-id: a mapping from something the client can use to identify the +:: metadata to nonce and/or token :: +$ state-0 $: %0 @@ -40,11 +44,21 @@ our-metadata=(map cord metadata:reel) outstanding-pokes=(set (pair ship cord)) == ++$ state-4 + $: %4 + vic=@t + civ=ship + our-metadata=(map cord metadata:reel) + open-link-requests=(set (pair ship cord)) + open-describes=(set cord) + stable-id=(map cord cord) + == +:: url with old style token ++ url-for-token - |= [vic=cord our=ship token=cord] - (crip "{(trip vic)}{(trip (scot %p our))}/{(trip token)}") + |= [vic=cord token=cord] + (cat 3 vic token) -- -=| state-3 +=| state-4 =* state - :: %- agent:dbug @@ -63,14 +77,16 @@ ^- (quip card _this) =/ old !<(versioned-state old-state) ?- -.old - %3 + %4 `this(state old) + %3 + `this(state [%4 vic.old civ.old our-metadata.old outstanding-pokes.old ~ ~]) %2 - `this(state [%3 vic.old civ.old our-metadata.old ~]) + `this(state [%4 vic.old civ.old our-metadata.old ~ ~ ~]) %1 - `this(state [%3 'https://tlon.network/lure/' ~loshut-lonreg ~ ~]) + `this(state [%4 'https://tlon.network/lure/' ~loshut-lonreg ~ ~ ~ ~]) %0 - `this(state [%3 'https://tlon.network/lure/' ~loshut-lonreg ~ ~]) + `this(state [%4 'https://tlon.network/lure/' ~loshut-lonreg ~ ~ ~ ~]) == :: ++ on-poke @@ -85,7 +101,9 @@ :_ this(vic vic.command) ~[[%pass /set-ship %arvo %k %fard q.byk.bowl %reel-set-ship %noun !>(vic.command)]] %set-ship - :_ this(civ civ.command) + :: since we're changing providers, we need to regenerate links + :: we'll use whatever key we currently have as the nonce + :_ this(civ civ.command, open-describes ~(key by our-metadata)) %+ turn ~(tap by our-metadata) |= [token=cord =metadata:reel] ^- card @@ -93,24 +111,62 @@ == :: %reel-bite + ?> =(civ src.bowl) =+ !<(=bite:reel vase) [[%give %fact ~[/bites] mark !>(bite)]~ this] :: %reel-describe + ?> =(our.bowl src.bowl) =+ !<([token=cord =metadata:reel] vase) - :_ this(our-metadata (~(put by our-metadata) token metadata)) - ~[[%pass /describe %agent [civ %bait] %poke %bait-describe !>([token metadata])]] + :: the token here is a temporary identifier for the metadata + :: a new one will be assigned by the bait provider and returned to us + =/ new-fields (~(put by fields.metadata) 'bite-type' '2') + =/ new-metadata metadata(fields new-fields) + =/ nonce=cord (scot %da now.bowl) + =. our-metadata (~(put by our-metadata) nonce new-metadata) + =. open-describes (~(put in open-describes) nonce) + =. stable-id (~(put by stable-id) token nonce) + :_ this + ~[[%pass /describe %agent [civ %bait] %poke %bait-describe !>([nonce new-metadata])]] + :: + %reel-confirmation + ?> =(civ src.bowl) + =+ !<(confirmation:reel vase) + =. open-describes (~(del in open-describes) nonce) + ?~ md=(~(get by our-metadata) nonce) + ~|("no metadata for nonce: {}" !!) + =/ ids=(list [id=cord token=cord]) + %+ skim + ~(tap by stable-id) + |= [key=cord token=cord] + =(nonce token) + ?~ ids + ~|("no stable id for nonce: {}" !!) + =* id -<.ids + :: update the token the id points to + =. stable-id (~(put by stable-id) id token) + :: swap out the nonce for the token in our-metadata + =. our-metadata + (~(put by (~(del by our-metadata) nonce)) token u.md) + `this + :: %reel-undescribe + ?> =(our.bowl src.bowl) =+ !<(token=cord vase) + :: the token here should be the actual token given to us by the provider :_ this(our-metadata (~(del by our-metadata) token)) ~[[%pass /undescribe %agent [civ %bait] %poke %bait-undescribe !>(token)]] + :: old pokes for getting links, we no longer use these because all links + :: are unique to that ship/user and can be scried out + :: %reel-want-token-link =+ !<(token=cord vase) :_ this =/ result=(unit [cord cord]) ?. (~(has by our-metadata) token) ~ - `[token (url-for-token vic our.bowl token)] - ~[[%pass [%token-link-want token ~] %agent [src.bowl %reel] %poke %reel-give-token-link !>(result)]] + `[token (url-for-token vic token)] + ~[[%pass [%token-link-want token ~] %agent [src dap]:bowl %poke %reel-give-token-link !>(result)]] + :: %reel-give-token-link =+ !<(result=(unit [cord cord]) vase) ?~ result `this @@ -122,43 +178,69 @@ ++ on-agent |= [=wire =sign:agent:gall] ^- (quip card _this) - ?: ?=([%token-link @ @ ~] wire) + =/ =(pole knot) wire + ?+ pole (on-agent:def wire sign) + [%token-link @ name=@ ~] ?+ -.sign (on-agent:def wire sign) %poke-ack - `this(outstanding-pokes (~(del in outstanding-pokes) [src.bowl i.t.t.wire])) + `this(open-link-requests (~(del in open-link-requests) [src.bowl name.pole])) == - (on-agent:def wire sign) + == :: ++ on-watch - |= =path + |= =(pole knot) ^- (quip card _this) ?> =(our.bowl src.bowl) - ?+ path (on-watch:def path) - [%bites ~] `this - [%token-link @ @ ~] - =/ target (slav %p i.t.path) - =/ group i.t.t.path - ?~ (~(has in outstanding-pokes) [target group]) `this - :_ this(outstanding-pokes (~(put in outstanding-pokes) [target group])) - :~ [%pass path %agent [target %reel] %poke %reel-want-token-link !>(group)] - [%pass /expire/(scot %p our.bowl)/[group] %arvo %b [%wait (add ~h1 now.bowl)]] + =/ any ?(%v0 %v1) + =? pole !?=([any *] pole) + [%v0 pole] + ?+ pole ~|("bad pole: {}" (on-watch:def pole)) + [any %bites ~] `this + :: old subscription for getting links, we no longer use these because all + :: links are unique to that ship/user and can be scried out + :: + [%v0 %token-link ship=@ token=@ ~] + =/ ship (slav %p ship.pole) + =/ key [ship token.pole] + ?~ (~(has in open-link-requests) key) `this + :_ this(open-link-requests (~(put in open-link-requests) key)) + =/ =dock [ship dap.bowl] + =/ =cage reel-want-token-link+!>(token.pole) + :~ [%pass +.pole %agent dock %poke cage] + [%pass /expire/[ship.pole]/[token.pole] %arvo %b [%wait (add ~h1 now.bowl)]] == == :: ++ on-leave on-leave:def ++ on-peek - |= =path + |= =(pole knot) ^- (unit (unit cage)) - ?+ path [~ ~] - [%x %service ~] ``noun+!>(vic) - [%x %bait ~] ``reel-bait+!>([vic civ]) - :: - [%x %outstanding-poke @ @ ~] - ``json+!>([%b (~(has in outstanding-pokes) [(slav %p i.t.t.path) i.t.t.t.path])]) - :: - [%x %metadata @ ~] - =/ =metadata:reel (fall (~(get by our-metadata) i.t.t.path) *metadata:reel) + =/ any ?(%v0 %v1) + =? +.pole !?=([any *] +.pole) + [%v0 +.pole] + ?+ pole [~ ~] + [%x any %service ~] ``noun+!>(vic) + [%x any %bait ~] ``reel-bait+!>([vic civ]) + :: + [%x %v0 %outstanding-poke ship=@ name=@ ~] + =/ has (~(has in open-link-requests) [(slav %p ship.pole) name.pole]) + ``json+!>([%b has]) + :: + [%x any %metadata token=@ ~] + =/ =metadata:reel (fall (~(get by our-metadata) token.pole) *metadata:reel) ``reel-metadata+!>(metadata) + :: + [%x any %token-url token=*] + =/ token (crip (join '/' token.pole)) + =/ url (url-for-token vic token) + ``reel-token-url+!>(url) + :: + [%x %v1 %id-url id=*] + =/ id (crip (join '/' id.pole)) + ?~ token=(~(get by stable-id) id) + ``reel-token-url+!>('') + =/ url (cat 3 vic id) + ``reel-token-url+!>(url) == :: ++ on-arvo @@ -177,7 +259,9 @@ =/ target (slav %p i.t.wire) =/ group i.t.t.wire ?~ error.sign-arvo - `this(outstanding-pokes (~(del in outstanding-pokes) [target group])) + :_ this(open-link-requests (~(del in open-link-requests) [target group])) + =/ path (welp /token-link t.wire) + ~[[%give %kick ~[path] ~]] (on-arvo:def wire sign-arvo) == == diff --git a/desk/lib/test-agent.hoon b/desk/lib/test-agent.hoon new file mode 100644 index 00000000..a2d58ab1 --- /dev/null +++ b/desk/lib/test-agent.hoon @@ -0,0 +1,421 @@ +:: test-agent: testing harness for agents +:: +:: this library helps you write tests for agents in the monadic ;< style. +:: the general concept is that an agent and its bowl are continuously +:: "passed forward" as you perform operations on them. +:: +:: the bowl is partially managed for you by the library: when the agent +:: emits %watch or %leave cards, outgoing subscriptions in wex.bowl are +:: updated. likewise for %watch-ack and %kick calls to +on-agent. incoming +:: subscriptions in sup.bowl are updated in response to %kick cards and +:: calls to +on-watch and +on-leave. +:: +:: an example test arm, which initializes an agent and pokes it, might look +:: something like this (assuming /+ *test-agent): +:: +:: ++ test-example +:: %- eval-mare +:: =/ m (mare ,~) +:: ^- form:m +:: ;< ~ bind:m (set-scry-gate |=(path `!>(%some-noun))) +:: ;< caz=(list card) bind:m (do-init %my-agent-name my-agent-core) +:: ;< ~ bind:m (ex-cards caz ~) +:: ;< ~ bind:m (set-src ~dev) +:: ;< caz=(list card) bind:m (do-poke %noun !>(123)) +:: (ex-cards caz (ex-fact [/echo]~ %noun !>([~dev 123])) ~) +:: +/+ test +!. +:: +=/ drop-verb=? & +:: +|% +:: voodoo basics +:: ++$ agent $+(agent agent:gall) ++$ bowl $+(bowl bowl:gall) ++$ card $+(card card:agent:gall) ++$ scry $-(path (unit vase)) +:: ++$ state [=agent =bowl =scry] :: passed continuously +++ form-raw |$ [a] $-(state (output-raw a)) :: continuation +++ output-raw |$ [a] (each [out=a =state] tang) :: continue or fail +:: +++ mare + |* a=mold + |% + ++ output (output-raw a) + ++ form (form-raw a) + ++ pure + |= arg=a + ^- form + |= =state + [%& arg state] + :: + ++ bind + |* b=mold + |= [m-b=(form-raw b) fun=$-(b form)] + ^- form + |= =state + =/ b-res=(output-raw b) (m-b state) + ?- -.b-res + %& ((fun out.p.b-res) state.p.b-res) + %| [%| p.b-res] + == + -- +:: +++ eval-mare + =/ m (mare ,~) + |= f=form:m + ^- tang + =/ res (f *state) + ?-(-.res %& ~, %| p.res) +:: +:: internal transformations (you shouldn't be calling these directly) +:: +++ play-cards + |= [=bowl cards=(list card)] + ^+ bowl + ?~ cards bowl + =* card i.cards + =* next $(cards t.cards) + ?+ card next + [%pass * %agent * ?(%watch %watch-as %leave) *] + =- =.(wex.bowl - next) + =/ key=[=wire =gill:gall] [p [ship name]:q]:card + ?: ?=(%leave -.task.q.card) + (~(del by wex.bowl) key) + ?. (lien ~(tap by wex.bowl) |=([k=[wire gill:gall] *] =(k key))) + =; =path + (~(put by wex.bowl) key [| path]) + ?- -.task.q.card + %watch path.task.q.card + %watch-as path.task.q.card + == + ~_ 'subscribe wire not unique' ::TODO maybe integrate the test tang instead? + ~| key + !! + :: + [%give %kick *] + =- =.(sup.bowl - next) + %+ roll paths.p.card + |= [=path =_sup.bowl] + %- ~(gas by *bitt:gall) + %+ skip ~(tap by sup) + |= [duct s=ship p=^path] + &(=(p path) |(?=(~ ship.p.card) =(s u.ship.p.card))) + == +:: +++ play-sign + |= [=bowl =wire =gill:gall =sign:agent:gall] + ^+ bowl + =. src.bowl p.gill + ?: ?=(%poke-ack -.sign) bowl + =; =_wex.bowl bowl(wex wex) + ?. (~(has by wex.bowl) [wire gill]) + ~_ leaf+"missing subscription, got %{(trip -.sign)} on {(spud wire)}" + !! + ?+ sign wex.bowl + ?([%watch-ack ~ *] [%kick ~]) + (~(del by wex.bowl) [wire gill]) + :: + [%watch-ack ~] + %+ ~(jab by wex.bowl) [wire gill] + |= [ack=? =path] + ~_ 'duplicate watch-ack' + ?<(ack [& path]) + == +:: +++ do :: execute agent lifecycle step with mocked scry + |= call=$-(state [(list card) agent:gall]) + =/ m (mare ,(list card)) + ^- form:m + |= s=state + =; result=(each [(list card) agent:gall] (list tank)) + ?: ?=(%| -.result) + |+p.result + =^ c agent.s p.result + =. bowl.s (play-cards bowl.s c) + &+[c s] + =; res=toon + ?- -.res + %0 :- %& + ::NOTE we would ;;, but it's too slow. + :: we know for a fact p.res is of the type we expect, + :: so we just play pretend with vases instead. + !< [(list card) agent:gall] + [-:!>(*[(list card) agent:gall]) p.res] + %1 |+~['blocking on scry' >;;(path p.res)<] + %2 |+p.res + == + %+ mock [. !=((call s))] + |= [ref=* pax=*] + ^- (unit (unit *)) + ?> ?=(^ ref) + ?> =(hoon-version -.ref) + =+ ;;(pax=path pax) + =/ res=(unit vase) (scry.s pax) + %. ?~(res ~ ``q.u.res) + :: warn about type mismatches if the tested code expects a result type + :: different from what the mocked scry produces. + :: + ::NOTE we would ;;, but it's too slow. + :: we can safely assume +.ref is indeed a type, + :: so we just play pretend with vases instead. + =+ !<(typ=type [-:!>(*type) +.ref]) + ?. &(?=(^ res) !(~(nest ut typ) | p.u.res)) + same + %- %*(. slog pri 2) + :~ 'mocked scry result mismatches expected type' + >pax< + (~(dunk ut typ) %need) + (~(dunk ut p.u.res) %have) + == +:: +++ jab-state + |= f=$-(state state) + =/ m (mare ,~) + ^- form:m + |= s=state + &+[~ (f s)] +:: +:: managed agent lifecycle +:: +++ do-init + =+ scry-warn=& + |= [dap=term =agent] + =/ m (mare ,(list card)) + ^- form:m + ;< old-scry=scry bind:m |=(s=state &+[scry.s s]) + ;< ~ bind:m %- set-scry-gate + |= p=path + ~? >> scry-warn + ['scrying during +on-init... careful!' p] + (old-scry p) + ;< b=bowl bind:m get-bowl + ;< ~ bind:m (set-bowl %*(. *bowl dap dap, our our.b, src our.b)) + ;< c=(list card) bind:m (do |=(s=state ~(on-init agent bowl.s))) + ;< ~ bind:m (set-scry-gate old-scry) + (pure:m c) +:: +++ do-load + =+ scry-warn=& + |= [=agent vase=(unit vase)] + =/ m (mare ,(list card)) + ^- form:m + ;< old-scry=scry bind:m |=(s=state &+[scry.s s]) + ;< ~ bind:m %- set-scry-gate + |= p=path + ~? >> scry-warn + ['scrying during +on-load... careful!' p] + (old-scry p) + ;< c=(list card) bind:m %- do |= s=state + %- ~(on-load agent bowl.s) + (fall vase ~(on-save agent.s bowl.s)) + ;< ~ bind:m (set-scry-gate old-scry) + (pure:m c) +:: +++ do-poke + |= [=mark =vase] + %- do + |= s=state + (~(on-poke agent.s bowl.s) mark vase) +:: +++ do-watch + |= =path + =/ m (mare ,(list card)) + ^- form:m + |= s=state + =. sup.bowl.s + =/ =duct [%test-sub (scot %p src.bowl.s) path]~ + ~_ leaf+"sub on {(spud path)} already made by {(scow %p src.bowl.s)}" + ?< (~(has by sup.bowl.s) duct) + (~(put by sup.bowl.s) duct [src.bowl.s path]) + %. s %- do + |= s=state + (~(on-watch agent.s bowl.s) path) +:: +++ do-leave + |= =path + =/ m (mare ,(list card)) + ^- form:m + |= s=state + =. sup.bowl.s + =/ =duct [%test-sub (scot %p src.bowl.s) path]~ + ~_ leaf+"sub on {(spud path)} not yet made by {(scow %p src.bowl.s)}" + ?> (~(has by sup.bowl.s) duct) + (~(del by sup.bowl.s) duct [src.bowl.s path]) + %. s %- do + |= s=state + (~(on-leave agent.s bowl.s) path) +:: +++ do-agent + |= [=wire =gill:gall =sign:agent:gall] + =/ m (mare ,(list card)) + ^- form:m + |= s=state + =. bowl.s (play-sign bowl.s wire gill sign) + %. s %- do + |= s=state + (~(on-agent agent.s bowl.s) wire sign) +:: +++ do-arvo + |= [=wire sign=sign-arvo] + %- do + |= s=state + (~(on-arvo agent.s bowl.s) wire sign) +:: +++ do-fail + |= [=term =tang] + %- do + |= s=state + (~(on-fail agent.s bowl.s) term tang) +:: +:: data extraction +:: +++ get-save + =/ m (mare ,vase) + ^- form:m + |= s=state + &+[~(on-save agent.s bowl.s) s] +:: +++ get-peek + |= =path + =/ m (mare ,(unit (unit cage))) + ^- form:m + |= s=state + &+[(~(on-peek agent.s bowl.s) path) s] +:: +++ get-agent + =/ m (mare agent) + ^- form:m + |= s=state + &+[agent.s s] +:: +++ get-bowl + =/ m (mare bowl) + ^- form:m + |= s=state + &+[bowl.s s] +:: +:: bowl modification +:: +++ jab-bowl + |= f=$-(bowl bowl) + =/ m (mare ,~) + ^- form:m + |= s=state + &+[~ s(bowl (f bowl.s))] +:: +++ set-bowl + |=(b=bowl (jab-bowl |=(* b))) +:: +++ set-src + |= src=ship + %- jab-bowl + |=(b=bowl b(src src)) +:: +++ wait + |= d=@dr + %- jab-bowl + |=(b=bowl b(now (add now.b d))) +:: +++ set-scry-gate + |= f=scry + =/ m (mare ,~) + ^- form:m + |= s=state + &+[~ s(scry f)] +:: +:: testing utilities +:: +++ ex-equal + |= [actual=vase expected=vase] ::NOTE reverse order from /lib/test + =/ m (mare ,~) + ^- form:m + |= s=state + =/ =tang (expect-eq:test expected actual) + ?~(tang &+[~ s] |+tang) +:: +++ ex-fail + |= form=(form-raw ,*) + =/ m (mare ,~) + ^- form:m + |= =state + =/ res (form state) + ?-(-.res %| &+[~ state], %& |+['expected failure, but succeeded']~) +:: +++ ex-cards + |= [caz=(list card) exes=(list $-(card tang))] + =? caz drop-verb + :: remove cards unconditionally emitted by /lib/verb + :: + %+ skip caz + |= =card + ?=([%give %fact [[%verb ?(%events %events-plus) ~] ~] *] card) + =/ m (mare ,~) + ^- form:m + |= s=state + =; =tang + ?~(tang &+[~ s] |+tang) + |- ^- tang + ?~ exes + ?~ caz + ~ + ['got more cards than expected' >caz< ~] + ?~ caz + ['expected more cards than got' ~] + %+ weld + (i.exes i.caz) + $(exes t.exes, caz t.caz) +:: +++ ex-card + |= caw=card + |= cav=card + (expect-eq:test !>(caw) !>(cav)) +:: +++ ex-fact + |= [paths=(list path) =mark =vase] + |= car=card + ^- tang + =* nope + %- expect-eq:test + [!>(`card`[%give %fact paths mark vase]) !>(`card`car)] + ?. ?=([%give %fact *] car) nope + ?. =(paths paths.p.car) nope + ?. =(mark p.cage.p.car) nope + =/ =tang (expect-eq:test vase q.cage.p.car) + ?~ tang ~ + ['in %fact vase,' tang] +:: +++ ex-poke + |= [=wire =gill:gall =mark =vase] + |= car=card + ^- tang + =* nope + %- expect-eq:test + [!>(`card`[%pass wire %agent gill %poke mark vase]) !>(`card`car)] + ?. ?=([%pass * %agent * %poke *] car) nope + ?. =(wire p.car) nope + ?. =(gill [ship name]:q.car) nope + ?. =(mark p.cage.task.q.car) nope + =/ =tang (expect-eq:test vase q.cage.task.q.car) + ?~ tang ~ + ['in %poke vase on ,' tang] +:: +++ ex-task + |= [=wire =gill:gall =task:agent:gall] + (ex-card %pass wire %agent gill task) +:: +++ ex-arvo + |= [=wire note=note-arvo] + (ex-card %pass wire %arvo note) +:: +++ ex-scry-result + |= [=path =vase] + =/ m (mare ,~) + ^- form:m + ;< res=(unit (unit cage)) bind:m (get-peek path) + (ex-equal q:(need (need res)) vase) +:: +-- diff --git a/desk/sur/reel.hoon b/desk/sur/reel.hoon index b3fee23d..c54302eb 100644 --- a/desk/sur/reel.hoon +++ b/desk/sur/reel.hoon @@ -7,7 +7,9 @@ +$ bite $% [%bite-0 token=@ta ship=@p] [%bite-1 token=@ta joiner=@p inviter=@p] + [%bite-2 token=cord joiner=@p =metadata] == :: +$ metadata [tag=term fields=(map cord cord)] ++$ confirmation [nonce=cord token=cord] -- diff --git a/desk/tests/app/reel.hoon b/desk/tests/app/reel.hoon new file mode 100644 index 00000000..c4239854 --- /dev/null +++ b/desk/tests/app/reel.hoon @@ -0,0 +1,120 @@ +/- r=reel +/+ *test-agent +/= reel-agent /app/reel +|% +++ dap %reel-test +++ vic 'https://tlon.network/lure/' +++ civ ~loshut-lonreg +++ token '~bus/reel-test' ++$ reel-state + $: %4 + vic=@t + civ=ship + our-metadata=(map cord metadata:r) + open-link-requests=(set (pair ship cord)) + open-describes=(set cord) + stable-id=(map cord cord) + == +++ test-reel-describe + %- eval-mare + =/ m (mare ,~) + ;< * bind:m (do-init dap reel-agent) + ;< * bind:m (jab-bowl |=(b=bowl b(our ~dev, src ~dev, now *@da))) + =/ =metadata:r [%test (my ['inviter' '~dev'] ~)] + =/ describe [token metadata] + ;< caz=(list card) bind:m (do-poke %reel-describe !>(describe)) + ;< bw=bowl bind:m get-bowl + =/ nonce (scot %da now.bw) + =/ edited-md [%test (~(put by fields.metadata) 'bite-type' '2')] + :: make sure we're sending a describe request to the bait provider + ;< * bind:m + %+ ex-cards caz + =/ request [nonce edited-md] + ~[(ex-poke /describe [civ %bait] bait-describe+!>(request))] + ;< state=vase bind:m get-save + =+ !<(reel-state state) + :: ensure link metadata added to our state and has bite-type field + ;< * bind:m (ex-equal !>(our-metadata) !>((my [nonce edited-md] ~))) + :: ensure nonce is added to open-describes set + ;< * bind:m (ex-equal !>(open-describes) !>((sy [nonce] ~))) + :: ensure stable-id has an entry for the token + ;< * bind:m (ex-equal !>(stable-id) !>((my [token nonce] ~))) + :: simulate the bait provider returning the new metadata + ;< bw=bowl bind:m get-bowl + =/ real-token (shax (jam [dap eny.bw])) + ;< * bind:m (jab-bowl |=(b=bowl b(src civ))) + ;< * bind:m (do-poke %reel-confirmation !>([nonce real-token])) + ;< state=vase bind:m get-save + =+ !<(reel-state state) + ;< * bind:m (ex-equal !>(open-describes) !>(~)) + ;< * bind:m (ex-equal !>(stable-id) !>((sy [token real-token] ~))) + (ex-equal !>(our-metadata) !>((my [real-token edited-md] ~))) +:: +:: testing old way of distributing links from requester side +++ test-reel-token-link-requester + %- eval-mare + =/ m (mare ,~) + ;< * bind:m (do-init dap reel-agent) + ;< * bind:m (jab-bowl |=(b=bowl b(our ~dev, src ~dev, now *@da))) + ;< bw=bowl bind:m get-bowl + =/ request-path /token-link/(scot %p ~bus)/[dap] + :: simulate subscription from frontend for link + ;< caz=(list card) bind:m + (do-watch request-path) + =/ next (add now.bw ~h1) + =/ expire=wire /expire/(scot %p ~bus)/[dap] + ;< * bind:m + %+ ex-cards caz + =/ =cage reel-want-token-link+!>(dap) + :~ (ex-poke request-path [~bus dap] cage) + (ex-arvo expire %b %wait next) + == + ;< state=vase bind:m get-save + =+ !<(reel-state state) + =/ new-requests (sy [~bus dap] ~) + :: ensure that the request is in the open-link-requests set + ;< * bind:m (ex-equal !>(open-link-requests) !>(new-requests)) + ;< * bind:m (jab-bowl |=(b=bowl b(now next))) + ;< bw=bowl bind:m get-bowl + :: simulate link request expiring + ;< * bind:m (do-arvo expire %behn %wake ~) + ;< state=vase bind:m get-save + =+ !<(reel-state state) + :: make sure the request is removed from the open-link-requests set + ;< * bind:m (ex-equal !>(open-link-requests) !>(~)) + :: try to get the link again, but this time not expiring + ;< * bind:m (do-watch request-path) + =/ url (cat 3 vic '~bus/reel-test') + =/ response `[dap url] + ;< * bind:m (jab-bowl |=(b=bowl b(src ~bus))) + ;< caz=(list card) bind:m (do-poke %reel-give-token-link !>(response)) + %+ ex-cards caz + ~[(ex-fact ~[request-path] %json !>(s+url))] +:: +:: testing old way of distributing links from dispenser side +++ test-reel-token-link-dispenser + %- eval-mare + =/ m (mare ,~) + ;< * bind:m (do-init dap reel-agent) + ;< * bind:m (jab-bowl |=(b=bowl b(our ~bus, src ~bus))) + :: build state for link + =/ fields=(map cord cord) (my ['inviter' '~zod'] ~) + =/ init-state=vase + !> + :* %4 + vic + civ + (my [token %meta fields] ~) + ~ + ~ + (my [token token] ~) + == + ;< * bind:m (do-load reel-agent `init-state) + ;< * bind:m (jab-bowl |=(b=bowl b(src ~zod))) + :: simulate link request + ;< caz=(list card) bind:m (do-poke %reel-want-token-link !>(token)) + %+ ex-cards caz + =/ url (cat 3 vic '~bus/reel-test') + =/ =cage reel-give-token-link+!>(`[token url]) + ~[(ex-poke /token-link-want/[token] [~zod dap] cage)] +-- \ No newline at end of file From a2441284f5d416e79935e1666615633bef6a7df3 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Wed, 28 Aug 2024 16:13:32 -0500 Subject: [PATCH 08/18] Fix issue with subscribeOnce to reel's token-link not always returning a value --- desk/app/reel.hoon | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/desk/app/reel.hoon b/desk/app/reel.hoon index a51b554e..caea752a 100644 --- a/desk/app/reel.hoon +++ b/desk/app/reel.hoon @@ -108,14 +108,16 @@ =+ !<(token=cord vase) :_ this =/ result=(unit [cord cord]) - ?. (~(has by our-metadata) token) ~ + ?. (~(has by our-metadata) token) `[token ''] `[token (url-for-token vic our.bowl token)] ~[[%pass [%token-link-want token ~] %agent [src.bowl %reel] %poke %reel-give-token-link !>(result)]] %reel-give-token-link =+ !<(result=(unit [cord cord]) vase) ?~ result `this - =/ [token=cord url=cord] u.result :_ this + =/ [token=cord url=cord] u.result + ?: =('' url) + ~[[%give %fact ~[[%token-link (scot %p src.bowl) token ~]] %json !>(~)]] ~[[%give %fact ~[[%token-link (scot %p src.bowl) token ~]] %json !>(s+url)]] == :: From 51d8fac6c9089c2ffb76e90314c0fe2f4a9c7f38 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Thu, 29 Aug 2024 16:49:36 -0500 Subject: [PATCH 09/18] reel: make sure we don't make the same link again --- desk/app/reel.hoon | 1 + 1 file changed, 1 insertion(+) diff --git a/desk/app/reel.hoon b/desk/app/reel.hoon index c0d4df63..8f68d78a 100644 --- a/desk/app/reel.hoon +++ b/desk/app/reel.hoon @@ -118,6 +118,7 @@ %reel-describe ?> =(our.bowl src.bowl) =+ !<([token=cord =metadata:reel] vase) + ?~ (~(has by stable-id) token) `this :: the token here is a temporary identifier for the metadata :: a new one will be assigned by the bait provider and returned to us =/ new-fields (~(put by fields.metadata) 'bite-type' '2') From 9c68eb20fd4905fd507649209a341a6f3449c98f Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Thu, 29 Aug 2024 16:49:54 -0500 Subject: [PATCH 10/18] bait: modifications to support new flow --- desk/app/bait.hoon | 113 +++++++++++++++++++++------ desk/tests/app/bait.hoon | 165 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 252 insertions(+), 26 deletions(-) create mode 100644 desk/tests/app/bait.hoon diff --git a/desk/app/bait.hoon b/desk/app/bait.hoon index 34251e9a..317c7eb5 100644 --- a/desk/app/bait.hoon +++ b/desk/app/bait.hoon @@ -5,6 +5,7 @@ +$ versioned-state $% state-0 state-1 + state-2 == :: +$ state-0 @@ -15,6 +16,10 @@ $: %1 token-metadata=(map [inviter=ship token=cord] metadata:reel) == ++$ state-2 + $: %2 + token-metadata=(map token=cord metadata:reel) + == -- :: |% @@ -53,7 +58,7 @@ == -- :: -=| state-1 +=| state-2 =* state - :: %- agent:dbug @@ -72,10 +77,22 @@ ^- (quip card _this) =/ old !<(versioned-state old-state) ?- -.old - %1 + %2 `this(state old) + :: + %1 + =/ new-metadata + %- ~(gas by *(map cord metadata:reel)) + %+ turn + ~(tap by token-metadata.old) + |= [[inviter=ship token=cord] meta=metadata:reel] + =/ new-token + (crip "{(trip (scot %p inviter))}/{(trip token)}") + [new-token meta] + `this(state [%2 new-metadata]) + :: %0 - `this(state *state-1) + `this(state *state-2) == :: ++ on-poke @@ -88,53 +105,97 @@ :_ this =/ full-line=request-line:server (parse-request-line:server url.request) =/ line - ?: ?=([%lure @ @ *] site.full-line) + ?: ?=([%lure @ *] site.full-line) t.site.full-line ?: ?=([@ @ *] site.full-line) site.full-line !! ?+ method.request (give not-found:gen:server) - %'GET' - ?: ?=([%bait %who ~] line) - (give (json-response:gen:server s+(scot %p our.bowl))) - =/ inviter (slav %p i.line) - =/ token i.t.line - =/ =metadata:reel (fall (~(get by token-metadata) [inviter token]) *metadata:reel) - ?: ?=([@ @ %metadata ~] line) - (give (json-response:gen:server (enjs-metadata metadata))) - (give (manx-response:gen:server (landing-page metadata))) + %'GET' (get-request line) + :: %'POST' - =/ inviter (slav %p i.line) - =/ token i.t.line ?~ body.request + ~& "body not found" (give not-found:gen:server) ?. =('ship=%7E' (end [3 8] q.u.body.request)) + ~& "ship not found in body" (give not-found:gen:server) =/ joiner (slav %p (cat 3 '~' (rsh [3 8] q.u.body.request))) - :* :* %pass /bite %agent [inviter %reel] - %poke %reel-bite !>([%bite-1 token joiner inviter]) - == - :* %pass /bite %agent [our.bowl %reel] - %poke %reel-bite !>([%bite-1 token joiner inviter]) - == - (give (manx-response:gen:server (sent-page joiner))) - == + =; [=bite:reel inviter=(unit ship)] + ?~ inviter + ~& "inviter not found" + (give not-found:gen:server) + ^- (list card) + :* :* %pass /bite %agent [u.inviter %reel] + %poke %reel-bite !>(bite) + == + :* %pass /bite %agent [our.bowl %reel] + %poke %reel-bite !>(bite) + == + (give (manx-response:gen:server (sent-page joiner))) + == + =/ =(pole knot) line + ?: ?=([@ @ ~] line) + =/ inviter (slav %p i.line) + =/ old-token i.t.line + :_ `inviter + [%bite-1 (scot %t old-token) joiner inviter] + =/ token + ?~ ext.full-line i.line + (crip "{(trip i.line)}.{(trip u.ext.full-line)}") + =/ =metadata:reel (~(gut by token-metadata) token *metadata:reel) + ?~ type=(~(get by fields.metadata) 'bite-type') + ~|("no bite type for token: {}" !!) + ?> =('2' u.type) + :_ + ?~ inviter-field=(~(get by fields.metadata) 'inviter') ~ + `(slav %p u.inviter-field) + [%bite-2 token joiner metadata] == + ++ get-request + |= =(pole knot) + ^- (list card) + ?+ pole (give not-found:gen:server) + [%bait %who ~] + (give (json-response:gen:server s+(scot %p our.bowl))) + :: + [ship=@ name=@ %metadata ~] + =/ token (crip "{(trip ship.pole)}/{(trip name.pole)}") + =/ =metadata:reel + (~(gut by token-metadata) token *metadata:reel) + (give (json-response:gen:server (enjs-metadata metadata))) + :: + [token=@ %metadata ~] + =/ =metadata:reel + (~(gut by token-metadata) token.pole *metadata:reel) + (give (json-response:gen:server (enjs-metadata metadata))) + :: + [token=* ~] + =/ token (crip (join '/' pole)) + =/ =metadata:reel + (~(gut by token-metadata) token *metadata:reel) + (give (manx-response:gen:server (landing-page metadata))) + == :: ++ give |= =simple-payload:http (give-simple-payload:app:server id simple-payload) -- %bait-describe - =+ !<([token=cord =metadata:reel] vase) - `this(token-metadata (~(put by token-metadata) [src.bowl token] metadata)) + =+ !<([nonce=cord =metadata:reel] vase) + =/ token=cord (scot %uv (end [3 16] eny.bowl)) + :_ this(token-metadata (~(put by token-metadata) token metadata)) + =/ =cage reel-confirmation+!>([nonce token]) + ~[[%pass /confirm/[nonce] %agent [src.bowl %reel] %poke cage]] :: %bait-undescribe =+ !<(token=cord vase) - `this(token-metadata (~(del by token-metadata) [src.bowl token])) + `this(token-metadata (~(del by token-metadata) token)) + :: %bind-slash :_ this ~[[%pass /eyre/connect %arvo %e %connect [~ /] dap.bowl]] + :: %unbind-slash :_ this ~[[%pass /eyre/connect %arvo %e %connect [~ /] %docket]] diff --git a/desk/tests/app/bait.hoon b/desk/tests/app/bait.hoon new file mode 100644 index 00000000..eff1a7a0 --- /dev/null +++ b/desk/tests/app/bait.hoon @@ -0,0 +1,165 @@ +/- r=reel, spider +/+ *test-agent, reel, strandio, server +/= bait-agent /app/bait +|% +++ dap %bait-test +++ vic 'https://tlon.network/lure/' +++ civ ~loshut-lonreg +++ eny + `@uv`0xffff.ffff.ffff.ffff.ffff.ffff.ffff.ffff +++ nonce '~2000.1.1' +++ token `@t`(scot %uv (end [3 16] eny)) ++$ bait-state + $: %2 + metadata=(map cord metadata:r) + == +++ test-bait-describe + %- eval-mare + =/ m (mare ,~) + ;< * bind:m (do-init dap bait-agent) + ;< * bind:m (jab-bowl |=(b=bowl b(our civ, src ~dev, eny eny))) + =/ =metadata:r [%test (my ['inviter' '~dev'] ['bite-type' '2'] ~)] + =/ describe [nonce metadata] + ;< caz=(list card) bind:m (do-poke %bait-describe !>(describe)) + ;< * bind:m + %+ ex-cards caz + ~[(ex-poke /confirm/[nonce] [~dev %reel] reel-confirmation+!>([nonce token]))] + ;< state=vase bind:m get-save + =+ !<(bait-state state) + (ex-equal !>(metadata) !>((my [token ^metadata] ~))) +++ test-bait-who-get + %- eval-mare + =/ m (mare ,~) + ;< * bind:m (do-init dap bait-agent) + ;< * bind:m (jab-bowl |=(b=bowl b(our ~dev))) + =/ simple-payload + (json-response:gen:server s+(scot %p ~dev)) + :: request 1: test old style tokens + =/ eyre-id %eyre-request-1 + =/ request=[id=@ta inbound-request:eyre] + [eyre-id (eyre-get-request '/lure/bait/who')] + ;< caz=(list card) bind:m (do-poke %handle-http-request !>(request)) + %+ ex-cards caz + (eyre-request-cards eyre-id simple-payload) +++ test-bait-metadata-get + %- eval-mare + =/ m (mare ,~) + ;< * bind:m (do-init dap bait-agent) + ;< * bind:m (jab-bowl |=(b=bowl b(our civ, src civ, eny eny))) + =/ =metadata:r [%test (my ['title' 'test-group'] ~)] + =/ init-state=bait-state + :- %2 + (my ['~zod/test' metadata] [token metadata] ~) + ;< * bind:m (do-load bait-agent `!>(init-state)) + =/ simple-payload + (json-response:gen:server (enjs-metadata:reel metadata)) + :: request 1: test old style tokens + =/ eyre-id %eyre-request-1 + =/ request=[id=@ta inbound-request:eyre] + [eyre-id (eyre-get-request '/lure/~zod/test/metadata')] + ;< caz=(list card) bind:m (do-poke %handle-http-request !>(request)) + ;< * bind:m + %+ ex-cards caz + (eyre-request-cards eyre-id simple-payload) + :: request 2: test new style tokens + =/ eyre-id %eyre-request-2 + =/ request=[id=@ta inbound-request:eyre] + [eyre-id (eyre-get-request (crip "/lure/{(trip token)}/metadata"))] + ;< caz=(list card) bind:m (do-poke %handle-http-request !>(request)) + %+ ex-cards caz + (eyre-request-cards eyre-id simple-payload) +:: +++ test-bait-bite-post + %- eval-mare + =/ m (mare ,~) + ;< * bind:m (do-init dap bait-agent) + ;< * bind:m (jab-bowl |=(b=bowl b(our civ, src civ, eny eny))) + =/ m1=metadata:r [%test (my ['title' 'test-group'] ~)] + =/ m2=metadata:r + :- %test + %- my + :~ ['title' 'test-group'] + ['bite-type' '2'] + ['inviter' '~dev'] + == + =/ init-state=bait-state + :- %2 + (my ['~zod/test' m1] [token m2] ~) + ;< * bind:m (do-load bait-agent `!>(init-state)) + =/ payload (as-octs:mimes:html 'ship=%7Erus') + =/ simple-payload + (manx-response:gen:server (sent-page ~rus)) + :: request 1: test new style tokens + =/ eyre-id %eyre-request-1 + =/ request=[id=@ta inbound-request:eyre] + [eyre-id (eyre-post-request (cat 3 '/lure/' token) payload)] + ;< caz=(list card) bind:m (do-poke %handle-http-request !>(request)) + ;< * bind:m + %+ ex-cards caz + =/ =cage reel-bite+!>([%bite-2 token ~rus m2]) + %+ welp + :~ (ex-poke /bite [~dev %reel] cage) + (ex-poke /bite [civ %reel] cage) + == + (eyre-request-cards eyre-id simple-payload) + :: request 2: test old style tokens + =/ eyre-id %eyre-request-2 + =/ request=[id=@ta inbound-request:eyre] + [eyre-id (eyre-post-request '/lure/~zod/test' payload)] + ;< caz=(list card) bind:m (do-poke %handle-http-request !>(request)) + %+ ex-cards caz + =/ =cage reel-bite+!>([%bite-1 token ~rus m1]) + %+ welp + :~ (ex-poke /bite [~dev %reel] cage) + (ex-poke /bite [civ %reel] cage) + == + (eyre-request-cards eyre-id simple-payload) +++ eyre-get-request + |= url=@t + :* | + & + *address:eyre + :* %'GET' + url + ~ + ~ + == + == +:: +++ eyre-post-request + |= [url=@t payload=octs] + :* | + & + *address:eyre + :* %'POST' + url + ~ + `payload + == + == +++ eyre-request-cards + |= [id=@ta =simple-payload:http] + ^- (list $-(card tang)) + =/ paths ~[/http-response/[id]] + =/ header-cage + [%http-response-header !>(response-header.simple-payload)] + =/ data-cage + [%http-response-data !>(data.simple-payload)] + %- limo + :~ (ex-fact paths header-cage) + (ex-fact paths data-cage) + (ex-card [%give %kick paths ~]) + == +++ sent-page + |= invitee=ship + ^- manx + ;html + ;head + ;title:"Lure" + == + ;body + Your invite has been sent! Go to your ship to accept it. + ;script: document.cookie="ship={(trip (scot %p invitee))}" + == + == +-- \ No newline at end of file From 28a5c4bafe2b071325085b4f1eed3b0fb3194c76 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Tue, 3 Sep 2024 11:28:36 -0500 Subject: [PATCH 11/18] bait: better conditional ordering Co-authored-by: fang --- desk/app/bait.hoon | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/desk/app/bait.hoon b/desk/app/bait.hoon index 317c7eb5..4c170a4e 100644 --- a/desk/app/bait.hoon +++ b/desk/app/bait.hoon @@ -147,10 +147,9 @@ ?~ type=(~(get by fields.metadata) 'bite-type') ~|("no bite type for token: {}" !!) ?> =('2' u.type) - :_ - ?~ inviter-field=(~(get by fields.metadata) 'inviter') ~ - `(slav %p u.inviter-field) - [%bite-2 token joiner metadata] + :- [%bite-2 token joiner metadata] + ?~ inviter-field=(~(get by fields.metadata) 'inviter') ~ + `(slav %p u.inviter-field) == ++ get-request |= =(pole knot) From e7394874b77d8106bffe178c2d442a241b9a850f Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Tue, 3 Sep 2024 12:15:51 -0500 Subject: [PATCH 12/18] reel,bait: improving types, fixing tests, adding body to 404s --- desk/app/bait.hoon | 14 +++++++------- desk/app/reel.hoon | 24 ++++++++++++------------ desk/sur/reel.hoon | 6 ++++-- desk/tests/app/bait.hoon | 8 ++++---- desk/tests/app/reel.hoon | 6 +++--- 5 files changed, 30 insertions(+), 28 deletions(-) diff --git a/desk/app/bait.hoon b/desk/app/bait.hoon index 317c7eb5..63da6408 100644 --- a/desk/app/bait.hoon +++ b/desk/app/bait.hoon @@ -115,16 +115,13 @@ :: %'POST' ?~ body.request - ~& "body not found" - (give not-found:gen:server) + (give-not-found 'body not found') ?. =('ship=%7E' (end [3 8] q.u.body.request)) - ~& "ship not found in body" - (give not-found:gen:server) + (give-not-found 'ship not found in body') =/ joiner (slav %p (cat 3 '~' (rsh [3 8] q.u.body.request))) =; [=bite:reel inviter=(unit ship)] ?~ inviter - ~& "inviter not found" - (give not-found:gen:server) + (give-not-found 'inviter not found') ^- (list card) :* :* %pass /bite %agent [u.inviter %reel] %poke %reel-bite !>(bite) @@ -139,7 +136,7 @@ =/ inviter (slav %p i.line) =/ old-token i.t.line :_ `inviter - [%bite-1 (scot %t old-token) joiner inviter] + [%bite-1 old-token joiner inviter] =/ token ?~ ext.full-line i.line (crip "{(trip i.line)}.{(trip u.ext.full-line)}") @@ -177,6 +174,9 @@ (give (manx-response:gen:server (landing-page metadata))) == :: + ++ give-not-found + |= body=cord + (give [[404 ~] `(as-octs:mimes:html body)]) ++ give |= =simple-payload:http (give-simple-payload:app:server id simple-payload) diff --git a/desk/app/reel.hoon b/desk/app/reel.hoon index 8f68d78a..3025666a 100644 --- a/desk/app/reel.hoon +++ b/desk/app/reel.hoon @@ -48,10 +48,10 @@ $: %4 vic=@t civ=ship - our-metadata=(map cord metadata:reel) + our-metadata=(map token:reel metadata:reel) open-link-requests=(set (pair ship cord)) - open-describes=(set cord) - stable-id=(map cord cord) + open-describes=(set token:reel) + stable-id=(map cord token:reel) == :: url with old style token ++ url-for-token @@ -117,16 +117,16 @@ :: %reel-describe ?> =(our.bowl src.bowl) - =+ !<([token=cord =metadata:reel] vase) - ?~ (~(has by stable-id) token) `this + =+ !<([id=cord =metadata:reel] vase) + ?~ (~(has by stable-id) id) `this :: the token here is a temporary identifier for the metadata :: a new one will be assigned by the bait provider and returned to us =/ new-fields (~(put by fields.metadata) 'bite-type' '2') =/ new-metadata metadata(fields new-fields) - =/ nonce=cord (scot %da now.bowl) + =/ =nonce:reel (scot %da now.bowl) =. our-metadata (~(put by our-metadata) nonce new-metadata) =. open-describes (~(put in open-describes) nonce) - =. stable-id (~(put by stable-id) token nonce) + =. stable-id (~(put by stable-id) id nonce) :_ this ~[[%pass /describe %agent [civ %bait] %poke %bait-describe !>([nonce new-metadata])]] :: @@ -136,10 +136,10 @@ =. open-describes (~(del in open-describes) nonce) ?~ md=(~(get by our-metadata) nonce) ~|("no metadata for nonce: {}" !!) - =/ ids=(list [id=cord token=cord]) + =/ ids=(list [id=cord =token:reel]) %+ skim ~(tap by stable-id) - |= [key=cord token=cord] + |= [key=cord =token:reel] =(nonce token) ?~ ids ~|("no stable id for nonce: {}" !!) @@ -153,7 +153,7 @@ :: %reel-undescribe ?> =(our.bowl src.bowl) - =+ !<(token=cord vase) + =+ !<(=token:reel vase) :: the token here should be the actual token given to us by the provider :_ this(our-metadata (~(del by our-metadata) token)) ~[[%pass /undescribe %agent [civ %bait] %poke %bait-undescribe !>(token)]] @@ -161,7 +161,7 @@ :: are unique to that ship/user and can be scried out :: %reel-want-token-link - =+ !<(token=cord vase) + =+ !<(=token:reel vase) :_ this =/ result=(unit [cord cord]) ?. (~(has by our-metadata) token) ~ @@ -232,7 +232,7 @@ ``reel-metadata+!>(metadata) :: [%x any %token-url token=*] - =/ token (crip (join '/' token.pole)) + =/ =token:reel (crip (join '/' token.pole)) =/ url (url-for-token vic token) ``reel-token-url+!>(url) :: diff --git a/desk/sur/reel.hoon b/desk/sur/reel.hoon index c54302eb..1f46275c 100644 --- a/desk/sur/reel.hoon +++ b/desk/sur/reel.hoon @@ -7,9 +7,11 @@ +$ bite $% [%bite-0 token=@ta ship=@p] [%bite-1 token=@ta joiner=@p inviter=@p] - [%bite-2 token=cord joiner=@p =metadata] + [%bite-2 =token joiner=@p =metadata] == :: ++$ token cord ++$ nonce @ta +$ metadata [tag=term fields=(map cord cord)] -+$ confirmation [nonce=cord token=cord] ++$ confirmation [=nonce =token] -- diff --git a/desk/tests/app/bait.hoon b/desk/tests/app/bait.hoon index eff1a7a0..e1bc3c3a 100644 --- a/desk/tests/app/bait.hoon +++ b/desk/tests/app/bait.hoon @@ -7,11 +7,11 @@ ++ civ ~loshut-lonreg ++ eny `@uv`0xffff.ffff.ffff.ffff.ffff.ffff.ffff.ffff -++ nonce '~2000.1.1' +++ nonce `@ta`'~2000.1.1' ++ token `@t`(scot %uv (end [3 16] eny)) +$ bait-state $: %2 - metadata=(map cord metadata:r) + metadata=(map token:r metadata:r) == ++ test-bait-describe %- eval-mare @@ -108,9 +108,9 @@ [eyre-id (eyre-post-request '/lure/~zod/test' payload)] ;< caz=(list card) bind:m (do-poke %handle-http-request !>(request)) %+ ex-cards caz - =/ =cage reel-bite+!>([%bite-1 token ~rus m1]) + =/ =cage reel-bite+!>([%bite-1 `@ta`'test' ~rus ~zod]) %+ welp - :~ (ex-poke /bite [~dev %reel] cage) + :~ (ex-poke /bite [~zod %reel] cage) (ex-poke /bite [civ %reel] cage) == (eyre-request-cards eyre-id simple-payload) diff --git a/desk/tests/app/reel.hoon b/desk/tests/app/reel.hoon index c4239854..7bc662cf 100644 --- a/desk/tests/app/reel.hoon +++ b/desk/tests/app/reel.hoon @@ -10,10 +10,10 @@ $: %4 vic=@t civ=ship - our-metadata=(map cord metadata:r) + our-metadata=(map token:r metadata:r) open-link-requests=(set (pair ship cord)) - open-describes=(set cord) - stable-id=(map cord cord) + open-describes=(set token:r) + stable-id=(map cord token:r) == ++ test-reel-describe %- eval-mare From 5919bf6f97ed920104602f4cb74d01cfc8425611 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Tue, 3 Sep 2024 16:30:08 -0500 Subject: [PATCH 13/18] bait: using type aliases, fixing pr feedback --- desk/app/bait.hoon | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/desk/app/bait.hoon b/desk/app/bait.hoon index d4a1a45d..08f7ae70 100644 --- a/desk/app/bait.hoon +++ b/desk/app/bait.hoon @@ -18,7 +18,7 @@ == +$ state-2 $: %2 - token-metadata=(map token=cord metadata:reel) + token-metadata=(map token:reel metadata:reel) == -- :: @@ -82,12 +82,12 @@ :: %1 =/ new-metadata - %- ~(gas by *(map cord metadata:reel)) + %- ~(gas by *(map token:reel metadata:reel)) %+ turn ~(tap by token-metadata.old) - |= [[inviter=ship token=cord] meta=metadata:reel] + |= [[inviter=ship =token:reel] meta=metadata:reel] =/ new-token - (crip "{(trip (scot %p inviter))}/{(trip token)}") + (rap 3 (scot %p inviter) '/' token ~) [new-token meta] `this(state [%2 new-metadata]) :: @@ -123,6 +123,7 @@ ?~ inviter (give-not-found 'inviter not found') ^- (list card) + :: TODO: figure out if we need to send both pokes :* :* %pass /bite %agent [u.inviter %reel] %poke %reel-bite !>(bite) == @@ -181,8 +182,8 @@ (give-simple-payload:app:server id simple-payload) -- %bait-describe - =+ !<([nonce=cord =metadata:reel] vase) - =/ token=cord (scot %uv (end [3 16] eny.bowl)) + =+ !<([=nonce:reel =metadata:reel] vase) + =/ =token:reel (scot %uv (end [3 16] eny.bowl)) :_ this(token-metadata (~(put by token-metadata) token metadata)) =/ =cage reel-confirmation+!>([nonce token]) ~[[%pass /confirm/[nonce] %agent [src.bowl %reel] %poke cage]] From 7448dc721fe5f0d5ee7ea77eaa46344eb3bb026f Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Tue, 3 Sep 2024 16:33:34 -0500 Subject: [PATCH 14/18] reel: clarifying open-link-requests comment --- desk/app/reel.hoon | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/desk/app/reel.hoon b/desk/app/reel.hoon index 3025666a..c068baa3 100644 --- a/desk/app/reel.hoon +++ b/desk/app/reel.hoon @@ -13,7 +13,8 @@ :: vic: URL of bait service :: civ: @p of bait service :: our-metadata: a mapping from nonce/token to metadata -:: open-link-requests: open requests for an existing foreign link, DEPRECATED +:: open-link-requests: open requests for an existing foreign link, v0 +:: lure links only :: open-describes: attempts to create a link waiting to be assigned a token :: stable-id: a mapping from something the client can use to identify the :: metadata to nonce and/or token From 9bbc39a17b787649eb30be6defde4e6f30725e13 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Fri, 6 Sep 2024 15:43:48 -0500 Subject: [PATCH 15/18] reel: fixing meta and url scries, token rotation, and extra metadata --- desk/app/reel.hoon | 44 +++++++++++++++++++++++++++---------- desk/ted/reel/set-ship.hoon | 2 +- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/desk/app/reel.hoon b/desk/app/reel.hoon index 78bf8edc..1578be10 100644 --- a/desk/app/reel.hoon +++ b/desk/app/reel.hoon @@ -119,16 +119,27 @@ %reel-describe ?> =(our.bowl src.bowl) =+ !<([id=cord =metadata:reel] vase) - ?~ (~(has by stable-id) id) `this - :: the token here is a temporary identifier for the metadata - :: a new one will be assigned by the bait provider and returned to us - =/ new-fields (~(put by fields.metadata) 'bite-type' '2') + =/ old-token (~(get by stable-id) id) + =/ new-fields + %- ~(gas by fields.metadata) + :~ ['bite-type' '2'] + ['inviter' (scot %p src.bowl)] + ['group' id] + == =/ new-metadata metadata(fields new-fields) + :: the nonce here is a temporary identifier for the metadata + :: a new one will be assigned by the bait provider and returned to us =/ =nonce:reel (scot %da now.bowl) + :: delete old metadata if we have an existing token for this id + =? our-metadata ?=(^ old-token) + (~(del by our-metadata) u.old-token) =. our-metadata (~(put by our-metadata) nonce new-metadata) =. open-describes (~(put in open-describes) nonce) =. stable-id (~(put by stable-id) id nonce) :_ this + %+ welp + ?~ old-token ~ + ~[[%pass /undescribe %agent [civ %bait] %poke %bait-undescribe !>(u.old-token)]] ~[[%pass /describe %agent [civ %bait] %poke %bait-describe !>([nonce new-metadata])]] :: %reel-confirmation @@ -229,21 +240,30 @@ =/ has (~(has in open-link-requests) [(slav %p ship.pole) name.pole]) ``json+!>([%b has]) :: - [%x any %metadata token=@ ~] - =/ =metadata:reel (fall (~(get by our-metadata) token.pole) *metadata:reel) + [%x %v1 %metadata ship=@ name=@ ~] + =/ id (rap 3 ship.pole '/' name.pole ~) + =/ token (~(get by stable-id) id) + ?~ token [~ ~] + =/ =metadata:reel (fall (~(get by our-metadata) u.token) *metadata:reel) + ``reel-metadata+!>(metadata) + :: + [%x %v0 %metadata name=@ ~] + :: old style tokens are directly in metadata + =/ id (rap 3 (scot %p our.bowl) '/' name.pole ~) + =/ =metadata:reel (fall (~(get by our-metadata) id) *metadata:reel) ``reel-metadata+!>(metadata) :: [%x any %token-url token=*] - =/ =token:reel (crip (join '/' token.pole)) + =/ =token:reel (crip +:(spud token.pole)) =/ url (url-for-token vic token) - ``reel-token-url+!>(url) + ``json+!>(s+url) :: [%x %v1 %id-url id=*] - =/ id (crip (join '/' id.pole)) + =/ id (crip +:(spud id.pole)) ?~ token=(~(get by stable-id) id) - ``reel-token-url+!>('') - =/ url (cat 3 vic id) - ``reel-token-url+!>(url) + ``json+!>(s+'') + =/ url (cat 3 vic u.token) + ``json+!>(s+url) == :: ++ on-arvo diff --git a/desk/ted/reel/set-ship.hoon b/desk/ted/reel/set-ship.hoon index e891ccb0..0de8478b 100644 --- a/desk/ted/reel/set-ship.hoon +++ b/desk/ted/reel/set-ship.hoon @@ -11,7 +11,7 @@ =/ url ?: =(vic 'https://tlon.network/lure/') "https://tlon.network/v1/lure/bait/who" - "{(trip vic)}/bait/who" + "{(trip vic)}bait/who" ;< =json bind:m (fetch-json url) =/ =ship (slav %p (so:dejs:format json)) ;< ~ bind:m (poke [our %reel] reel-command+!>([%set-ship ship])) From 5e2b00cde864424d87ff08a3a5759f36cfe941c7 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Mon, 9 Sep 2024 12:27:06 -0500 Subject: [PATCH 16/18] reel: better indentation Co-authored-by: fang --- desk/app/reel.hoon | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/desk/app/reel.hoon b/desk/app/reel.hoon index 1578be10..e7051899 100644 --- a/desk/app/reel.hoon +++ b/desk/app/reel.hoon @@ -138,8 +138,8 @@ =. stable-id (~(put by stable-id) id nonce) :_ this %+ welp - ?~ old-token ~ - ~[[%pass /undescribe %agent [civ %bait] %poke %bait-undescribe !>(u.old-token)]] + ?~ old-token ~ + ~[[%pass /undescribe %agent [civ %bait] %poke %bait-undescribe !>(u.old-token)]] ~[[%pass /describe %agent [civ %bait] %poke %bait-describe !>([nonce new-metadata])]] :: %reel-confirmation From e4d08383ad291ab42c20e3b6ee02c8b79ba8143d Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Mon, 9 Sep 2024 12:34:40 -0500 Subject: [PATCH 17/18] reel: better tis work and updating tests --- desk/app/reel.hoon | 7 +++---- desk/tests/app/reel.hoon | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/desk/app/reel.hoon b/desk/app/reel.hoon index 1578be10..a712fd7c 100644 --- a/desk/app/reel.hoon +++ b/desk/app/reel.hoon @@ -120,27 +120,26 @@ ?> =(our.bowl src.bowl) =+ !<([id=cord =metadata:reel] vase) =/ old-token (~(get by stable-id) id) - =/ new-fields + =. fields.metadata %- ~(gas by fields.metadata) :~ ['bite-type' '2'] ['inviter' (scot %p src.bowl)] ['group' id] == - =/ new-metadata metadata(fields new-fields) :: the nonce here is a temporary identifier for the metadata :: a new one will be assigned by the bait provider and returned to us =/ =nonce:reel (scot %da now.bowl) :: delete old metadata if we have an existing token for this id =? our-metadata ?=(^ old-token) (~(del by our-metadata) u.old-token) - =. our-metadata (~(put by our-metadata) nonce new-metadata) + =. our-metadata (~(put by our-metadata) nonce metadata) =. open-describes (~(put in open-describes) nonce) =. stable-id (~(put by stable-id) id nonce) :_ this %+ welp ?~ old-token ~ ~[[%pass /undescribe %agent [civ %bait] %poke %bait-undescribe !>(u.old-token)]] - ~[[%pass /describe %agent [civ %bait] %poke %bait-describe !>([nonce new-metadata])]] + ~[[%pass /describe %agent [civ %bait] %poke %bait-describe !>([nonce metadata])]] :: %reel-confirmation ?> =(civ src.bowl) diff --git a/desk/tests/app/reel.hoon b/desk/tests/app/reel.hoon index 7bc662cf..ee7808db 100644 --- a/desk/tests/app/reel.hoon +++ b/desk/tests/app/reel.hoon @@ -20,7 +20,7 @@ =/ m (mare ,~) ;< * bind:m (do-init dap reel-agent) ;< * bind:m (jab-bowl |=(b=bowl b(our ~dev, src ~dev, now *@da))) - =/ =metadata:r [%test (my ['inviter' '~dev'] ~)] + =/ =metadata:r [%test (my ['inviter' '~dev'] ['group' '~bus/reel-test'] ~)] =/ describe [token metadata] ;< caz=(list card) bind:m (do-poke %reel-describe !>(describe)) ;< bw=bowl bind:m get-bowl From 404c03864a6109132420c9a454d2a22a72e6e104 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Wed, 11 Sep 2024 10:38:19 -0500 Subject: [PATCH 18/18] ops: version bump --- desk/desk.docket-0 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desk/desk.docket-0 b/desk/desk.docket-0 index 2c7fc72b..df65e62e 100644 --- a/desk/desk.docket-0 +++ b/desk/desk.docket-0 @@ -4,7 +4,7 @@ glob-http+['https://bootstrap.urbit.org/glob-0v7.the2a.smdhg.89k09.6ar0t.gb5te.glob' 0v7.the2a.smdhg.89k09.6ar0t.gb5te] ::glob-ames+~zod^0v0 base+'landscape' - version+[1 25 0] + version+[1 26 0] website+'https://tlon.io' license+'MIT' ==