5This app stores a number for each user. You can increment your number, increment
6someone else's number, start tracking someone else's number by poking. It
7exposes a scry namespace to inspect everyone's number.
9### `app/example-gall.hoon`
12:: Import sur/example-gall
14:: Import lib/default-agent
17+$ card card:agent:gall
21 [%agent [=ship name=term] =task:agent:gall]
23+$ state-zero [%0 local=@ud]
24+$ state-one [%1 local=@ud remote=(map @p @ud)]
36 def ~(. (default-agent this %|) bowl)
38:: Set local counter to 1 by default
42:: Expose state for saving
46:: Load old state and upgrade if neccessary
50 =/ loaded=versioned-state
51 !<(versioned-state old)
54 `this(local local.loaded) :: Upgrade old state
60:: App can be poked in the dojo by running the following commands
61:: Increment local counter
62:: :example-gall &example-gall-action [%increment ~]
63:: Increment ~zod's counter
64:: :example-gall &example-gall-action [%increment-remote ~zod]
65:: Subscribe to ~zod's counter
66:: :example-gall &example-gall-action [%view ~zod]
67:: Unsubscribe from ~zod's counter
68:: :example-gall &example-gall-action [%stop-view ~zod]
73 :: Ensure poke is of mark %example-gall-action
74 ?> =(mark %example-gall-action)
75 =/ act=example-gall-action !<(example-gall-action vase)
78 :: Increment local counter and send new counter to subscribers
81 :- [%give %fact `/local %atom !>(+(local))]~
84 :: Send remote %increment poke
86 [%increment-remote who=@p]
90 /inc/(scot %p who.act)
92 [who.act %example-gall]
93 %poke %example-gall-action !>([%increment ~])
96 :: Subscribe to a remote counter
100 [%pass /view/(scot %p who.act) %agent [who.act %example-gall] %watch /local]~
102 :: Unsubscribe from remote counter and remove from state
105 :_ this(remote (~(del by remote) who.act))
106 [%pass /view/(scot %p who.act) %agent [who.act %example-gall] %leave ~]~
110:: Print on unsubscribe
115 ~& "Unsubscribed by: {<src.bowl>} on: {<path>}"
118:: Handle new subscription
120:: When another ship subscribes to our counter, give them the current state of
121:: the counter immediately
127 :: Crash if we see a subscription we don't recognise
128 ?+ path ~|("unexpected subscription" !!)
131 [%give %fact ~ %atom !>(local)]~
134:: Expose scry namespace
136:: .^(@ %gx /=example-gall=/local/atom) will produce the current local counter
137:: .^(@ %gx /=example-gall=/remote/~zod/atom) will produce the counter for ~zod
138:: .^(arch %gy /=example-gall=/remote) will produce a listing of the current
142 ^- (unit (unit cage))
145 :: Produce local counter
150 :: Produce remote counter
152 [%x %remote who=@ta ~]
153 =* location i.t.t.path :: Ship name is third in the list
155 (~(got by remote) (slav %p location))
158 :: Produce listing of remote counters
162 %- molt :: Map from list of k-v pairs
163 %+ turn :: iterate over list of k-v pairs
164 ~(tap by remote) :: list of k-v pairs from map
167 ``[%arch !>(`arch`[~ dir])]
170:: Handle sign from agent
173 |= [=wire =sign:agent:gall]
177 :: Print error if poke failed
185 :: Print error if subscription failed
190 =/ =tank leaf+"subscribe failed from {<dap.bowl>} on wire {<wire>}"
191 %- (slog tank u.p.sign)
194 :: Do nothing if unsubscribed
198 :: Update remote counter when we get a subscription update
202 ?. ?=(%atom p.cage.sign)
204 this(remote (~(put by remote) src.bowl !<(@ q.cage.sign)))
209:: We never give any cards to arvo. Therefore we never need to handle any signs
210:: from arvo. We use the default-agent library to avoid implementing this arm,
211:: as gall apps must have all the arms.
213++ on-arvo on-arvo:def
217:: Print errors when they happen
222 %- (slog leaf+"error in {<dap.bowl>}" >term< tang)
228### `sur/example-gall.hoon`
232+$ example-gall-action
236 [%increment-remote who=@p]
242### `mar/example-gall/action.hoon`
246|_ act=example-gall-action
249 ++ noun example-gall-action
258Application initialisation
260`++on-init` is called when an application is first started. It is not a gate and
269List of cards and new agent
274:: From reference agent.
275:: Set local counter to 1 by default
280:: From app/weather.hoon. This setup is typical of a landscape tile.
284 :~ [%pass /bind/weather %arvo %e %connect [~ /'~weather'] %weather]
285 :* %pass /launch/weather %agent [our.bol %launch] %poke
286 %launch-action !>([%weather /weathertile '/~weather/js/tile.js'])
293Expose state for saving.
295This arm is called immediately before the agent is upgraded. It packages the
296permament state of the agent in a vase for the next version of the agent.
297Unlike most handlers, this cannot produce effects. It is not a gate and has no input.
301`vase` of permanent state.
306:: From reference agent
308:: Expose state for saving
318This arm is called immediately after the agent is upgraded. It receives
319a vase of the state of the previously-running version of the agent, obtained
320from `+on-save`, which allows it to cleanly upgrade from the old agent.
328`vase` of previous state, from `++on-save`
336List of cards and new agent
341:: From reference agent
343:: Load old state and upgrade if neccessary
347 =/ loaded=versioned-state
348 !<(versioned-state old)
351 `this(local local.loaded) :: Upgrade old state
359Handle application poke.
361This arm is called when the agent is "poked". The input is a cage, so
362it's a pair of a mark and a dynamic vase.
370`mark` is the mark of the poked data.
372`vase` is a vase with the poked data inside.
380List of cards and new agent.
385:: From reference agent.
388:: App can be poked in the dojo by running the following commands
389:: Increment local counter
390:: :example-gall &example-gall-action [%increment ~]
391:: Increment ~zod's counter
392:: :example-gall &example-gall-action [%increment-remote ~zod]
393:: Subscribe to ~zod's counter
394:: :example-gall &example-gall-action [%view ~zod]
395:: Unsubscribe from ~zod's counter
396:: :example-gall &example-gall-action [%stop-view ~zod]
401 :: Ensure poke is of mark %example-gall-action
402 ?> =(mark %example-gall-action)
403 =/ act=example-gall-action !<(example-gall-action vase)
406 :: Increment local counter and send new counter to subscribers
409 :- [%give %fact `/local %atom !>(+(local))]~
412 :: Send remote %increment poke
414 [%increment-remote who=@p]
418 /inc/(scot %p who.act)
420 [who.act %example-gall]
421 %poke %example-gall-action !>([%increment ~])
424 :: Subscribe to a remote counter
428 [%pass /view/(scot %p who.act) %agent [who.act %example-gall] %watch /local]~
430 :: Unsubscribe from remote counter and remove from state
433 :_ this(remote (~(del by remote) who.act))
434 [%pass /view/(scot %p who.act) %agent [who.act %example-gall] %leave ~]~
441Handle new subscriber.
443This arm is called when a program wants to subscribe to the agent on a
444particular path. The agent may or may not need to perform setup steps
445to intialize the subscription. It may produce a `%give`
446`%subscription-result` to the subscriber to get it up to date, but after
447this event is complete, it cannot give further updates to a specific
448subscriber. It must give all further updates to all subscribers on a
451If this arm crashes, then the subscription is immediately terminated.
452More specifcally, it never started -- the subscriber will receive a
453negative `%watch-ack`. You may also produce an explicit `%kick` to
454close the subscription without crashing -- for example, you could
455produce a single update followed by a `%kick`.
463Path of new subscription.
471List of cards and new agent.
476:: From reference agent
478:: Handle new subscription
480:: When another ship subscribes to our counter, give them the current state of
481:: the counter immediately
490 [%give %fact ~ %atom !>(local)]~
498This arm is called when a program becomes unsubscribed to you.
499Subscriptions may close because the subscriber intentionally
500unsubscribed, but they also could be closed by an intermediary. For
501example, if a subscription is from another ship which is currently
502unreachable, Ames may choose to close the subscription to avoid queueing
503updates indefinitely. If the program crashes while processing an
504update, this may also generate an unsubscription. You should consider
505subscriptions to be closable at any time.
513Path of the closed subscription.
521List of cards and new agent.
526:: From reference agent. Prints a message when programs become unsubscribed.
530 ~& "Unsubscribe by: {<src.bowl>} on: {<path>}"
538This arm is called when a program reads from the agent's "scry"
539namespace, which should be referentially transparent. Unlike most
540handlers, this cannot perform IO, and it cannot change the state. All
541it can do is produce a piece of data to the caller, or not.
549The path being scryed for.
552:: Example scry to path mappings
554.^(arch %gy /=example-gall=/remote)
555:: Path will be /y/remote
556.^(@ %gx /=example-gall=/local/atom)
557:: Path will be /x/local
566If this arm produces `[~ ~ data]`, then `data` is the value at the the
567given path. If it produces `[~ ~]`, then there is no data at the given
568path and never will be. If it produces `~`, then we don't know yet whether
569there is or will be data at the given path. The head of the path is known as the
570`care`. Requests with a care of `%x` should return a vase that matches or is
571convertible to the mark at the end of the scry request. This mark is not
572included in the path passed to `++on-peek`. Requests with a care of `%y` should
573return a cage with a mark of `%arch` and a vase of `arch`.
578:: From reference agent
580:: Expose scry namespace
582:: .^(@ %gx /=example-gall=/local/atom) will produce the current local counter
583:: .^(@ %gx /=example-gall=/remote/~zod/atom) will produce the counter for ~zod
584:: .^(arch %gy /=example-gall=/remote) will produce a listing of the current
588 ^- (unit (unit cage))
591 :: Produce local counter
596 :: Produce remote counter
598 [%x %remote who=@ta ~]
599 =* location i.t.t.path :: Ship name is third in the list
601 (~(got by remote) (slav %p location))
604 :: Produce listing of remote counters
608 %- molt :: Map from list of k-v pairs
609 %+ turn :: iterate over list of k-v pairs
610 ~(tap by remote) :: list of k-v pairs from map
613 ``[%arch !>(`arch`[~ dir])]
621This arm is called to handle responses to `%pass` cards to other agents.
622It will be one of the following types of response:
624- `%poke-ack`: acknowledgment (positive or negative) of a poke. If the
625 value is `~`, then the poke succeeded. If the value is `[~ tang]`,
626 then the poke failed, and a printable explanation (eg a stack trace)
627 is given in the `tang`.
629- `%watch-ack`: acknowledgment (positive or negative) of a subscription.
630 If negative, the subscription is already ended (technically, it never
633- `%fact`: update from the publisher.
635- `%kick`: notification that the subscription has ended. This happens because
636 either the target app passed a `%leave` note, or ames killed the subscription
637 due to backpressure. Most of the time you will want to resubscribe. If you can
638 no longer access the subscription you will get a negative `%watch-ack` and end
644[=wire =sign:agent:gall]
647`wire` is the wire from the `+gift` that triggered `++on-agent`
649`sign` is response for the gift.
660:: From reference agent
662:: Handle sign from agent
665 |= [=wire =sign:agent:gall]
669 :: Print error if poke failed
677 :: Print error if subscription failed
682 =/ =tank leaf+"subscribe failed from {<dap.bowl>} on wire {<wire>}"
683 %- (slog tank u.p.sign)
686 :: Do nothing if unsubscribed
690 :: Update remote counter when we get a subscription update
694 ?. ?=(%atom p.cage.sign)
696 this(remote (~(put by remote) src.bowl !<(@ q.cage.sign)))
704This arm is called to handle responses for `%pass` cards to vanes.
709 [=wire =sign:agent:gall]
712`wire` is the wire from the `++gift` that triggered `++on-arvo`.
714`sign` is the response from the vane. The list of possible responses from the
715vanes is statically defined in sys/zuse.hoon (grep for `++ sign-arvo`).
723List of cards and new agent.
728:: From app/weather.hoon. Handles %bound, %wake and %http-response signs
730 |= [=wire =sign-arvo]
731 ^- (quip card:agent:gall _this)
732 ?: ?=(%bound +<.sign-arvo)
734 ?: ?=(%wake +<.sign-arvo)
736 (wake:wc wire error.sign-arvo)
738 ?: ?=(%http-response +<.sign-arvo)
740 (http-response:wc wire client-response.sign-arvo)
742 (on-arvo:def wire sign-arvo)
744:: From reference agent
748:: We never give any cards to arvo. Therefore we never need to handle any signs
749:: from arvo. We use the default-agent library to avoid implementing this arm,
750:: as gall apps must have all the arms specified in the agent:gall definition.
752++ on-arvo on-arvo:def
759If an error happens in `+on-poke`, the crash report goes into the
760`%poke-ack` response. Similarly, if an error happens in
761`+on-subscription`, the crash report goes into the `%watch-ack`
762response. If a crash happens in any of the other handlers, the report
763is passed into this arm.
771`term` is a cord describing the error.
773`tang` is a stack trace for the error.
781List of cards and new agent
789:: Print errors when they happen
794 %- (slog leaf+"error in {<dap.bowl>}" >term< tang)
800Giving a gift takes the general form of
808Produce a subscription update.
810Produces a subscription update. A subscription update is a new piece of
811subscription content for all subscribers on a given path.
816[%fact (unit path) =cage]
819`(unit path)` is the path of the subscription being updated. If no path is
820 given, then the update is only given to the program that instigated the
821 request. Typical use of this mode is in `+on-watch` to give an initial update
822 to a new subscriber to get them up to date.
824`cage` is a cage of the subscription update.
829:: From ++on-watch in reference agent.
831:: Gives current local state to new subscribers.
832[%give %fact ~ %atom !>(local.sta)]
839Closes a subscription. A subscription close closes the subscription for all or
840one subscribers on a given path.
845[%kick (unit path) (unit ship)]
848`(unit path)` is the path of the subscription being updated. If no path is
849given, then the update is only given to the program that instigated the request.
850Typical use of this mode would be in `+on-watch` to produce a single update to a
851subscription then close the subscription.
853`(unit ship)` is the ship to close the subscription for. If no path is given,
854then the subscription is closed for all subscribers.
858Passing a agent note (a 'task') along a wire looks like so.
861[%pass =wire %agent [=ship name=term] =task]
864`wire` is used to identify the response to the note.
866`ship` is the ship to pass the note to.
868`name` is the name of the agent that should receive the note.
870`task` is the task itself, described below.
876This note is passed to poke an application with a cage, a marked vase.
884`cage` is the marked data to poke the application with. It is a pair of a mark
890:: From ++on-poke in reference agent.
892:: Sends an increment poke to the example-gall agent
896 /inc/(scot %p who.act)
898 [who.act %example-gall]
899 %poke %example-gall-action !>([%increment ~])
905Subscribe to an application.
907This note is given to subscribe to an application at a path
915`path` is the path to be subscribed to.
920:: From ++on-poke in reference agent.
922:: Subscribes to the example-gall agent on who.act on the path /local
924[%pass /view/(scot %p who.act) %agent [who.act %example-gall] %watch /local]
929Unsubscribe from an application.
931 This note is passed to unsubscribe from an application. It should be passed on
932the same wire that the corresponding `%watch` note for the subscription was
944:: From ++on-poke in reference agent.
946:: Unsubscribes from the example-gall agent on who.act
947[%pass /view/(scot %p who.act) %agent [who.act %example-gall] %leave ~]
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list