4title: HTTP Requests and Timers
7There's a variety of arvo services we haven't touched on yet.
8Let's figure out how to make HTTP requests and set timers.
10Let's build an uptime-monitoring system. It'll ping a web
11service periodically and print out an error when the response
12code isn't 2xx. Here's `ape/up.hoon`:
19 $% [%them wire (unit hiss)]
23|_ [hid=bowl on=_| in-progress=_| target=@t]
26 ^- [(list move) _+>.$]
30 :_ +>.$(on &, in-progress &)
33 [ost.hid %them /request ~ (need (epur target)) %get ~ ~]~
36 |= [wir=wire code=@ud headers=mess body=(unit octs)]
37 ^- [(list move) _+>.$]
38 ?: &((gte code 200) (lth code 300))
39 ~& [%all-is-well code]
42 [ost.hid %wait /timer (add ~s10 now.hid)]~
44 ~& [%we-have-a-problem code]
49 [ost.hid %wait /timer (add ~s10 now.hid)]~
55 [ost.hid %them /request ~ (need (epur target)) %get ~ ~]~
56 [~ +>.$(in-progress |)]
60There's some fancy stuff going on here. We'll go through it line by
63Firstly, there's two kinds of cards we're sending to arvo. A
64`%them` card makes an HTTP requrest out of a unit `hiss`.
66> Recall that `++unit` means "maybe". Formally, "`(unit a)` is
67> either null or a pair of null and a value in `a`". Also recall
68> that to pull a value out of a unit `(u.unit)`, you must first
69> verify that the unit is not null (for example with `?~`).
71A `hiss` (all of the following terms are defined in `zuse`) is a
72pair of a `purl` and a `moth`. A `purl` is a parsed url
73structure, which can be created with `++epur`, which is a
74function that takes a url as text and parses it into a `(unit
75purl)`. Thus, the result is null if and only if the url is malformed.
77A `moth` is a treble of a `meth`, a `math`, and `(unit octs)`.
78`meth` is the HTTP method, in this case `%get`. `math` is a map
79of HTTP headers. The `(unit octs)` is a possible octet stream
80representing the body. If it's null, then no body is sent (as in
83> An octect stream is a pair of the length in bytes of the data
84> plus the data itself. You can use `++taco` takes text and
85> turns it into an octet strem.
87When you send this request, you can expect a `%thou` with the
88response, which we handle later on in `++thou-request`.
90For `%wait`, you just pass a [`@da`]() (absolute date), and arvo will
91produce a `%wake` when the time comes.
93> A timer is guaranteed to not be triggered before the given
94> time, but it's currently impossible to guarantee the timer will be
95> triggered at exactly the requested time.
97Let's take a look at our state:
100|_ [hid=bowl on=_| in-progress=_| target=@t]
103We have three pieces of app-specific state. `target` is the url
104we're monitoring. `on` and `in-progress` are booleans
105representing, respectively, whether or not we're supposed to keep
106monitoring and whether or not we're in the middle of a request.
108The type of booleans is usually written as `?`, which is a union
109of `&` (true) and `|` false. This type defaults to `&` (true). In our
110case, we want both of these to default to `|` (false). Because
111of that, we use `_|` as the type. `_value` means "take the type
112of `value`, but make the default value be `value`". Thus, our
113type is still a boolean, just like `?`, but the default value is
116> This is the same `_` used in `_+>.$`, which means "the same
117> type as the value "+>.$". In other words, the same type as our
118> current context and state.
120Let's take a look at `++poke-cord`. When we're poked with a
121cord, we first check whether it's `'off'`. If so, we set `on` to
124If not, we check whether it's `on`. If so, we set `on` and
125`in-progress` to true. If it was already either on or in
126progress, then we don't take any other immediate action. If it
127was both off and not in progress, then we send an HTTP request.
128This request follows the pattern in `++hiss` well. `(need (epur
129target))` is the parsed url, `%get` is the HTTP method, `~`
130means no extra headers, and another `~` means no body.
132> Note the `~` at the end of the move. This is a convenient
133> shortcut for creating a list of a single element. It's part of
134> a small family of such shortcuts. `~[a b c]` is `[a b c ~]`,
135> `[a b c]~` is `[[a b c] ~]` and `\`[a b c]` is `[~ a b c]`.
136> These may be mixed and matched to create various convoluted
137> structures and emojis.
139If the argument is neither 'off' nor 'on', then we assume it's an
140actual url, so we save it in `target`.
142When the HTTP response comes back, we handle it with
143`++thou-request`, which, along with the wire the request was sent
144on, takes the status code, the response headers, and the response
147We check whether the status code is between 200 and 300. If so,
148all is well, and we print a message saying so. We start the
149timer for ten seconds after the present time.
151If we got a bad status code, then we print out the entire
152response and start the timer again.
154After ten seconds, arvo will give us a `%wake` event, which will
155be handled in `++wake-timer`. If we're still supposed to keep
156monitoring, we send the same HTTP request as before. Otherwise,
157we set `in-progress` to false.
162~fintud-macrep:dojo> |start %up
164~fintud-macrep:dojo> :up &cord 'http://www.google.com'
168~fintud-macrep:dojo> :up &cord 'http://example.com'
171~fintud-macrep:dojo> :up &cord 'http://google.com'
173[%we-have-a-problem 301]
176 [p='X-Frame-Options' q='SAMEORIGIN']
177 [p='X-XSS-Protection' q='1; mode=block']
178 [p='Content-Length' q='219']
180 [p='Cache-Control' q='public, max-age=2592000']
181 [p='Expires' q='Sun, 10 Jan 2016 23:45:05 GMT']
182 [p='Date' q='Fri, 11 Dec 2015 23:45:05 GMT']
183 [p='Content-Type' q='text/html; charset=UTF-8']
184 [p='Location' q='http://www.google.com/']
191 \/'<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">\0a<TITLE>301 Moved</TI\/
192 TLE></HEAD><BODY>\0a<H1>301 Moved</H1>\0aThe document has moved\0a<A HREF="http://www.google.com/">her
193 e</A>.\0d\0a</BODY></HTML>\0d\0a'
198~fintud-macrep:dojo> :up &cord 'off'
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