mirror of
https://github.com/urbit/shrub.git
synced 2025-01-01 00:51:59 +03:00
eyre: subscribe to apps for responses
This removes the %http-response special case from gall. In its place, we implement a subscription regime with the following steps: - Agent sends %connect to Eyre - Eyre pokes agent with %handle-http-response, including unique eyre-id - Agent passes %start-watching to Eyre with eyre-id and unique app-id - Eyre subscribes to agent on /http-response/app-id - Agent produces a %http-response-header fact followed by 0 or more %http-response-data facts and possibly a %http-response-cancel fact - Agent produces a %kick to close the subscription, which Eyre interprets as completion of the message. This works when there is data. There is currently a bug where if the response has no data in total (as in the case of a naked 404), no response will be sent. This also includes lib/http-handler, which implements a convenient interface for agents that want to respond immediately with all the data. This lets them avoid carrying extra state to keep track of pending requests. This should really have access to your state and the ability to change it. Perhaps a more minimalist design would be better: just keep track of the requests, then hand it off to +on-watch when eyre is ready to receive responses. It's not clear how to pass in the request data in +on-watch.
This commit is contained in:
parent
85a40a13d0
commit
47e3b260d5
64
pkg/arvo/age/clock.hoon
Normal file
64
pkg/arvo/age/clock.hoon
Normal file
@ -0,0 +1,64 @@
|
||||
/+ *server, default-agent, verb
|
||||
/= tile-js
|
||||
/^ octs
|
||||
/; as-octs:mimes:html
|
||||
/: /===/app/clock/js/tile
|
||||
/| /js/
|
||||
/~ ~
|
||||
==
|
||||
=, format
|
||||
::
|
||||
%+ verb &
|
||||
^- agent:mall
|
||||
%+ http-handler
|
||||
%- require-authorization:app
|
||||
|= =inbound-request:eyre
|
||||
^- response:http-handler
|
||||
=/ request-line (parse-request-line url.request.inbound-request)
|
||||
=/ back-path (flop site.request-line)
|
||||
=/ name=@t
|
||||
=/ back-path (flop site.request-line)
|
||||
?~ back-path
|
||||
''
|
||||
i.back-path
|
||||
::
|
||||
?~ back-path
|
||||
not-found:gen
|
||||
?: =(name 'tile')
|
||||
(js-response:gen tile-js)
|
||||
not-found:gen
|
||||
::
|
||||
|_ =bowl:mall
|
||||
+* this .
|
||||
def ~(. (default-agent this %|) bowl)
|
||||
::
|
||||
++ on-init
|
||||
^- (quip card:agent:mall _this)
|
||||
=/ launcha
|
||||
[%launch-action !>([%clock /tile '/~clock/js/tile.js'])]
|
||||
:_ this
|
||||
:~ [%pass / %arvo %e %connect [~ /'~clock'] %clock]
|
||||
[%pass /clock %agent [our.bowl %launch] %poke launcha]
|
||||
==
|
||||
++ on-save on-save:def
|
||||
++ on-load on-load:def
|
||||
++ on-poke on-poke:def
|
||||
++ on-watch
|
||||
|= =path
|
||||
^- (quip card:agent:mall _this)
|
||||
?. =(/tile path)
|
||||
(on-watch:def path)
|
||||
[[%give %fact ~ %json !>(*json)]~ this]
|
||||
::
|
||||
++ on-leave on-leave:def
|
||||
++ on-peek on-peek:def
|
||||
++ on-agent on-agent:def
|
||||
++ on-arvo
|
||||
|= [=wire =sign-arvo]
|
||||
^- (quip card:agent:mall _this)
|
||||
?. ?=(%bound +<.sign-arvo)
|
||||
(on-arvo:def wire sign-arvo)
|
||||
[~ this]
|
||||
::
|
||||
++ on-fail on-fail:def
|
||||
--
|
@ -8,12 +8,10 @@
|
||||
`agent
|
||||
::
|
||||
++ on-save
|
||||
~& "extracting empty state for {<dap.bowl>}"
|
||||
!>(~)
|
||||
::
|
||||
++ on-load
|
||||
|= old-state=vase
|
||||
~& "updating agent {<dap.bowl>} by throwing away old state"
|
||||
`agent
|
||||
::
|
||||
++ on-poke
|
||||
|
93
pkg/arvo/lib/http-handler.hoon
Normal file
93
pkg/arvo/lib/http-handler.hoon
Normal file
@ -0,0 +1,93 @@
|
||||
:: wrap an http handler without having to worry about subscriptions
|
||||
::
|
||||
|%
|
||||
+$ response simple-payload:http
|
||||
+$ handler $-(inbound-request:eyre response)
|
||||
--
|
||||
|= [=handler =agent:mall]
|
||||
=| state=[count=@ud map=(map app-id=@ud response)]
|
||||
^- agent:mall
|
||||
|_ =bowl:mall
|
||||
+* this .
|
||||
ag ~(. agent bowl)
|
||||
::
|
||||
++ on-init
|
||||
^- (quip card:agent:mall agent:mall)
|
||||
=^ cards agent on-init:ag
|
||||
[cards this]
|
||||
::
|
||||
++ on-save
|
||||
^- vase
|
||||
!>([on-save:ag state])
|
||||
::
|
||||
++ on-load
|
||||
|= old-state=vase
|
||||
^- (quip card:agent:mall agent:mall)
|
||||
=^ old state !<([vase _state] old-state)
|
||||
=^ cards agent (on-load:ag old)
|
||||
[cards this]
|
||||
::
|
||||
++ on-poke
|
||||
|= [=mark =vase]
|
||||
^- (quip card:agent:mall agent:mall)
|
||||
?. ?=(%handle-http-request mark)
|
||||
=^ cards agent (on-poke:ag mark vase)
|
||||
[cards this]
|
||||
=+ !<([eyre-id=@ud =inbound-request:eyre] vase)
|
||||
=/ response (handler inbound-request)
|
||||
=/ app-id count.state
|
||||
=: count.state +(count.state)
|
||||
map.state (~(put by map.state) app-id response)
|
||||
==
|
||||
:_ this :_ ~
|
||||
[%pass / %arvo %e %start-watching eyre-id app-id]
|
||||
::
|
||||
++ on-watch
|
||||
|= =path
|
||||
^- (quip card:agent:mall agent:mall)
|
||||
?. ?=([%http-response @ ~] path)
|
||||
=^ cards agent (on-watch:ag path)
|
||||
[cards this]
|
||||
=/ app-id (slav %ud i.t.path)
|
||||
=/ response (~(get by map.state) app-id)
|
||||
:_ this(map.state (~(del by map.state) app-id))
|
||||
?~ response
|
||||
^- (list card:agent:mall)
|
||||
:~ [%give %fact `path %http-response-cancel !>(~)]
|
||||
[%give %kick `path ~]
|
||||
==
|
||||
^- (list card:agent:mall)
|
||||
:~ [%give %fact `path %http-response-header !>(response-header.u.response)]
|
||||
[%give %fact `path %http-response-data !>(data.u.response)]
|
||||
[%give %kick `path ~]
|
||||
==
|
||||
::
|
||||
++ on-leave
|
||||
|= =path
|
||||
^- (quip card:agent:mall agent:mall)
|
||||
=^ cards agent (on-leave:ag path)
|
||||
[cards this]
|
||||
::
|
||||
++ on-peek
|
||||
|= =path
|
||||
^- (unit (unit cage))
|
||||
(on-peek:ag path)
|
||||
::
|
||||
++ on-agent
|
||||
|= [=wire =sign:agent:mall]
|
||||
^- (quip card:agent:mall agent:mall)
|
||||
=^ cards agent (on-agent:ag wire sign)
|
||||
[cards this]
|
||||
::
|
||||
++ on-arvo
|
||||
|= [=wire =sign-arvo]
|
||||
^- (quip card:agent:mall agent:mall)
|
||||
=^ cards agent (on-arvo:ag wire sign-arvo)
|
||||
[cards this]
|
||||
::
|
||||
++ on-fail
|
||||
|= [=term =tang]
|
||||
^- (quip card:agent:mall agent:mall)
|
||||
=^ cards agent (on-fail:ag term tang)
|
||||
[cards this]
|
||||
--
|
@ -1,3 +1,4 @@
|
||||
/+ http-handler
|
||||
=, eyre
|
||||
|%
|
||||
::
|
||||
@ -24,22 +25,19 @@
|
||||
:: +require-authorization: redirect to the login page when unauthenticated
|
||||
::
|
||||
++ require-authorization
|
||||
|* this=*
|
||||
|= handler=$-(inbound-request:eyre (quip card:agent:mall _this))
|
||||
|= handler=$-(inbound-request:eyre simple-payload:http)
|
||||
|= =inbound-request:eyre
|
||||
^- (quip card:agent:mall _this)
|
||||
^- simple-payload:http
|
||||
::
|
||||
?: authenticated.inbound-request
|
||||
~! this
|
||||
~! +:*handler
|
||||
(handler inbound-request)
|
||||
::
|
||||
:_ this
|
||||
^- (list card:agent:mall)
|
||||
=/ redirect=cord
|
||||
%- crip
|
||||
"/~/login?redirect={(trip url.request.inbound-request)}"
|
||||
[%give [%http-response %start [307 ['location' redirect]~] ~ %.y]]~
|
||||
[[307 ['location' redirect]~] ~]
|
||||
::
|
||||
++ html-response
|
||||
|= oct-html=octs
|
||||
|
@ -447,7 +447,6 @@
|
||||
+>.$
|
||||
(dump:(crud %reap u.p.p.+>.sih) %logo ~)
|
||||
$fact pump:(from ;;(dill-blit q:`vase`+>+>.sih))
|
||||
$http-response !!
|
||||
==
|
||||
::
|
||||
{$c $note *}
|
||||
|
@ -102,6 +102,11 @@
|
||||
:: the :binding into a (map (unit @t) (trie knot =action)).
|
||||
::
|
||||
bindings=(list [=binding =duct =action])
|
||||
:: starting: new http connections waiting for app to send %start-watching
|
||||
::
|
||||
:: Ducts should be keys of connections.
|
||||
::
|
||||
starting=[count=@ud map=(map eyre-id=@ud [=duct app=term])]
|
||||
:: connections: open http connections not fully complete
|
||||
::
|
||||
connections=(map duct outstanding-connection)
|
||||
@ -816,6 +821,12 @@
|
||||
^- [(list move) server-state]
|
||||
::
|
||||
=/ act [%app app=%lens]
|
||||
=/ eyre-id count.starting.state
|
||||
=: count.starting.state +(count.starting.state)
|
||||
map.starting.state
|
||||
(~(put by map.starting.state) eyre-id [duct app.act])
|
||||
==
|
||||
::
|
||||
=/ connection=outstanding-connection
|
||||
[act [& secure address request] ~ 0]
|
||||
::
|
||||
@ -831,7 +842,7 @@
|
||||
^- task:agent:mall
|
||||
:* %poke
|
||||
%handle-http-request
|
||||
!>(inbound-request.connection)
|
||||
!>([eyre-id inbound-request.connection])
|
||||
==
|
||||
:: +request: starts handling an inbound http request
|
||||
::
|
||||
@ -866,6 +877,12 @@
|
||||
[%$ %noun !>([authenticated request])]
|
||||
::
|
||||
%app
|
||||
=/ eyre-id count.starting.state
|
||||
=: count.starting.state +(count.starting.state)
|
||||
map.starting.state
|
||||
(~(put by map.starting.state) eyre-id [duct app.action])
|
||||
==
|
||||
::
|
||||
:_ state
|
||||
:_ ~
|
||||
:^ duct %pass /run-app-request/[app.action]
|
||||
@ -878,7 +895,7 @@
|
||||
^- task:agent:mall
|
||||
:* %poke
|
||||
%handle-http-request
|
||||
!>(inbound-request.connection)
|
||||
!>([eyre-id inbound-request.connection])
|
||||
==
|
||||
::
|
||||
%authentication
|
||||
@ -891,6 +908,23 @@
|
||||
%^ return-static-data-on-duct 404 'text/html'
|
||||
(error-page 404 authenticated url.request ~)
|
||||
==
|
||||
:: +start-watching: start watching app for response
|
||||
::
|
||||
++ start-watching
|
||||
|= [eyre-id=@ud app-id=@ud]
|
||||
^- [(list move) server-state]
|
||||
=/ start=(unit [duct=^duct app=term])
|
||||
(~(get by map.starting.state) eyre-id)
|
||||
?~ start
|
||||
~& [%invalid-starting-connection eyre-id]
|
||||
[~ state]
|
||||
::
|
||||
:_ state(map.starting (~(del by map.starting.state) eyre-id))
|
||||
:_ ~
|
||||
:* duct.u.start %pass /watch-response
|
||||
%m %deal [our our] app.u.start
|
||||
%watch /http-response/(scot %ud app-id)
|
||||
==
|
||||
:: +cancel-request: handles a request being externally aborted
|
||||
::
|
||||
++ cancel-request
|
||||
@ -1513,19 +1547,19 @@
|
||||
:: +on-gall-response: turns a gall response into an event
|
||||
::
|
||||
++ on-gall-response
|
||||
|= [channel-id=@t request-id=@ud =unto:mall]
|
||||
|= [channel-id=@t request-id=@ud =sign:agent:mall]
|
||||
^- [(list move) server-state]
|
||||
::
|
||||
?+ -.unto ~|([%invalid-gall-response -.unto] !!)
|
||||
?- -.sign
|
||||
%poke-ack
|
||||
=/ =json
|
||||
=, enjs:format
|
||||
%- pairs :~
|
||||
['response' [%s 'poke']]
|
||||
['id' (numb request-id)]
|
||||
?~ p.unto
|
||||
?~ p.sign
|
||||
['ok' [%s 'ok']]
|
||||
['err' (wall (render-tang-to-wall 100 u.p.unto))]
|
||||
['err' (wall (render-tang-to-wall 100 u.p.sign))]
|
||||
==
|
||||
::
|
||||
(emit-event channel-id [(en-json:html json)]~)
|
||||
@ -1537,8 +1571,8 @@
|
||||
['response' [%s 'diff']]
|
||||
['id' (numb request-id)]
|
||||
:- 'json'
|
||||
?> =(%json p.cage.unto)
|
||||
;;(json q.q.cage.unto)
|
||||
?> =(%json p.cage.sign)
|
||||
;;(json q.q.cage.sign)
|
||||
==
|
||||
::
|
||||
(emit-event channel-id [(en-json:html json)]~)
|
||||
@ -1560,9 +1594,9 @@
|
||||
%- pairs :~
|
||||
['response' [%s 'subscribe']]
|
||||
['id' (numb request-id)]
|
||||
?~ p.unto
|
||||
?~ p.sign
|
||||
['ok' [%s 'ok']]
|
||||
['err' (wall (render-tang-to-wall 100 u.p.unto))]
|
||||
['err' (wall (render-tang-to-wall 100 u.p.sign))]
|
||||
==
|
||||
::
|
||||
(emit-event channel-id [(en-json:html json)]~)
|
||||
@ -1805,6 +1839,8 @@
|
||||
%cancel
|
||||
:: todo: log this differently from an ise.
|
||||
::
|
||||
:: maybe should also send %leave to app?
|
||||
::
|
||||
error-connection
|
||||
==
|
||||
::
|
||||
@ -2110,6 +2146,10 @@
|
||||
%request-local
|
||||
=^ moves server-state.ax (request-local:server +.task)
|
||||
[moves http-server-gate]
|
||||
::
|
||||
%start-watching
|
||||
=^ moves server-state.ax (start-watching:server +.task)
|
||||
[moves http-server-gate]
|
||||
::
|
||||
%cancel-request
|
||||
=^ moves server-state.ax cancel-request:server
|
||||
@ -2169,6 +2209,7 @@
|
||||
~|([%bad-take-wire wire] !!)
|
||||
::
|
||||
%run-app-request run-app-request
|
||||
%watch-response watch-response
|
||||
%run-app-cancel run-app-cancel
|
||||
%run-build run-build
|
||||
%channel channel
|
||||
@ -2180,24 +2221,62 @@
|
||||
?> ?=([%m %unto *] sign)
|
||||
::
|
||||
::
|
||||
?: ?=([%poke-ack *] p.sign)
|
||||
?> ?=([%poke-ack *] p.sign)
|
||||
?~ p.p.sign
|
||||
:: received a positive acknowledgment: take no action
|
||||
::
|
||||
[~ http-server-gate]
|
||||
:: we have an error; propagate it to the client
|
||||
::
|
||||
=/ event-args [[our eny duct now scry-gate] server-state.ax]
|
||||
=/ handle-gall-error
|
||||
handle-gall-error:(per-server-event event-args)
|
||||
=^ moves server-state.ax
|
||||
(handle-gall-error u.p.p.sign)
|
||||
[moves http-server-gate]
|
||||
::
|
||||
++ watch-response
|
||||
::
|
||||
=/ event-args [[our eny duct now scry-gate] server-state.ax]
|
||||
::
|
||||
?: ?=([%m %unto %watch-ack *] sign)
|
||||
?~ p.p.sign
|
||||
:: received a positive acknowledgment: take no action
|
||||
::
|
||||
[~ http-server-gate]
|
||||
:: we have an error; propagate it to the client
|
||||
::
|
||||
=/ event-args [[our eny duct now scry-gate] server-state.ax]
|
||||
=/ handle-gall-error
|
||||
handle-gall-error:(per-server-event event-args)
|
||||
=^ moves server-state.ax (handle-gall-error u.p.p.sign)
|
||||
[moves http-server-gate]
|
||||
::
|
||||
?> ?=([%m %unto %http-response *] sign)
|
||||
?: ?=([%m %unto %kick ~] sign)
|
||||
=/ handle-response handle-response:(per-server-event event-args)
|
||||
=^ moves server-state.ax
|
||||
(handle-response %continue ~ &)
|
||||
[moves http-server-gate]
|
||||
::
|
||||
=/ event-args [[our eny duct now scry-gate] server-state.ax]
|
||||
?> ?=([%m %unto %fact *] sign)
|
||||
=/ =mark p.cage.p.sign
|
||||
=/ =vase q.cage.p.sign
|
||||
?. ?= ?(%http-response-header %http-response-data %http-response-cancel)
|
||||
mark
|
||||
=/ handle-gall-error
|
||||
handle-gall-error:(per-server-event event-args)
|
||||
=^ moves server-state.ax
|
||||
(handle-gall-error leaf+"eyre bad mark {<mark>}" ~)
|
||||
[moves http-server-gate]
|
||||
::
|
||||
=/ =http-event:http
|
||||
?- mark
|
||||
%http-response-header [%start !<(response-header:http vase) ~ |]
|
||||
%http-response-data [%continue !<((unit octs) vase) |]
|
||||
%http-response-cancel [%cancel ~]
|
||||
==
|
||||
=/ handle-response handle-response:(per-server-event event-args)
|
||||
=^ moves server-state.ax (handle-response http-event.p.sign)
|
||||
=^ moves server-state.ax
|
||||
(handle-response http-event)
|
||||
[moves http-server-gate]
|
||||
::
|
||||
++ run-app-cancel
|
||||
|
@ -535,8 +535,7 @@
|
||||
::
|
||||
[%m %unto *]
|
||||
?- +>-.hin
|
||||
$kick ~|([%jael-unexpected-quit tea hin] !!)
|
||||
$http-response ~|([%jael-unexpected-http-response tea hin] !!)
|
||||
$kick ~|([%jael-unexpected-quit tea hin] !!)
|
||||
$poke-ack
|
||||
?~ p.p.+>.hin
|
||||
+>.$
|
||||
|
@ -683,17 +683,17 @@
|
||||
mo-core
|
||||
::
|
||||
?> ?=([%m %unto *] sign-arvo)
|
||||
=/ =unto:agent +>.sign-arvo
|
||||
=/ =sign:agent +>.sign-arvo
|
||||
::
|
||||
?- -.unto
|
||||
?- -.sign
|
||||
%poke-ack
|
||||
(mo-give %mack p.unto)
|
||||
(mo-give %mack p.sign)
|
||||
::
|
||||
%fact
|
||||
=/ sys-path [%sys %red t.path]
|
||||
=/ =note-arvo
|
||||
=/ path [%m %gh dap ~]
|
||||
=/ noun [num %d p.cage.unto q.q.cage.unto]
|
||||
=/ noun [num %d p.cage.sign q.q.cage.sign]
|
||||
[%a %want him path noun]
|
||||
(mo-pass sys-path note-arvo)
|
||||
::
|
||||
@ -706,10 +706,7 @@
|
||||
(mo-pass sys-path note-arvo)
|
||||
::
|
||||
%watch-ack
|
||||
(mo-give %mack p.unto)
|
||||
::
|
||||
%http-response
|
||||
!!
|
||||
(mo-give %mack p.sign)
|
||||
==
|
||||
:: +mo-handle-sys-val: inbound validate.
|
||||
::
|
||||
@ -774,8 +771,7 @@
|
||||
::
|
||||
=. app (ap-generic-take:app t.t.path sign-arvo)
|
||||
ap-abet:app
|
||||
=/ =unto +>.sign-arvo
|
||||
?< ?=(%http-response -.unto)
|
||||
=/ =sign:agent +>.sign-arvo
|
||||
=/ app
|
||||
?> ?=([%out @ @ *] t.t.path)
|
||||
=/ =term i.path
|
||||
@ -783,7 +779,7 @@
|
||||
=/ =routes [disclosing=~ attributing=ship]
|
||||
(ap-abed:ap term routes)
|
||||
=. app
|
||||
(ap-specific-take:app t.t.path unto)
|
||||
(ap-specific-take:app t.t.path sign)
|
||||
ap-abet:app
|
||||
:: +mo-clear-queue: clear blocked tasks from the specified running agent.
|
||||
::
|
||||
|
@ -922,6 +922,9 @@
|
||||
:: starts handling an backdoor http request
|
||||
::
|
||||
[%request-local secure=? =address =request:http]
|
||||
:: initiates a subscription to get response
|
||||
::
|
||||
[%start-watching our-id=@ud app-id=@ud]
|
||||
:: cancels a previous request
|
||||
::
|
||||
[%cancel-request ~]
|
||||
@ -1876,7 +1879,7 @@
|
||||
$% {$mass p/mass} :: memory usage
|
||||
{$onto p/(each suss tang)} :: about agent
|
||||
{$rend p/path q/*} :: network request
|
||||
{$unto p/unto} ::
|
||||
{$unto p/sign:agent} ::
|
||||
{$mack p/(unit tang)} :: message ack
|
||||
== ::
|
||||
++ task :: incoming request
|
||||
@ -1928,10 +1931,6 @@
|
||||
[%pump ~]
|
||||
task:agent
|
||||
==
|
||||
+$ unto
|
||||
$% [%http-response =http-event:http]
|
||||
sign:agent
|
||||
==
|
||||
::
|
||||
:: +agent: app core
|
||||
::
|
||||
@ -1956,7 +1955,6 @@
|
||||
[%kick path=(unit path) ship=(unit ship)]
|
||||
[%watch-ack p=(unit tang)]
|
||||
[%poke-ack p=(unit tang)]
|
||||
[%http-response =http-event:http]
|
||||
==
|
||||
+$ sign
|
||||
$% [%poke-ack p=(unit tang)]
|
||||
|
Loading…
Reference in New Issue
Block a user