@@ -0,0 +1,958 @@
2+title = "API Reference"
9+This app stores a number for each user. You can increment your number, increment
10+someone else's number, start tracking someone else's number by poking. It
11+exposes a scry namespace to inspect everyone's number.
13+### `app/example-gall.hoon`
16+:: Import sur/example-gall
18+:: Import lib/default-agent
21++$ card card:agent:gall
25+ [%agent [=ship name=term] =task:agent:gall]
27++$ state-zero [%0 local=@ud]
28++$ state-one [%1 local=@ud remote=(map @p @ud)]
40+ def ~(. (default-agent this %|) bowl)
42+:: Set local counter to 1 by default
46+:: Expose state for saving
50+:: Load old state and upgrade if neccessary
54+ =/ loaded=versioned-state
55+ !<(versioned-state old)
58+ `this(local local.loaded) :: Upgrade old state
64+:: App can be poked in the dojo by running the following commands
65+:: Increment local counter
66+:: :example-gall &example-gall-action [%increment ~]
67+:: Increment ~zod's counter
68+:: :example-gall &example-gall-action [%increment-remote ~zod]
69+:: Subscribe to ~zod's counter
70+:: :example-gall &example-gall-action [%view ~zod]
71+:: Unsubscribe from ~zod's counter
72+:: :example-gall &example-gall-action [%stop-view ~zod]
77+ :: Ensure poke is of mark %example-gall-action
78+ ?> =(mark %example-gall-action)
79+ =/ act=example-gall-action !<(example-gall-action vase)
82+ :: Increment local counter and send new counter to subscribers
85+ :- [%give %fact ~[/local] %atom !>(+(local))]~
88+ :: Send remote %increment poke
90+ [%increment-remote who=@p]
94+ /inc/(scot %p who.act)
96+ [who.act %example-gall]
97+ %poke %example-gall-action !>([%increment ~])
100+ :: Subscribe to a remote counter
104+ [%pass /view/(scot %p who.act) %agent [who.act %example-gall] %watch /local]~
106+ :: Unsubscribe from remote counter and remove from state
109+ :_ this(remote (~(del by remote) who.act))
110+ [%pass /view/(scot %p who.act) %agent [who.act %example-gall] %leave ~]~
114+:: Print on unsubscribe
118+ ^- (quip card _this)
119+ ~& "Unsubscribed by: {<src.bowl>} on: {<path>}"
122+:: Handle new subscription
124+:: When another ship subscribes to our counter, give them the current state of
125+:: the counter immediately
129+ ^- (quip card _this)
131+ :: Crash if we see a subscription we don't recognise
132+ ?+ path ~|("unexpected subscription" !!)
135+ [%give %fact ~ %atom !>(local)]~
138+:: Expose scry namespace
140+:: .^(@ %gx /=example-gall=/local/atom) will produce the current local counter
141+:: .^(@ %gx /=example-gall=/remote/~zod/atom) will produce the counter for ~zod
142+:: .^(arch %gy /=example-gall=/remote) will produce a listing of the current
146+ ^- (unit (unit cage))
149+ :: Produce local counter
154+ :: Produce remote counter
156+ [%x %remote who=@ta ~]
157+ =* location i.t.t.path :: Ship name is third in the list
159+ (~(got by remote) (slav %p location))
162+ :: Produce listing of remote counters
166+ %- molt :: Map from list of k-v pairs
167+ %+ turn :: iterate over list of k-v pairs
168+ ~(tap by remote) :: list of k-v pairs from map
171+ ``[%arch !>(`arch`[~ dir])]
174+:: Handle sign from agent
177+ |= [=wire =sign:agent:gall]
178+ ^- (quip card _this)
181+ :: Print error if poke failed
189+ :: Print error if subscription failed
194+ =/ =tank leaf+"subscribe failed from {<dap.bowl>} on wire {<wire>}"
195+ %- (slog tank u.p.sign)
198+ :: Do nothing if unsubscribed
202+ :: Update remote counter when we get a subscription update
206+ ?. ?=(%atom p.cage.sign)
208+ this(remote (~(put by remote) src.bowl !<(@ q.cage.sign)))
213+:: We never give any cards to arvo. Therefore we never need to handle any signs
214+:: from arvo. We use the default-agent library to avoid implementing this arm,
215+:: as gall apps must have all the arms.
217+++ on-arvo on-arvo:def
221+:: Print errors when they happen
225+ ^- (quip card _this)
226+ %- (slog leaf+"error in {<dap.bowl>}" >term< tang)
232+### `sur/example-gall.hoon`
236++$ example-gall-action
240+ [%increment-remote who=@p]
246+### `mar/example-gall/action.hoon`
250+|_ act=example-gall-action
253+ ++ noun example-gall-action
262+Application initialisation
264+`++on-init` is called when an application is first started. It is not a gate and
273+List of cards and new agent
278+:: From reference agent.
279+:: Set local counter to 1 by default
282+ ^- (quip card _this)
284+:: From app/weather.hoon. This setup is typical of a landscape tile.
288+ :~ [%pass /bind/weather %arvo %e %connect [~ /'~weather'] %weather]
289+ :* %pass /launch/weather %agent [our.bol %launch] %poke
290+ %launch-action !>([%weather /weathertile '/~weather/js/tile.js'])
297+Expose state for saving.
299+This arm is called immediately before the agent is upgraded. It packages the
300+permament state of the agent in a vase for the next version of the agent.
301+Unlike most handlers, this cannot produce effects. It is not a gate and has no input.
305+`vase` of permanent state.
310+:: From reference agent
312+:: Expose state for saving
322+This arm is called immediately after the agent is upgraded. It receives
323+a vase of the state of the previously-running version of the agent, obtained
324+from `+on-save`, which allows it to cleanly upgrade from the old agent.
332+`vase` of previous state, from `++on-save`
340+List of cards and new agent
345+:: From reference agent
347+:: Load old state and upgrade if neccessary
350+ ^- (quip card _this)
351+ =/ loaded=versioned-state
352+ !<(versioned-state old)
355+ `this(local local.loaded) :: Upgrade old state
363+Handle application poke.
365+This arm is called when the agent is "poked". The input is a cage, so
366+it's a pair of a mark and a dynamic vase.
374+`mark` is the mark of the poked data.
376+`vase` is a vase with the poked data inside.
384+List of cards and new agent.
389+:: From reference agent.
392+:: App can be poked in the dojo by running the following commands
393+:: Increment local counter
394+:: :example-gall &example-gall-action [%increment ~]
395+:: Increment ~zod's counter
396+:: :example-gall &example-gall-action [%increment-remote ~zod]
397+:: Subscribe to ~zod's counter
398+:: :example-gall &example-gall-action [%view ~zod]
399+:: Unsubscribe from ~zod's counter
400+:: :example-gall &example-gall-action [%stop-view ~zod]
404+ ^- (quip card _this)
405+ :: Ensure poke is of mark %example-gall-action
406+ ?> =(mark %example-gall-action)
407+ =/ act=example-gall-action !<(example-gall-action vase)
410+ :: Increment local counter and send new counter to subscribers
413+ :- [%give %fact ~[/local] %atom !>(+(local))]~
414+ this(local +(local))
416+ :: Send remote %increment poke
418+ [%increment-remote who=@p]
422+ /inc/(scot %p who.act)
424+ [who.act %example-gall]
425+ %poke %example-gall-action !>([%increment ~])
428+ :: Subscribe to a remote counter
432+ [%pass /view/(scot %p who.act) %agent [who.act %example-gall] %watch /local]~
434+ :: Unsubscribe from remote counter and remove from state
437+ :_ this(remote (~(del by remote) who.act))
438+ [%pass /view/(scot %p who.act) %agent [who.act %example-gall] %leave ~]~
445+Handle new subscriber.
447+This arm is called when a program wants to subscribe to the agent on a
448+particular path. The agent may or may not need to perform setup steps
449+to intialize the subscription. It may produce a `%give`
450+`%subscription-result` to the subscriber to get it up to date, but after
451+this event is complete, it cannot give further updates to a specific
452+subscriber. It must give all further updates to all subscribers on a
455+If this arm crashes, then the subscription is immediately terminated.
456+More specifcally, it never started -- the subscriber will receive a
457+negative `%watch-ack`. You may also produce an explicit `%kick` to
458+close the subscription without crashing -- for example, you could
459+produce a single update followed by a `%kick`.
467+Path of new subscription.
475+List of cards and new agent.
480+:: From reference agent
482+:: Handle new subscription
484+:: When another ship subscribes to our counter, give them the current state of
485+:: the counter immediately
489+ ^- (quip card _this)
491+ ?+ path on-watch:def
494+ [%give %fact ~ %atom !>(local)]~
502+This arm is called when a program becomes unsubscribed to you.
503+Subscriptions may close because the subscriber intentionally
504+unsubscribed, but they also could be closed by an intermediary. For
505+example, if a subscription is from another ship which is currently
506+unreachable, Ames may choose to close the subscription to avoid queueing
507+updates indefinitely. If the program crashes while processing an
508+update, this may also generate an unsubscription. You should consider
509+subscriptions to be closable at any time.
517+Path of the closed subscription.
525+List of cards and new agent.
530+:: From reference agent. Prints a message when programs become unsubscribed.
533+ ^- (quip card _this)
534+ ~& "Unsubscribe by: {<src.bowl>} on: {<path>}"
542+This arm is called when a program reads from the agent's "scry"
543+namespace, which should be referentially transparent. Unlike most
544+handlers, this cannot perform IO, and it cannot change the state. All
545+it can do is produce a piece of data to the caller, or not.
553+The path being scryed for.
556+:: Example scry to path mappings
558+.^(arch %gy /=example-gall=/remote)
559+:: Path will be /y/remote
560+.^(@ %gx /=example-gall=/local/atom)
561+:: Path will be /x/local
570+If this arm produces `[~ ~ data]`, then `data` is the value at the the
571+given path. If it produces `[~ ~]`, then there is no data at the given
572+path and never will be. If it produces `~`, then we don't know yet whether
573+there is or will be data at the given path. The head of the path is known as the
574+`care`. Requests with a care of `%x` should return a vase that matches or is
575+convertible to the mark at the end of the scry request. This mark is not
576+included in the path passed to `++on-peek`. Requests with a care of `%y` should
577+return a cage with a mark of `%arch` and a vase of `arch`.
582+:: From reference agent
584+:: Expose scry namespace
586+:: .^(@ %gx /=example-gall=/local/atom) will produce the current local counter
587+:: .^(@ %gx /=example-gall=/remote/~zod/atom) will produce the counter for ~zod
588+:: .^(arch %gy /=example-gall=/remote) will produce a listing of the current
592+ ^- (unit (unit cage))
595+ :: Produce local counter
600+ :: Produce remote counter
602+ [%x %remote who=@ta ~]
603+ =* location i.t.t.path :: Ship name is third in the list
605+ (~(got by remote) (slav %p location))
608+ :: Produce listing of remote counters
612+ %- molt :: Map from list of k-v pairs
613+ %+ turn :: iterate over list of k-v pairs
614+ ~(tap by remote) :: list of k-v pairs from map
617+ ``[%arch !>(`arch`[~ dir])]
625+This arm is called to handle responses to `%pass` cards to other agents.
626+It will be one of the following types of response:
628+- `%poke-ack`: acknowledgment (positive or negative) of a poke. If the
629+ value is `~`, then the poke succeeded. If the value is `[~ tang]`,
630+ then the poke failed, and a printable explanation (eg a stack trace)
631+ is given in the `tang`.
633+- `%watch-ack`: acknowledgment (positive or negative) of a subscription.
634+ If negative, the subscription is already ended (technically, it never
637+- `%fact`: update from the publisher.
639+- `%kick`: notification that the subscription has ended. This happens because
640+ either the target app passed a `%leave` note, or ames killed the subscription
641+ due to backpressure. Most of the time you will want to resubscribe. If you can
642+ no longer access the subscription you will get a negative `%watch-ack` and end
648+[=wire =sign:agent:gall]
651+`wire` is the wire from the `+gift` that triggered `++on-agent`
653+`sign` is response for the gift.
664+:: From reference agent
666+:: Handle sign from agent
669+ |= [=wire =sign:agent:gall]
670+ ^- (quip card _this)
673+ :: Print error if poke failed
681+ :: Print error if subscription failed
686+ =/ =tank leaf+"subscribe failed from {<dap.bowl>} on wire {<wire>}"
687+ %- (slog tank u.p.sign)
690+ :: Do nothing if unsubscribed
694+ :: Update remote counter when we get a subscription update
698+ ?. ?=(%atom p.cage.sign)
700+ this(remote (~(put by remote) src.bowl !<(@ q.cage.sign)))
708+This arm is called to handle responses for `%pass` cards to vanes.
713+ [=wire =sign:agent:gall]
716+`wire` is the wire from the `++gift` that triggered `++on-arvo`.
718+`sign` is the response from the vane. The list of possible responses from the
719+vanes is statically defined in sys/zuse.hoon (grep for `++ sign-arvo`).
727+List of cards and new agent.
732+:: From app/weather.hoon. Handles %bound, %wake and %http-response signs
734+ |= [=wire =sign-arvo]
735+ ^- (quip card:agent:gall _this)
736+ ?: ?=(%bound +<.sign-arvo)
738+ ?: ?=(%wake +<.sign-arvo)
740+ (wake:wc wire error.sign-arvo)
742+ ?: ?=(%http-response +<.sign-arvo)
744+ (http-response:wc wire client-response.sign-arvo)
746+ (on-arvo:def wire sign-arvo)
748+:: From reference agent
752+:: We never give any cards to arvo. Therefore we never need to handle any signs
753+:: from arvo. We use the default-agent library to avoid implementing this arm,
754+:: as gall apps must have all the arms specified in the agent:gall definition.
756+++ on-arvo on-arvo:def
763+If an error happens in `+on-poke`, the crash report goes into the
764+`%poke-ack` response. Similarly, if an error happens in
765+`+on-subscription`, the crash report goes into the `%watch-ack`
766+response. If a crash happens in any of the other handlers, the report
767+is passed into this arm.
775+`term` is a cord describing the error.
777+`tang` is a stack trace for the error.
785+List of cards and new agent
793+:: Print errors when they happen
797+ ^- (quip card _this)
798+ %- (slog leaf+"error in {<dap.bowl>}" >term< tang)
804+Giving a gift takes the general form of
812+Produce a subscription update.
814+Produces a subscription update. A subscription update is a new piece of
815+subscription content for all subscribers on a given path.
820+[%fact (list path) =cage]
823+`(list path)` is a list of the paths to send the update on. If no path is
824+given, then the update is only given to the program that instigated the
825+request. Typical use of this mode is in `+on-watch` to give an initial update
826+to a new subscriber to get them up to date.
828+`cage` is a cage of the subscription update.
833+:: From ++on-watch in reference agent.
835+:: Gives current local state to new subscribers.
836+[%give %fact ~ %atom !>(local.sta)]
839+:: From ++on-poke in reference agent
841+:: Gives incremented local state to any subscribers on /local
842+[%give %fact ~[/local] %atom !>(+(local))]
849+Closes a subscription. A subscription close closes the subscription for all or
850+one subscribers on a given path.
855+[%kick (unit path) (unit ship)]
858+`(unit path)` is the path of the subscription being updated. If no path is
859+given, then the update is only given to the program that instigated the request.
860+Typical use of this mode would be in `+on-watch` to produce a single update to a
861+subscription then close the subscription.
863+`(unit ship)` is the ship to close the subscription for. If no path is given,
864+then the subscription is closed for all subscribers.
868+Passing a agent note (a 'task') along a wire looks like so.
871+[%pass =wire %agent [=ship name=term] =task]
874+`wire` is used to identify the response to the note.
876+`ship` is the ship to pass the note to.
878+`name` is the name of the agent that should receive the note.
880+`task` is the task itself, described below.
886+This note is passed to poke an application with a cage, a marked vase.
894+`cage` is the marked data to poke the application with. It is a pair of a mark
900+:: From ++on-poke in reference agent.
902+:: Sends an increment poke to the example-gall agent
906+ /inc/(scot %p who.act)
908+ [who.act %example-gall]
909+ %poke %example-gall-action !>([%increment ~])
915+Subscribe to an application.
917+This note is given to subscribe to an application at a path
925+`path` is the path to be subscribed to.
930+:: From ++on-poke in reference agent.
932+:: Subscribes to the example-gall agent on who.act on the path /local
934+[%pass /view/(scot %p who.act) %agent [who.act %example-gall] %watch /local]
939+Unsubscribe from an application.
941+This note is passed to unsubscribe from an application. It should be passed on
942+the same wire that the corresponding `%watch` note for the subscription was
954+:: From ++on-poke in reference agent.
956+:: Unsubscribes from the example-gall agent on who.act
957+[%pass /view/(scot %p who.act) %agent [who.act %example-gall] %leave ~]