In this lesson we're going to look at interacting with vanes (kernel modules). The API for each vane consists of task
s it can take, and gift
s it can return. The task
s and gift
s for each vane are defined in its section of lull.hoon
. Here's the task:iris
s and gift:iris
s for Iris, the HTTP client vane, as an example:
|%+$ gift$% [%request id=@ud request=request:http][%cancel-request id=@ud][%http-response =client-response]==+$ task$~ [%vega ~]$% $>(%born vane-task)$>(%trim vane-task)$>(%vega vane-task)[%request =request:http =outbound-config][%cancel-request ~][%receive id=@ud =http-event:http]==
The API of each vane is documented in its respective section of the Arvo documentation. Each vane has a detailed API reference and examples of their usage. There are far too many task
s and gift
s across the vanes to cover here, so in the Example
section of this document, we'll just look at a single, simple example with a Behn timer. The basic pattern in the example is broadly applicable to the other vanes as well.
Sending a vane task
A task
can be sent to a vane by %pass
ing it an %arvo
card. We touched on these in the Cards lesson, but we'll briefly recap it here. The type of the card is as follows:
[%pass path %arvo note-arvo]
The path
will just be the wire
you want the response to arrive on. The note-arvo
is the following union:
+$ note-arvo$~ [%b %wake ~]$% [%a task:ames][%b task:behn][%c task:clay][%d task:dill][%e task:eyre][%g task:gall][%i task:iris][%j task:jael][%k task:khan][%l task:lick][%$ %whiz ~][@tas %meta vase]==
The letter tags just specify which vane it goes to, and then follows the task
itself. Here are a couple of examples. The first sends a %wait
task:behn
to Behn, setting a timer to go off one minute in the future. The second sends a %warp
task:clay
to Clay, asking whether sys.kelvin
exists on the %base
desk.
[%pass /some/wire %arvo %b %wait (add ~m1 now.bowl)][%pass /some/wire %arvo %c %warp our.bowl %base ~ %sing %u da+now.bowl /sys/kelvin]
Receiving a vane gift
Once a task
has been sent to a vane, any gift
s the vane sends back in response will arrive in the on-arvo
arm of your agent. The on-arvo
arm exclusively handles such vane gift
s. The gift
s will arrive in a sign-arvo
, along with the wire
specified in the original request. The on-arvo
arm produces a (quip card _this)
like usual, so it would look like:
++ on-arvo|= [=wire =sign-arvo]^- (quip card _this).....
A sign-arvo
is the following structure, defined in lull.hoon
:
+$ sign-arvo$% [%ames gift:ames]$: %behn$% gift:behn$>(%wris gift:clay)$>(%writ gift:clay)$>(%mere gift:clay)$>(%unto gift:gall)====[%clay gift:clay][%dill gift:dill][%eyre gift:eyre][%gall gift:gall][%iris gift:iris][%jael gift:jael][%khan gift:khan][%lick gift:lick]==
The head of the sign-arvo
will be the name of the vane like %behn
, %clay
, etc. The tail will be the gift
itself. Here are a couple of sign-arvo
examples, and the responses to the example task
s in the previous section:
[%behn %wake ~]
[ %clay[ %writp[ ~[ p=[p=%u q=[%da p=~2021.11.17..13.55.00..c195] r=%base]q=/sys/kelvinr=[p=%flag q=[#t/?(%.y %.n) q=0]]]]]]
The typical pattern is to first test the wire
with something like a wutlus (?+
) expression, and then test the sign-arvo
. Since most gift
s are head-tagged, you can test both the vane and the gift at the same time like:
?+ sign-arvo (on-arvo:def wire sign-arvo)[%behn %wake *].........
Example
Here's a very simple example that takes a poke of a @dr
(a relative date-time value) and sends Behn a %wait
task:behn
, setting a timer to go off @dr
in the future. When the timer goes off, on-arvo
will take the %wake
gift:behn
and print "Ding!" to the terminal.
/app/ding.hoon
Click to expand
/+ default-agent, dbug|%+$ card card:agent:gall--%- agent:dbug^- agent:gall|_ =bowl:gall+* this .def ~(. (default-agent this %.n) bowl)++ on-init on-init:def++ on-save on-save:def++ on-load on-load:def++ on-poke|= [=mark =vase]^- (quip card _this)?+ mark (on-poke:def mark vase)%noun:_ this:~ [%pass /timers %arvo %b %wait (add now.bowl !<(@dr vase))]====++ on-watch on-watch:def++ on-leave on-leave:def++ on-peek on-peek:def++ on-agent on-agent:def++ on-arvo|= [=wire =sign-arvo]^- (quip card _this)?+ wire (on-arvo:def wire sign-arvo)[%timers ~]?+ sign-arvo (on-arvo:def wire sign-arvo)[%behn %wake *]?~ error.sign-arvo((slog 'Ding!' ~) `this)(on-arvo:def wire sign-arvo)====++ on-fail on-fail:def--
Let's examine the on-poke
arm:
++ on-poke|= [=mark =vase]^- (quip card _this)?+ mark (on-poke:def mark vase)%noun:_ this:~ [%pass /timers %arvo %b %wait (add now.bowl !<(@dr vase))]====
A Behn %wait
task has the format [%wait @da]
- the @da
(an absolute date-time value) is the time the timer should go off. The vase
of the poke takes a @dr
, so we extract it directly into an add
expression, producing a date-time @dr
from now. Behn will receive the %wait
task and set the timer in Unix. When it fires, Behn will produce a %wake
gift:behn
and deliver it to on-arvo
, on the wire
we specified (/timers
). Here's the on-arvo
arm:
++ on-arvo|= [=wire =sign-arvo]^- (quip card _this)?+ wire (on-arvo:def wire sign-arvo)[%timers ~]?+ sign-arvo (on-arvo:def wire sign-arvo)[%behn %wake *]?~ error.sign-arvo((slog 'Ding!' ~) `this)(on-arvo:def wire sign-arvo)====
We remark that, just like in the case of agent-agent communication, gift
s from Arvo are also routed wire
before sign-arvo
.
First we check the wire
is /timers
, and then we check the sign-arvo
begins with [%behn %wake ....]
. Behn's %wake
gift has the following format:
[%wake error=(unit tang)]
The error
is null if the timer fired successfully, and contains an error in the tang
if it did not. We therefore test whether error.sign-arvo
is ~
, and if it is, we print Ding!
to the terminal. If the wire
, sign-arvo
or error
are something unexpected, we pass it to %default-agent
, which will just crash and print an error message.
Let's try it out. Save the agent above as /app/ding.hoon
on the %base
desk and |commit %base
. Then, start the agent with |rein %base [& %ding]
.
Next, in the dojo let's try poking our agent, setting a timer for five seconds from now:
> :ding ~s5>=
After approximately five seconds, we see the timer fired successfully:
> Ding!
Summary
- Each vane has an API composed of
task
s it takes andgift
s it produces. - Each vane's
task
s andgift
s are defined inlull.hoon
- Each vane's section of the Arvo documentation includes an API reference that explains its
task
s andgift
s, as well as an Examples section demonstrating their usage. - Vane
task
s can be sent to vanes by%pass
ing them an%arvo
card
. - Vane
gift
s come back to theon-arvo
arm of the agent core in asign-arvo
.
Exercises
- Run through the Example yourself if you've not done so already.
- Have a look at some vane sections of
lull.hoon
to familiarize yourself with its structure. - Have a quick look at the API reference sections of a couple of vanes in the Arvo documentation.