@@ -12,62 +12,124 @@ somewhat limited. A poke is a one-way message, but more often we want to
1212subscribe to updates from another app. You could build a subscription model out
1313of one-way pokes, but it's such a common pattern that it's built into arvo.
1414
15−Let's take a look at two apps, `:examples-source` and `:examples-sink`. First,
16−`:examples-source`:
17−
18− /? 314
15+Let's take a look at two apps, `:source` and `:sink`. First,
16+`:source`:
17+
18+ :: Sends subscription updates to sink.hoon
19+ ::
20+ :::: /===/app/source/hoon
21+ ::
1922 !:
23+ ::
2024 |%
21− ++ move {bone $diff mark *}
25+ ++ move {bone card}
26+ ++ card $% {$diff diff-contents}
27+ ==
28+ ++ diff-contents $% {$noun *}
29+ ==
2230 --
23− |_ {hid/bowl state/$~}
24− ++ poke-noun
25− |= arg/*
31+ ::
32+ |_ {bow/bowl $~}
33+ ::
34+ ++ poke-noun
35+ |= non/*
2636 ^- {(list move) _+>.$}
2737 :_ +>.$
28− %+ turn (prey /example-path hid)
29− |=({o/bone *} `move`[o %diff %noun arg])
30− ++ peer-example-path
38+ %+ turn (prey /example-path bow)
39+ |=({o/bone *} [o %diff %noun non])
40+ ::
41+ ++ peer-example-path
3142 |= pax/path
3243 ^- {(list move) _+>.$}
33− ~& [%subscribed-to pax=pax]
44+ ~& source+peer-notify+'Someone subscribed to you!'
45+ ~& source+[ship+src.bow path+pax]
46+ [~ +>.$]
47+ ::
48+ ++ coup
49+ |= {wir/wire err/(unit tang)}
50+ ^- {(list move) _+>.$}
51+ ?~ err
52+ ~& source+success+'Poke succeeded!'
53+ [~ +>.$]
54+ ~& source+error+'Poke failed. Error:'
55+ ~& source+error+err
56+ [~ +>.$]
57+ ::
58+ ++ reap
59+ |= {wir/wire err/(unit tang)}
60+ ^- {(list move) _+>.$}
61+ ?~ err
62+ ~& source+success+'Peer succeeded!'
63+ [~ +>.$]
64+ ~& source+error+'Peer failed. Error:'
65+ ~& source+error+err
3466 [~ +>.$]
67+ ::
3568 --
3669
37−And secondly, `:examples-sink`:
38−
39− /? 314
70+And secondly, `:sink`:
71+
72+ :: Sets up a simple subscription to source.hoon
73+ ::
74+ :::: /===/app/sink/hoon
75+ ::
76+ !:
4077 |%
41− ++ move {bone card}
42− ++ card
43− $% {$peer wire {@p term} path}
44− {$pull wire {@p term} $~}
45− ==
78+ ++ move {bone card}
79+ ++ card $% {$peer wire dock path}
80+ {$pull wire dock $~}
81+ ==
4682 --
47− !:
48− |_ {bowl available/?}
49− ++ poke-noun
50− |= arg/*
83+ ::
84+ |_ {bow/bowl val/?}
85+ ::
86+ ++ poke-noun
87+ |= non/*
5188 ^- {(list move) _+>.$}
52− ?: &(=(%on arg) available)
53− [[[ost %peer /subscribe [our %source] /example-path] ~] +>.$(available |)]
54− ?: &(=(%off arg) !available)
55− [[[ost %pull /subscribe [our %source] ~] ~] +>.$(available &)]
56− ~& ?:(available %not-subscribed %subscribed)
89+ ?: &(=(%on non) val)
90+ :_ +>.$(val |)
91+ :~ :* ost.bow
92+ %peer
93+ /subscribe
94+ [our.bow %source]
95+ /example-path
96+ ==
97+ ==
98+ ?: &(=(%off non) !val)
99+ :_ +>.$(val &)
100+ ~[[ost.bow %pull /subscribe [our.bow %source] ~]]
101+ ~& ?: val
102+ sink+unsubscribed+'You are now unsubscribed!'
103+ sink+subscribed+'You are now subscribed!'
57104 [~ +>.$]
58− ++ diff-noun
59− |= {wir/wire arg/*}
105+ ::
106+ ++ diff-noun
107+ |= {wir/wire non/*}
60108 ^- {(list move) _+>.$}
61− ~& [%received-data arg]
109+ ~& sink+received-data+'You got something!'
110+ ~& sink+data+non
62111 [~ +>.$]
63− ++ reap
64− |= {wir/wire error/(unit tang)}
112+ ::
113+ ++ coup
114+ |= {wir/wire err/(unit tang)}
65115 ^- {(list move) _+>.$}
66− ?~ error
67− ~& %successfully-subscribed
68− [~ +>.$]
69− ~& [%subscription-failed error]
116+ ?~ err
117+ ~& sink+success+'Poke succeeded!'
118+ [~ +>.$]
119+ ~& sink+error+'Poke failed. Error:'
120+ ~& sink+error+err
70121 [~ +>.$]
122+ ::
123+ ++ reap
124+ |= {wir/wire err/(unit tang)}
125+ ^- {(list move) _+>.$}
126+ ?~ err
127+ ~& sink+success+'Peer succeeded!'
128+ [~ +>.$]
129+ ~& sink+error+'Peer f ailed. Error:'
130+ ~& sink+error+err
131+ [~ +>.$]
132+ ::
71133 --
72134
73135Cheat sheet:
@@ -116,38 +178,42 @@ Cheat sheet:
116178
117179Here's some sample output of the two working together:
118180
119− ~fintud-macrep:dojo> |start %examples-source
181+ ~fintud-macrep:dojo> |start %source
120182 >=
121− ~fintud-macrep:dojo> |start %examples-sink
183+ ~fintud-macrep:dojo> |start %sink
122184 >=
123− ~fintud-macrep:dojo> :examples-sink %on
124− [%subscribed-to pax=/example-path]
125− %successfully-subscribed]
185+ ~fintud-macrep:dojo> :sink %on
186+ [%source %peer-notify 'Someone subscribed to you!']
187+ [%source [%ship ~fintud-macrep] %path /]
188+ [%sink %success 'Peer succeeded!']
126189 >=
127− ~fintud-macrep:dojo> :examples-source 5
128− [%received-data 5]
190+ ~fintud-macrep:dojo> :source 5
191+ [%sink %received-data 'You got something!']
192+ [%sink %data 5]
129193 >=
130− ~fintud-macrep:dojo> :examples-sink %off
194+ ~fintud-macrep:dojo> :sink %off
131195 >=
132− ~fintud-macrep:dojo> :examples-source 6
196+ ~fintud-macrep:dojo> :source 6
133197 >=
134− ~fintud-macrep:dojo> :examples-sink %on
135− [%subscribed-to pax=/example-path]
136− %successfully-subscribed]
198+ ~fintud-macrep:dojo> :sink %on
199+ [%source %peer-notify 'Someone subscribed to you!']
200+ [%source [%ship ~fintud-macrep] %path /]
201+ [%sink %success 'Peer succeeded!']
137202 >=
138− ~fintud-macrep:dojo> :examples-source 7
139− [%received-data 7]
203+ ~fintud-macrep:dojo> :source 7
204+ [%sink %received-data 'You got something!']
205+ [%sink %data 7]
140206 >=
141207
142−### :examples-source
208+### :source
143209
144210Hopefully you can get a sense for what's happening here. When we poke
145−`:examples-sink` with `%on`, `:examples-sink` subscribes to `:examples-source`,
146−and so whenever we poke `:examples-source`, `:examples-sink` gets the update and
147−prints it out. Then we unsubscribe by poking `:examples-sink` with `%off`, and
148−`:examples-sink` stops getting updates. We then resubscribe.
211+`:sink` with `%on`, `:sink` subscribes to `:source`,
212+and so whenever we poke `:source`, `:sink` gets the update and
213+prints it out. Then we unsubscribe by poking `:sink` with `%off`, and
214+`:sink` stops getting updates. We then resubscribe.
149215
150−There's a fair bit going on in this code. Let's look at `:examples-source`
216+There's a fair bit going on in this code. Let's look at `:source`
151217first.
152218
153219Our definition of `move` is fairly specific, since we're only going to sending
@@ -161,10 +227,10 @@ discussion of ducts, a layer gets popped off the duct rather than added to it.
161227This is why no wire is needed for the move -- we won't receive anything in
162228response to it.
163229
164−Anyways, there're two functions inside the `|_`. We already know when
165−`++poke-noun` is called. `++peer` is called when someone tries to subscribe to
166−our app. Of course, you don't just subscribe to an app; you subscribe to a path
167−on that app. This path comes in as the argument to `++peer`.
230+Anyways, there are four functions (arms) inside the `|_`. We already know when
231+`++poke-noun` is called. `++peer-example-path` is called when someone tries to
232+subscribe to our app. Of course, you don't just subscribe to an app; you
233+subscribe to a path on that app. This path comes in as the argument to `++peer`.
168234
169235In our case, we don't care what path you subscribed on, and all we do is print
170236out that you subscribed. Arvo keeps track of your subscriptions, so you don't
@@ -181,27 +247,27 @@ unchanged.
181247
182248Our list of moves is the result of a call to `++turn`. `++turn` is what many
183249languages call "map" -- it runs a function on every item in a list and collects
184−the results in a list. The list is `(prey /example-path hid)` and the function
250+the results in a list. The list is `(prey /example-path bow)` and the function
185251is the `|=` line right after it.
186252
187−`++prey` is a standard library function defined in `zuse`. It takes a path and a
188−bowl and gives you a list of the subscribers who are subscribed on a path that
189−begins with the given path. "Prey" is short for "prefix".
253+`++prey` is a standard library function defined in `zuse.hoon`. It takes a path
254+and a bowl and gives you a list of the subscribers who are subscribed on a path
255+that begins with the given path. "Prey" is short for "prefix".
190256
191257Now we have the list of relevant subscribers. This a list of triples,
192258`{bone @p path}`, where the only thing we really need is the bone, because we
193259don't need to know their urbit or what exact path they subscribed on. Thus, our
194−transformer function takes `{o/bone *}` and produces `[o %diff %noun arg]`,
260+transformer function takes `{o/bone *}` and produces `[o %diff %noun non]`,
195261which is a move that provides bone `o` with this subscription update:
196−`[%noun arg]`". This is fairly dense code, but what it's doing is
197−straightforward.
262+`[%noun non]`". This is fairly dense code, but what it's doing is
263+straightforward!
198264
199−### :examples-sink
265+### :sink
200266
201−`:examples-source` should now make sense. `:examples-sink` is a little longer,
202−but not much more complicated.
267+`:source` should now make sense. `:sink` is a little longer, but not much more
268+complicated.
203269
204−In `:examples-sink`, our definition of of `++move` is different. All moves start
270+In `:sink`, our definition of of `++move` is different. All moves start
205271with a `bone`, and we conventionally refer to the second half as the "card", so
206272that we can say a move is an action that sends a card along a bone.
207273
@@ -214,35 +280,56 @@ because its semantics are to cancel any subscriptions coming over this duct. If
214280your bone and wire are the same as when you subscribed, then the cancellation
215281will happen correctly.
216282
217−The only state we need for `:examples-sink` is a boolean to indicate whether
218−we're already subscribed to `:examples-source`. We use `available/?`, where `?`
283+The only state we need for `:sink` is a boolean to indicate whether
284+we're already subscribed to `:source`. We use `val/?`, where `?`
219285is the sign of type boolean (similar to `*`, `@`), which defaults to true (that
220286is, `0`).
221287
222288In `++poke-noun` we check our input to see both if it's `%on` and we're
223−available. If so, we produce the move to subscribe to `:examples-source`:
224−
225− [ost %peer /subscribe [our %source] /example-path]
226−
227−Also, we set available to false (`|`) with `+>.$(available |)`.
228−
229−Otherwise, if our input is `%off` and we're already subscribed (i.e. `available`
230−is false), then we unsubscribe from `:examples-source`:
231−
232− [ost %pull /subscribe [our %source] ~]
289+available (`val` is true). If so, we produce the move to subscribe to
290+`:source`:
291+
292+ :~ :* ost.bow
293+ %peer
294+ /subscribe
295+ [our.bow %source]
296+ /example-path
297+ ==
298+ ==
299+
300+Also, in the preceding lines, we set `val` to false (`|`) with `+>.$(val |)`.
301+Remember that the `:_` constructs an inverted cell, with the first child
302+(`+>.$(val |` in our case) as the tail and the second child as the head. Here,
303+the cell we produce when our subscription is `%on` and `val` is true has a
304+head with our new state where `val` is set to false and a tail of our list of
305+moves, which is shown in the code block above.
306+
307+Otherwise, if our input is `%off` and we're already subscribed (i.e. `val`
308+is false), then we unsubscribe from `:source` and set `val` back to true (`&`),
309+again using our handy inverted cell constructor mold `:_`:
310+
311+ :_ +>.$(val &)
312+ ~[[ost.bow %pull /subscribe [our.bow %source] ~]]
233313
234314It's important to send over the same bone and wire (`/subscribe`) as the one we
235315originally subscribed on.
236316
237−We also set `available` to true (`&`).
238−
239317If neither of these cases are true, then we print our current subscription
240−state.
318+state, based on whether `val` is true or false, and return a cell containing
319+a null list of moves and our unchanged app state:
320+
321+ ~& ?: val
322+ sink+unsubscribed+'You are now unsubscribed!'
323+ sink+subscribed+'You are now subscribed!'
324+ [~ +>.$]
241325
242326`++diff-noun` is called when we get a `%diff` update along a subscription with a
243327mark of `noun`. `++diff-noun` is given the wire that we originally passed with
244328the `%peer` subscription request along and the data we got back. In our case we
245−just print out the data.
329+just print out the data:
330+
331+ ~& sink+received-data+'You got something!'
332+ ~& sink+data+non
246333
247334`++reap` is called when we receive an acknowledgment as to whether the
248335subscription was handled successfully. You can remember that `++reap` is the
@@ -252,5 +339,5 @@ counterpart to `++peer` as it's pronounced like 'peer' backwards. Similarly,
252339Moving forward, `++reap` is given the wire we attempted to subscribe over,
253340possibly along with an error message in cases of failure. `(unit type)` means
254341"either `~` or `[~ type]`, which means it's used like Haskell's "maybe" or C's
255−nullability. If `error` is `~`, then the subscription was successful and we tell
342+nullability. If `err` is `~`, then the subscription was successful and we tell
256343that to the user. Otherwise, we print out the error message.