From 45d0e020dd38f3355ec6267ce6983e2d9b6a056b Mon Sep 17 00:00:00 2001 From: polwex Date: Thu, 5 Mar 2026 00:48:57 +0700 Subject: [PATCH 1/7] Added WebSockets support to Eyre and Iris cf. UIP-125 --- pkg/arvo/sys/lull.hoon | 48 +++++++++ pkg/arvo/sys/vane/eyre.hoon | 164 +++++++++++++++++++++++++++- pkg/arvo/sys/vane/iris.hoon | 210 +++++++++++++++++++++++++++++++++++- 3 files changed, 416 insertions(+), 6 deletions(-) diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index e071b53909..a2fe6b9020 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -3085,6 +3085,9 @@ :: notification that a cache entry has changed :: [%grow =path] + :: UIP-125 + :: + [%websocket-response wid=@ event=websocket-event] == :: +$ task @@ -3151,7 +3154,29 @@ :: remember (or update) a cache mapping :: [%set-response url=@t entry=(unit cache-entry)] + :: UIP-125 + :: + [%websocket-event ws-id=@ event=websocket-event] + [%websocket-handshake ws-id=@ secure=? =address =request:http] + + == + :: UIP-125 + :: + +$ websocket-connection + $: app=term + =inbound-request + == + +$ websocket-message + $: opcode=@ud + message=(unit data=octs) == + +$ websocket-event + $% [%accept ~] + [%reject ~] + [%disconnect ~] + [%message message=websocket-message] + == + :: +origin: request origin as specified in an Origin header :: +$ origin @torigin @@ -3956,6 +3981,11 @@ :: %response: response to the caller :: [%http-response =client-response] + :: UIP-125 + :: + [%websocket-handshake id=@ud url=@t] + [%websocket-response id=@ud websocket-event:eyre] + == :: +$ task @@ -3978,6 +4008,24 @@ :: receives http data from outside :: [%receive id=@ud =http-event:http] + :: UIP-125 + :: + [%cancel-websocket id=@ud] + :: receives websocket event from earth + [%websocket-connect app=term url=@t] + :: receives websocket event from earth + :: + [%websocket-event id=@ud event=websocket-event:eyre] + == + + :: UIP-125 + :: + +$ websocket-connection + $: app=term + =duct + id=@ud + url=@t + status=?(%pending %accepted) == :: +client-response: one or more client responses given to the caller :: diff --git a/pkg/arvo/sys/vane/eyre.hoon b/pkg/arvo/sys/vane/eyre.hoon index f65610dab2..0acc454c0d 100644 --- a/pkg/arvo/sys/vane/eyre.hoon +++ b/pkg/arvo/sys/vane/eyre.hoon @@ -43,7 +43,7 @@ ++ axle $: :: date: date at which http-server's state was updated to this data structure :: - date=%~2025.1.31 + date=%~2025.10.28 :: server-state: state of inbound requests :: =server-state @@ -95,6 +95,9 @@ :: who may have been affected by urbit/urbit#7103 :: check-session-timer=_| + :: UIP 125 + sockets=(map @ud websocket-connection) + == :: channel-request: an action requested on a channel :: @@ -1021,6 +1024,80 @@ %^ return-static-data-on-duct 404 'text/html' (error-page 404 authenticated url.request ~) == + :: WebSockets event + ++ ws-event + |= [wid=@ event=websocket-event] + =/ conn (~(get by connections.state) duct) + :: ~& ws-conn=conn + ?~ conn `state + ?. ?=(%app -.action.u.conn) `state + =/ url url.request.inbound-request.u.conn + =/ pat=(unit path) (rush url stap) + ?~ pat ~& error-parsing-path=pat `state + =/ app app.action.u.conn + =/ identity identity.u.conn + =/ wsid (scot %ud wid) + :: ~& >> ws-event=[identity app pat wsid] + :: TODO damn how + :: ~& eyre-ws-event=-.event + ?+ -.event `state + %message + :_ state + :~ %+ deal-as + /run-ws-app-request/[wsid] + :^ identity our app + :+ %poke %websocket-server-message + !>([wid u.pat message.event]) + == + %disconnect + =. connections.state (~(del by connections.state) duct) + :_ state + :~ %+ deal-as + /ws-watch-response/[wsid] + [identity our app %leave ~] + == + == + ++ ws-handshake + |= [wid=@ secure=? =address:eyre =request:http] + ^- [(list move) server-state] + + =/ host=(unit @t) (get-header:http 'host' header-list.request) + =/ [=action suburl=@t] + (get-action-for-binding host url.request) + :: TODO enable other actions + ?. ?=(%app -.action) `state + + :: TODO!! get clear what all the identity thing has to be + =/ app app.action + =^ ?(invalid=@uv [@uv identity (list move)]) state + (session-for-request:authentication request) + =/ [session-id=@uv =identity som=(list move)] + ?@ - ~& invalid-session=- + [invalid [%fake *@p] ~] - + + =/ authenticated ?=(%ours -.identity) + + =/ connection=outstanding-connection + [action [authenticated secure address request] [session-id identity] ~ 0] + + =. connections.state + (~(put by connections.state) duct connection) + :: eyre-id is assigned way up in this arm + =/ wsid (scot %ud wid) + :_ state + ~& som=som + %+ weld som + :~ %+ deal-as + /ws-watch-response/[wsid] + [identity our app %watch /websocket-server/[wsid]] + :: + %+ deal-as + /run-ws-app-request/[wsid] + :^ identity our app + :+ %poke %websocket-handshake + !>(`[@ inbound-request:eyre]`[wid inbound-request.connection]) + == + :: +handle-ip: respond with the requester's ip :: ++ handle-ip @@ -3079,6 +3156,28 @@ (subscription-wire channel-id request-id identity.session ship app) [identity.session ship app %leave ~] -- + + ++ handle-ws-response + |= [wid=@ event=websocket-event] + ^- [(list move) server-state] + =. connections.state + ?: ?=(%reject -.event) (~(del by connections.state) duct) + ?: ?=(%disconnect -.event) (~(del by connections.state) duct) + connections.state + =. sockets.state + ?: ?=(%reject -.event) (~(del by sockets.state) wid) + ?: ?=(%disconnect -.event) (~(del by sockets.state) wid) + ?: ?=(%accept -.event) + =/ outstanding (~(get by connections.state) duct) + ?~ outstanding ~& >>> eyre-ws-error=[wid event] sockets.state + =/ req=inbound-request inbound-request.u.outstanding + :: TODO this is bad + ?> ?=(%app -.action.u.outstanding) + (~(put by sockets.state) wid +.action.u.outstanding req) + sockets.state + + [[duct %give %websocket-response [wid event]]~ state] + :: +handle-gall-error: a call to +poke-http-response resulted in a %coup :: ++ handle-gall-error @@ -3853,6 +3952,14 @@ %set-response =^ moves server-state.ax (set-response:server +.task) [moves http-server-gate] + :: + %websocket-event + =^ moves server-state.ax (ws-event:server +.task) + [moves http-server-gate] + + %websocket-handshake + =^ moves server-state.ax (ws-handshake:server +.task) + [moves http-server-gate] == :: ++ take @@ -3886,8 +3993,56 @@ %channel channel %acme acme-ack %conversion-cache `http-server-gate + %run-ws-app-request run-ws-app-request + %ws-watch-response watch-ws-response == :: + ++ watch-ws-response + =/ event-args [[eny duct now rof] server-state.ax] + ?> ?=([@ *] t.wire) + ?+ sign `http-server-gate + [%gall %unto %watch-ack *] + ?~ p.p.sign + :: received a positive acknowledgment: take no action + :: + [~ http-server-gate] + :: we have an error; propagate it to the client + :: + ~& gall-error=u.p.p.sign + =/ 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] + :: + [%gall %unto %kick ~] + =/ handle-ws-response handle-ws-response:(per-server-event event-args) + =^ moves server-state.ax + :: TODO not great + =/ wids (head (flop wire)) + =/ wid (slav %ud wids) + (handle-ws-response wid [%disconnect ~]) + [moves http-server-gate] + :: + [%gall %unto %fact *] + =/ mark p.cage.p.sign + ?. ?=(%websocket-response mark) + =/ handle-gall-error + handle-gall-error:(per-server-event event-args) + =^ moves server-state.ax + (handle-gall-error leaf+"eyre bad mark {(trip mark)}" ~) + [moves http-server-gate] + =/ event !<([@ websocket-event] q.cage.p.sign) + =/ handle-ws-response handle-ws-response:(per-server-event event-args) + =^ moves server-state.ax + (handle-ws-response event) + [moves http-server-gate] + + == + ++ run-ws-app-request + + `http-server-gate + + :: ++ run-app-request :: ?> ?=([%gall %unto *] sign) @@ -4368,6 +4523,13 @@ == :: %~2025.1.31 + %= $ + date.old %~2025.10.28 + check-session-timer.old [check-session-timer.old sockets=~] + == + :: + %~2025.10.28 + http-server-gate(ax old) :: == diff --git a/pkg/arvo/sys/vane/iris.hoon b/pkg/arvo/sys/vane/iris.hoon index bdcfe1b42d..62fcb6de4f 100644 --- a/pkg/arvo/sys/vane/iris.hoon +++ b/pkg/arvo/sys/vane/iris.hoon @@ -38,7 +38,7 @@ +$ axle $: :: date: date at which iris state was updated to this data structure :: - date=%~2025.7.17 + date=%~2026.1.1 :: :: =state @@ -46,7 +46,10 @@ :: +state:client: state relating to open outbound HTTP connections :: +$ state - $: :: next-id: monotonically increasing id number for the next connection + $: :: sockets: ongoing websocket connections + :: + sockets=(map @ud websocket-connection) + :: next-id: monotonically increasing id number for the next connection :: next-id=@ud :: connection-by-id: open connections to the @@ -328,6 +331,94 @@ connection-by-id (~(del by connection-by-id.state) id) connection-by-duct (~(del by connection-by-duct.state) duct.u.con) == + :: UIP-125 + :: + ++ ws-connect + |= [desk=term url=@t] + ~& iris-ws-connect=[desk url duct] + + ?: (~(has by connection-by-duct.state) duct) + ~& "cant sent second ws-connect on same duct" `state + :: TODO ... the wid comes from vere tho...? + =^ id next-id.state [next-id.state +(next-id.state)] + + =/ wc=websocket-connection [desk duct id url %pending] + =. sockets.state (~(put by sockets.state) id wc) + :: :: keep track of the duct for cancellation + + :: This sends it to Vere to actually do the request + :- [outbound-duct.state %give %websocket-handshake id url]~ + state + ++ cleanup-ws + |= wid=@ud + ^- [(list move) ^state] + ?~ con=(~(get by sockets.state) wid) + `state + =. sockets.state (~(del by sockets.state) wid) + :_ state + :~ (leave-agent wid app.u.con) + == + + :: incoming websockets event to be sent BY VERE NOT USERSPACE + ++ ws-event + |= [wid=@ud event=websocket-event:eyre] + ~& iris-ws-event=[wid -.event duct] + =/ wc (~(get by sockets.state) wid) + ?~ wc `state + =/ wc u.wc + ~& wc=wc + =^ moves state + ?- -.event + %accept + =. wc wc(status %accepted) + =. sockets.state (~(put by sockets.state) wid wc) + :_ state + :~ (watch-agent wid app.wc) + == + %message :_ state + :~ (poke-agent [wid +.event] app.wc) + == + %reject (cleanup-ws wid) + + %disconnect (cleanup-ws wid) + == + =/ m2 (ws-response wc event) + [(welp m2 moves) state] + + ++ ws-response + |= [wc=websocket-connection event=websocket-event:eyre] + ~& ws-response=wc + :~ :* + duct.wc + %give + %websocket-response + id.wc + event + == == + + ++ ws-cancel + |= wid=@ud + =. sockets.state (~(del by sockets.state) wid) + :_ state + :: TODO this goes to vere + :~ [outbound-duct.state %give %cancel-request wid] + == + + ++ watch-agent + |= [wid=@ud app=term] ^- move + =/ wids (scot %ud wid) + =/ =note [%g %deal [our our /iris] app %watch /websocket-client/[wids]] + [duct %pass /ws-watch/[wids] note] + ++ leave-agent + |= [wid=@ud app=term] ^- move + ~& iris-leave-agent=[wid app] + =/ wids (scot %ud wid) + =/ =note [%g %deal [our our /iris] app %leave ~] + [duct %pass /ws-watch/[wids] note] + ++ poke-agent + |= [msg=[@ud websocket-message:eyre] app=term] ^- move + =/ =note [%g %deal [our our /iris] app %poke %websocket-client-message !>(msg)] + [duct %pass /iris-ws-poke note] -- -- :: end the =~ @@ -402,6 +493,17 @@ %receive =^ moves state.ax (receive:client +.task) [moves iris-gate] + :: UIP-125 + :: + %websocket-connect + =^ moves state.ax (ws-connect:client +.task) + [moves iris-gate] + %websocket-event + =^ moves state.ax (ws-event:client +.task) + [moves iris-gate] + %cancel-websocket + =^ moves state.ax (ws-cancel:client +.task) + [moves iris-gate] == :: http-client issues no requests to other vanes :: @@ -410,7 +512,51 @@ ^- [(list move) _iris-gate] ~> %spin.['take/iris'] ?< ?=(^ dud) - !! + :_ iris-gate + ?+ wire ~ + [%ws-watch wids=@t ~] =/ wid (slav %ud wids.wire) + ~& iris-ws-take=-.hin + ?+ -.hin ~ + %gall + ?> ?=(%unto +<.hin) + ~& hin=-.p.hin + ?+ -.p.hin ~ + ?(%poke-ack %watch-ack) + ?~ p.p.hin ~ + ~ + %kick + =/ event-args [[eny duct now rof] state.ax] + =/ client (per-client-event event-args) + =^ movs state.ax (cleanup-ws:client wid) + movs + %fact + =* cag cage.p.hin + :: This comes from agent, goes to vere + ~& > iris-take-ws-fact=p.cag + ?+ p.cag ~&(bad-fact+p.cag !!) + %message =/ msg !<(websocket-message:eyre q.cag) + :~ [outbound-duct.state.ax %give %websocket-response wid %message msg] + == + %disconnect + ~& iris-take-ws-disconnect=wid + =/ event-args [[eny duct now rof] state.ax] + =/ client (per-client-event event-args) + =^ movs state.ax (cleanup-ws:client wid) + %+ welp movs + :~ [outbound-duct.state.ax %give %websocket-response wid %disconnect ~] + == + :: =/ =tang !<(tang q.cag) + :: :: %- (slog 'khan-fact' tang) + :: :: [hen %give %arow %| p.cag tang]~ + :: ~ + :: :: + :: %thread-done + :: :: [hen %give %arow %& %noun q.cag]~ + :: ~ + == + == + == + == :: ++ iris-gate ..$ :: +load: migrate old state to new state (called on vane reload) @@ -419,7 +565,9 @@ => |% +$ axle-any $% [date=%~2019.2.8 state=state-0] - [date=%~2025.7.17 =state] + [date=%~2025.7.17 =state-1] + [date=%~2026.1.1 =state] + == :: +$ state-0 @@ -436,6 +584,12 @@ bytes-read=@ud expected-size=(unit @ud) == + +$ state-1 + $: next-id=@ud + connection-by-id=(map @ud [=duct =in-progress-http-request]) + connection-by-duct=(map duct @ud) + outbound-duct=duct + == -- |= old=axle-any ^+ iris-gate @@ -458,7 +612,13 @@ +.r(expected-size [expected-size.r *request:http]) == %~2025.7.17 - iris-gate(ax old) + =/ new-ax=axle + :- %~2026.1.1 + :- *(map @ud websocket-connection) + state.old + iris-gate(ax new-ax) + :: + %~2026.1.1 iris-gate(ax old) == :: +stay: produce current state :: @@ -470,6 +630,46 @@ |= [lyc=gang pov=path car=term bem=beam] ^- (unit (unit cage)) ~> %spin.['scry/iris'] + :: UIP-125 + :: scry state of open sockets + ~& >> iris-scry=[lyc=lyc pov=pov car=car bem=bem syd=q.bem] + ?. ?=(%x car) [~ ~] + =/ caller +<.pov + ?: ?=(%ws q.bem) + ~& iris-ws-scry-id=s.bem + ?+ s.bem ~ + ~ ``noun+!>(sockets.state.ax) + + [%app ~] + =| conns=(list [wid=@ud url=@t status=$?(%accepted %pending)]) + =/ sockets ~(tap by sockets.state.ax) + :: pass a (unit websocket-connection) + :- ~ :- ~ :- %noun !> + |- ?~ sockets conns + =/ socket=websocket-connection:iris q.i.sockets + ?. .=(app.socket caller) $(sockets t.sockets) + =. conns :_ conns [id.socket url.socket status.socket] + $(sockets t.sockets) + [%id @ ~] + ~& caller=caller + =/ wid (slav %ud i.t.s.bem) + =/ socket (~(get by sockets.state.ax) wid) + ?~ socket ``noun+!>(~) + ?. .=(app.u.socket caller) ~ + ``noun+!>(`[id.u.socket url.u.socket status.u.socket]) + + [%url @ ~] + =/ sockets ~(tap by sockets.state.ax) + :: pass a (unit websocket-connection) + :- ~ :- ~ :- %noun !> + |- ?~ sockets ~ + =/ socket=websocket-connection:iris q.i.sockets + ?. .=(app.socket caller) $(sockets t.sockets) + ?: .=(url.socket i.t.s.bem) `[id.socket url.socket status.socket] + $(sockets t.sockets) + == + :: /socket scry + :: =* ren car =* why=shop &/p.bem =* syd q.bem From 5ab62f9ad4b9958107167b78b07ec72f301e97c1 Mon Sep 17 00:00:00 2001 From: Tinnus Napbus Date: Tue, 10 Mar 2026 05:41:01 -0600 Subject: [PATCH 2/7] gw: iris/eyre fix websocket style issues --- pkg/arvo/sys/lull.hoon | 5 +- pkg/arvo/sys/vane/eyre.hoon | 160 +++++++++--------- pkg/arvo/sys/vane/iris.hoon | 318 ++++++++++++++++++------------------ 3 files changed, 242 insertions(+), 241 deletions(-) diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index a2fe6b9020..52a8425a64 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -3158,7 +3158,6 @@ :: [%websocket-event ws-id=@ event=websocket-event] [%websocket-handshake ws-id=@ secure=? =address =request:http] - == :: UIP-125 :: @@ -3176,7 +3175,6 @@ [%disconnect ~] [%message message=websocket-message] == - :: +origin: request origin as specified in an Origin header :: +$ origin @torigin @@ -3985,7 +3983,6 @@ :: [%websocket-handshake id=@ud url=@t] [%websocket-response id=@ud websocket-event:eyre] - == :: +$ task @@ -4012,12 +4009,12 @@ :: [%cancel-websocket id=@ud] :: receives websocket event from earth + :: [%websocket-connect app=term url=@t] :: receives websocket event from earth :: [%websocket-event id=@ud event=websocket-event:eyre] == - :: UIP-125 :: +$ websocket-connection diff --git a/pkg/arvo/sys/vane/eyre.hoon b/pkg/arvo/sys/vane/eyre.hoon index 0acc454c0d..6b10939dd4 100644 --- a/pkg/arvo/sys/vane/eyre.hoon +++ b/pkg/arvo/sys/vane/eyre.hoon @@ -96,8 +96,8 @@ :: check-session-timer=_| :: UIP 125 + :: sockets=(map @ud websocket-connection) - == :: channel-request: an action requested on a channel :: @@ -1025,6 +1025,7 @@ (error-page 404 authenticated url.request ~) == :: WebSockets event + :: ++ ws-event |= [wid=@ event=websocket-event] =/ conn (~(get by connections.state) duct) @@ -1040,46 +1041,44 @@ :: ~& >> ws-event=[identity app pat wsid] :: TODO damn how :: ~& eyre-ws-event=-.event - ?+ -.event `state - %message - :_ state - :~ %+ deal-as - /run-ws-app-request/[wsid] - :^ identity our app - :+ %poke %websocket-server-message - !>([wid u.pat message.event]) - == - %disconnect - =. connections.state (~(del by connections.state) duct) - :_ state - :~ %+ deal-as - /ws-watch-response/[wsid] - [identity our app %leave ~] - == + ?+ -.event `state + %message + :_ state + :~ %+ deal-as + /run-ws-app-request/[wsid] + :^ identity our app + :+ %poke %websocket-server-message + !>([wid u.pat message.event]) + == + :: + %disconnect + =. connections.state (~(del by connections.state) duct) + :_ state + :~ %+ deal-as + /ws-watch-response/[wsid] + [identity our app %leave ~] + == == + :: ++ ws-handshake |= [wid=@ secure=? =address:eyre =request:http] ^- [(list move) server-state] - =/ host=(unit @t) (get-header:http 'host' header-list.request) =/ [=action suburl=@t] (get-action-for-binding host url.request) :: TODO enable other actions ?. ?=(%app -.action) `state - - :: TODO!! get clear what all the identity thing has to be + :: TODO!! get clear what all the identity thing has to be =/ app app.action - =^ ?(invalid=@uv [@uv identity (list move)]) state + =^ $@(invalid=@uv [@uv identity (list move)]) state (session-for-request:authentication request) =/ [session-id=@uv =identity som=(list move)] - ?@ - ~& invalid-session=- - [invalid [%fake *@p] ~] - - + ?@ - + ~&(invalid-session=invalid [invalid [%fake *@p] ~]) + - =/ authenticated ?=(%ours -.identity) - =/ connection=outstanding-connection - [action [authenticated secure address request] [session-id identity] ~ 0] - + [action [authenticated secure address request] [session-id identity] ~ 0] =. connections.state (~(put by connections.state) duct connection) :: eyre-id is assigned way up in this arm @@ -1087,17 +1086,14 @@ :_ state ~& som=som %+ weld som - :~ %+ deal-as - /ws-watch-response/[wsid] + :~ %+ deal-as /ws-watch-response/[wsid] [identity our app %watch /websocket-server/[wsid]] :: - %+ deal-as - /run-ws-app-request/[wsid] + %+ deal-as /run-ws-app-request/[wsid] :^ identity our app :+ %poke %websocket-handshake !>(`[@ inbound-request:eyre]`[wid inbound-request.connection]) == - :: +handle-ip: respond with the requester's ip :: ++ handle-ip @@ -3156,28 +3152,29 @@ (subscription-wire channel-id request-id identity.session ship app) [identity.session ship app %leave ~] -- - + :: ++ handle-ws-response |= [wid=@ event=websocket-event] ^- [(list move) server-state] =. connections.state - ?: ?=(%reject -.event) (~(del by connections.state) duct) - ?: ?=(%disconnect -.event) (~(del by connections.state) duct) - connections.state + ?+ -.event connections.state + ?(%reject %disconnect) (~(del by connections.state) duct) + == =. sockets.state - ?: ?=(%reject -.event) (~(del by sockets.state) wid) - ?: ?=(%disconnect -.event) (~(del by sockets.state) wid) - ?: ?=(%accept -.event) + ?+ -.event sockets.state + ?(%reject %disconnect) + (~(del by sockets.state) wid) + :: + %accept =/ outstanding (~(get by connections.state) duct) - ?~ outstanding ~& >>> eyre-ws-error=[wid event] sockets.state + ?~ outstanding + ~& >>> eyre-ws-error=[wid event] sockets.state =/ req=inbound-request inbound-request.u.outstanding :: TODO this is bad ?> ?=(%app -.action.u.outstanding) - (~(put by sockets.state) wid +.action.u.outstanding req) - sockets.state - + (~(put by sockets.state) wid +.action.u.outstanding req) + == [[duct %give %websocket-response [wid event]]~ state] - :: +handle-gall-error: a call to +poke-http-response resulted in a %coup :: ++ handle-gall-error @@ -3987,12 +3984,12 @@ ?+ i.wire ~|([%bad-take-wire wire] !!) :: - %run-app-request run-app-request - %watch-response watch-response - %sessions sessions - %channel channel - %acme acme-ack - %conversion-cache `http-server-gate + %run-app-request run-app-request + %watch-response watch-response + %sessions sessions + %channel channel + %acme acme-ack + %conversion-cache `http-server-gate %run-ws-app-request run-ws-app-request %ws-watch-response watch-ws-response == @@ -4000,44 +3997,44 @@ ++ watch-ws-response =/ event-args [[eny duct now rof] server-state.ax] ?> ?=([@ *] t.wire) - ?+ sign `http-server-gate - [%gall %unto %watch-ack *] - ?~ p.p.sign - :: received a positive acknowledgment: take no action - :: - [~ http-server-gate] - :: we have an error; propagate it to the client + ?+ sign `http-server-gate + [%gall %unto %watch-ack *] + ?~ p.p.sign + :: received a positive acknowledgment: take no action :: - ~& gall-error=u.p.p.sign - =/ 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] - :: - [%gall %unto %kick ~] - =/ handle-ws-response handle-ws-response:(per-server-event event-args) - =^ moves server-state.ax + [~ http-server-gate] + :: we have an error; propagate it to the client + :: + ~& gall-error=u.p.p.sign + =/ 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] + :: + [%gall %unto %kick ~] + =/ handle-ws-response handle-ws-response:(per-server-event event-args) + =^ moves server-state.ax :: TODO not great =/ wids (head (flop wire)) =/ wid (slav %ud wids) - (handle-ws-response wid [%disconnect ~]) - [moves http-server-gate] - :: - [%gall %unto %fact *] - =/ mark p.cage.p.sign - ?. ?=(%websocket-response mark) - =/ handle-gall-error - handle-gall-error:(per-server-event event-args) - =^ moves server-state.ax - (handle-gall-error leaf+"eyre bad mark {(trip mark)}" ~) - [moves http-server-gate] - =/ event !<([@ websocket-event] q.cage.p.sign) - =/ handle-ws-response handle-ws-response:(per-server-event event-args) + (handle-ws-response wid [%disconnect ~]) + [moves http-server-gate] + :: + [%gall %unto %fact *] + =/ mark p.cage.p.sign + ?. ?=(%websocket-response mark) + =/ handle-gall-error + handle-gall-error:(per-server-event event-args) =^ moves server-state.ax - (handle-ws-response event) + (handle-gall-error leaf+"eyre bad mark {(trip mark)}" ~) + [moves http-server-gate] + =/ event !<([@ websocket-event] q.cage.p.sign) + =/ handle-ws-response handle-ws-response:(per-server-event event-args) + =^ moves server-state.ax + (handle-ws-response event) [moves http-server-gate] - == + :: ++ run-ws-app-request `http-server-gate @@ -4529,7 +4526,6 @@ == :: %~2025.10.28 - http-server-gate(ax old) :: == diff --git a/pkg/arvo/sys/vane/iris.hoon b/pkg/arvo/sys/vane/iris.hoon index 62fcb6de4f..7aab4dff6a 100644 --- a/pkg/arvo/sys/vane/iris.hoon +++ b/pkg/arvo/sys/vane/iris.hoon @@ -335,20 +335,19 @@ :: ++ ws-connect |= [desk=term url=@t] - ~& iris-ws-connect=[desk url duct] - - ?: (~(has by connection-by-duct.state) duct) - ~& "cant sent second ws-connect on same duct" `state - :: TODO ... the wid comes from vere tho...? - =^ id next-id.state [next-id.state +(next-id.state)] - - =/ wc=websocket-connection [desk duct id url %pending] - =. sockets.state (~(put by sockets.state) id wc) - :: :: keep track of the duct for cancellation - - :: This sends it to Vere to actually do the request - :- [outbound-duct.state %give %websocket-handshake id url]~ - state + ~& iris-ws-connect=[desk url duct] + ?: (~(has by connection-by-duct.state) duct) + ~& "cant sent second ws-connect on same duct" + `state + :: TODO ... the wid comes from vere tho...? + =^ id next-id.state [next-id.state +(next-id.state)] + =/ wc=websocket-connection [desk duct id url %pending] + =. sockets.state (~(put by sockets.state) id wc) + :: keep track of the duct for cancellation + :: This sends it to Vere to actually do the request + :_ state + [outbound-duct.state %give %websocket-handshake id url]~ + :: ++ cleanup-ws |= wid=@ud ^- [(list move) ^state] @@ -358,66 +357,73 @@ :_ state :~ (leave-agent wid app.u.con) == - :: incoming websockets event to be sent BY VERE NOT USERSPACE + :: ++ ws-event |= [wid=@ud event=websocket-event:eyre] - ~& iris-ws-event=[wid -.event duct] - =/ wc (~(get by sockets.state) wid) - ?~ wc `state - =/ wc u.wc - ~& wc=wc - =^ moves state - ?- -.event - %accept - =. wc wc(status %accepted) - =. sockets.state (~(put by sockets.state) wid wc) - :_ state - :~ (watch-agent wid app.wc) - == - %message :_ state - :~ (poke-agent [wid +.event] app.wc) - == - %reject (cleanup-ws wid) - + ~& iris-ws-event=[wid -.event duct] + =/ wc (~(get by sockets.state) wid) + ?~ wc `state + =/ wc u.wc + ~& wc=wc + =^ moves state + ?- -.event + %reject (cleanup-ws wid) %disconnect (cleanup-ws wid) + :: + %accept + =. wc wc(status %accepted) + =. sockets.state (~(put by sockets.state) wid wc) + :_ state + :~ (watch-agent wid app.wc) + == + :: + %message + :_ state + :~ (poke-agent [wid +.event] app.wc) == - =/ m2 (ws-response wc event) - [(welp m2 moves) state] - - ++ ws-response - |= [wc=websocket-connection event=websocket-event:eyre] - ~& ws-response=wc - :~ :* - duct.wc - %give - %websocket-response - id.wc - event - == == - + == + =/ m2 (ws-response wc event) + [(welp m2 moves) state] + :: + ++ ws-response + |= [wc=websocket-connection event=websocket-event:eyre] + ^- (list move) + ~& ws-response=wc + :~ :* duct.wc + %give + %websocket-response + id.wc + event + == == + :: ++ ws-cancel |= wid=@ud =. sockets.state (~(del by sockets.state) wid) :_ state :: TODO this goes to vere - :~ [outbound-duct.state %give %cancel-request wid] - == - + [outbound-duct.state %give %cancel-request wid]~ + :: ++ watch-agent - |= [wid=@ud app=term] ^- move - =/ wids (scot %ud wid) - =/ =note [%g %deal [our our /iris] app %watch /websocket-client/[wids]] - [duct %pass /ws-watch/[wids] note] + |= [wid=@ud app=term] + ^- move + =/ wids (scot %ud wid) + =/ =note [%g %deal [our our /iris] app %watch /websocket-client/[wids]] + [duct %pass /ws-watch/[wids] note] + :: ++ leave-agent - |= [wid=@ud app=term] ^- move - ~& iris-leave-agent=[wid app] - =/ wids (scot %ud wid) - =/ =note [%g %deal [our our /iris] app %leave ~] - [duct %pass /ws-watch/[wids] note] + |= [wid=@ud app=term] + ^- move + ~& iris-leave-agent=[wid app] + =/ wids (scot %ud wid) + =/ =note [%g %deal [our our /iris] app %leave ~] + [duct %pass /ws-watch/[wids] note] + :: ++ poke-agent - |= [msg=[@ud websocket-message:eyre] app=term] ^- move - =/ =note [%g %deal [our our /iris] app %poke %websocket-client-message !>(msg)] + |= [msg=[@ud websocket-message:eyre] app=term] + ^- move + =/ =note + [%g %deal [our our /iris] app %poke %websocket-client-message !>(msg)] [duct %pass /iris-ws-poke note] -- -- @@ -495,13 +501,15 @@ [moves iris-gate] :: UIP-125 :: - %websocket-connect + %websocket-connect =^ moves state.ax (ws-connect:client +.task) [moves iris-gate] - %websocket-event + %websocket-event + :: =^ moves state.ax (ws-event:client +.task) [moves iris-gate] - %cancel-websocket + :: + %cancel-websocket =^ moves state.ax (ws-cancel:client +.task) [moves iris-gate] == @@ -512,50 +520,45 @@ ^- [(list move) _iris-gate] ~> %spin.['take/iris'] ?< ?=(^ dud) - :_ iris-gate - ?+ wire ~ - [%ws-watch wids=@t ~] =/ wid (slav %ud wids.wire) - ~& iris-ws-take=-.hin - ?+ -.hin ~ + :_ iris-gate + ?+ wire ~ + [%ws-watch wids=@t ~] + =/ wid (slav %ud wids.wire) + ~& iris-ws-take=-.hin + ?+ -.hin ~ %gall - ?> ?=(%unto +<.hin) - ~& hin=-.p.hin - ?+ -.p.hin ~ - ?(%poke-ack %watch-ack) - ?~ p.p.hin ~ - ~ - %kick - =/ event-args [[eny duct now rof] state.ax] - =/ client (per-client-event event-args) - =^ movs state.ax (cleanup-ws:client wid) - movs - %fact - =* cag cage.p.hin - :: This comes from agent, goes to vere - ~& > iris-take-ws-fact=p.cag - ?+ p.cag ~&(bad-fact+p.cag !!) - %message =/ msg !<(websocket-message:eyre q.cag) - :~ [outbound-duct.state.ax %give %websocket-response wid %message msg] - == - %disconnect - ~& iris-take-ws-disconnect=wid - =/ event-args [[eny duct now rof] state.ax] - =/ client (per-client-event event-args) - =^ movs state.ax (cleanup-ws:client wid) - %+ welp movs - :~ [outbound-duct.state.ax %give %websocket-response wid %disconnect ~] - == - :: =/ =tang !<(tang q.cag) - :: :: %- (slog 'khan-fact' tang) - :: :: [hen %give %arow %| p.cag tang]~ - :: ~ - :: :: - :: %thread-done - :: :: [hen %give %arow %& %noun q.cag]~ - :: ~ - == + ?> ?=(%unto +<.hin) + ~& hin=-.p.hin + ?+ -.p.hin ~ + ?(%poke-ack %watch-ack) + ?~ p.p.hin ~ + ~ + :: + %kick + =/ event-args [[eny duct now rof] state.ax] + =/ client (per-client-event event-args) + =^ movs state.ax (cleanup-ws:client wid) + movs + :: + %fact + =* cag cage.p.hin + :: This comes from agent, goes to vere + ~& > iris-take-ws-fact=p.cag + ?+ p.cag ~&(bad-fact+p.cag !!) + %message + =/ msg !<(websocket-message:eyre q.cag) + [outbound-duct.state.ax %give %websocket-response wid %message msg]~ + :: + %disconnect + ~& iris-take-ws-disconnect=wid + =/ event-args [[eny duct now rof] state.ax] + =/ client (per-client-event event-args) + =^ movs state.ax (cleanup-ws:client wid) + %+ welp movs + [outbound-duct.state.ax %give %websocket-response wid %disconnect ~]~ == == + == == :: ++ iris-gate ..$ @@ -567,7 +570,6 @@ $% [date=%~2019.2.8 state=state-0] [date=%~2025.7.17 =state-1] [date=%~2026.1.1 =state] - == :: +$ state-0 @@ -596,29 +598,29 @@ ~> %spin.['load/iris'] ?- -.old %~2019.2.8 - %= $ - date.old %~2025.7.17 - :: - connection-by-id.state.old - %- ~(run by connection-by-id.state.old) - |= [d=duct r=in-progress-http-request-0] - ^- [duct in-progress-http-request] - :- d - :: set remaining redirects to 0 because we don't have the original request. - :: it's safe to bunt the .request because it only gets used if - :: .remaining-redirects is non-zero. + %= $ + date.old %~2025.7.17 :: - :- remaining-redirects=0 - +.r(expected-size [expected-size.r *request:http]) + connection-by-id.state.old + %- ~(run by connection-by-id.state.old) + |= [d=duct r=in-progress-http-request-0] + ^- [duct in-progress-http-request] + :- d + :: set remaining redirects to 0 because we don't have the original request. + :: it's safe to bunt the .request because it only gets used if + :: .remaining-redirects is non-zero. + :: + :- remaining-redirects=0 + +.r(expected-size [expected-size.r *request:http]) == + :: %~2025.7.17 =/ new-ax=axle - :- %~2026.1.1 - :- *(map @ud websocket-connection) - state.old - iris-gate(ax new-ax) - :: - %~2026.1.1 iris-gate(ax old) + [%~2026.1.1 *(map @ud websocket-connection) state.old] + iris-gate(ax new-ax) + :: + %~2026.1.1 + iris-gate(ax old) == :: +stay: produce current state :: @@ -637,36 +639,42 @@ =/ caller +<.pov ?: ?=(%ws q.bem) ~& iris-ws-scry-id=s.bem - ?+ s.bem ~ - ~ ``noun+!>(sockets.state.ax) - - [%app ~] - =| conns=(list [wid=@ud url=@t status=$?(%accepted %pending)]) - =/ sockets ~(tap by sockets.state.ax) - :: pass a (unit websocket-connection) - :- ~ :- ~ :- %noun !> - |- ?~ sockets conns - =/ socket=websocket-connection:iris q.i.sockets - ?. .=(app.socket caller) $(sockets t.sockets) - =. conns :_ conns [id.socket url.socket status.socket] - $(sockets t.sockets) - [%id @ ~] - ~& caller=caller - =/ wid (slav %ud i.t.s.bem) - =/ socket (~(get by sockets.state.ax) wid) - ?~ socket ``noun+!>(~) - ?. .=(app.u.socket caller) ~ - ``noun+!>(`[id.u.socket url.u.socket status.u.socket]) - - [%url @ ~] - =/ sockets ~(tap by sockets.state.ax) - :: pass a (unit websocket-connection) - :- ~ :- ~ :- %noun !> - |- ?~ sockets ~ - =/ socket=websocket-connection:iris q.i.sockets - ?. .=(app.socket caller) $(sockets t.sockets) - ?: .=(url.socket i.t.s.bem) `[id.socket url.socket status.socket] - $(sockets t.sockets) + ?+ s.bem ~ + ~ ``noun+!>(sockets.state.ax) + :: + [%app ~] + =| conns=(list [wid=@ud url=@t status=$?(%accepted %pending)]) + =/ sockets ~(tap by sockets.state.ax) + :: pass a (unit websocket-connection) + :^ ~ ~ %noun + !> + |- + ?~ sockets conns + =/ socket=websocket-connection:iris q.i.sockets + ?. =(app.socket caller) $(sockets t.sockets) + =. conns + :_ conns [id.socket url.socket status.socket] + $(sockets t.sockets) + :: + [%id @ ~] + ~& caller=caller + =/ wid (slav %ud i.t.s.bem) + =/ socket (~(get by sockets.state.ax) wid) + ?~ socket ``noun+!>(~) + ?. =(app.u.socket caller) ~ + ``noun+!>(`[id.u.socket url.u.socket status.u.socket]) + :: + [%url @ ~] + =/ sockets ~(tap by sockets.state.ax) + :: pass a (unit websocket-connection) + :^ ~ ~ %noun + !> + |- + ?~ sockets ~ + =/ socket=websocket-connection:iris q.i.sockets + ?. =(app.socket caller) $(sockets t.sockets) + ?: =(url.socket i.t.s.bem) `[id.socket url.socket status.socket] + $(sockets t.sockets) == :: /socket scry :: From 478c3bd91f37264fc0cae75823903cee75d31639 Mon Sep 17 00:00:00 2001 From: Tinnus Napbus Date: Wed, 11 Mar 2026 20:24:56 +1300 Subject: [PATCH 3/7] gw: eyre: more robust websocket path parsing --- pkg/arvo/sys/vane/eyre.hoon | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pkg/arvo/sys/vane/eyre.hoon b/pkg/arvo/sys/vane/eyre.hoon index 6b10939dd4..8465d4861c 100644 --- a/pkg/arvo/sys/vane/eyre.hoon +++ b/pkg/arvo/sys/vane/eyre.hoon @@ -1033,8 +1033,9 @@ ?~ conn `state ?. ?=(%app -.action.u.conn) `state =/ url url.request.inbound-request.u.conn - =/ pat=(unit path) (rush url stap) - ?~ pat ~& error-parsing-path=pat `state + =/ pat=(unit (list @t)) + (rush url ;~(pfix fas (more fas smeg:de-purl:html))) + ?~ pat ~&(error-parsing-path=url `state) =/ app app.action.u.conn =/ identity identity.u.conn =/ wsid (scot %ud wid) @@ -1073,9 +1074,8 @@ =^ $@(invalid=@uv [@uv identity (list move)]) state (session-for-request:authentication request) =/ [session-id=@uv =identity som=(list move)] - ?@ - - ~&(invalid-session=invalid [invalid [%fake *@p] ~]) - - + ?^ - - + ~&(invalid-session=invalid [invalid [%fake *@p] ~]) =/ authenticated ?=(%ours -.identity) =/ connection=outstanding-connection [action [authenticated secure address request] [session-id identity] ~ 0] @@ -3949,11 +3949,11 @@ %set-response =^ moves server-state.ax (set-response:server +.task) [moves http-server-gate] - :: + :: %websocket-event =^ moves server-state.ax (ws-event:server +.task) [moves http-server-gate] - + :: %websocket-handshake =^ moves server-state.ax (ws-handshake:server +.task) [moves http-server-gate] From 9bca16b80e2a3dca18ce3ac324101707b35bffc2 Mon Sep 17 00:00:00 2001 From: Tinnus Napbus Date: Wed, 11 Mar 2026 20:44:03 +1300 Subject: [PATCH 4/7] gw: eyre: fix +load logic --- pkg/arvo/sys/vane/eyre.hoon | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/pkg/arvo/sys/vane/eyre.hoon b/pkg/arvo/sys/vane/eyre.hoon index 8465d4861c..9b68fee745 100644 --- a/pkg/arvo/sys/vane/eyre.hoon +++ b/pkg/arvo/sys/vane/eyre.hoon @@ -4286,7 +4286,8 @@ [date=%~2023.4.11 server-state-3] [date=%~2023.5.15 server-state-4] [date=%~2024.8.20 server-state-4] - [date=%~2025.1.31 server-state] + [date=%~2025.1.31 server-state-5] + [date=%~2025.10.28 server-state] == :: +$ server-state-0 @@ -4399,6 +4400,21 @@ outgoing-duct=duct verb=@ == + :: + +$ server-state-5 + $: bindings=(list [=binding =duct =action]) + cache=(map url=@t [aeon=@ud val=(unit cache-entry)]) + =cors-registry + connections=(map duct outstanding-connection) + auth=authentication-state + =channel-state + domains=(set turf) + =http-config + ports=[insecure=@ud secure=(unit @ud)] + outgoing-duct=duct + verb=@ + check-session-timer=_| + == -- |= old=axle-any ^+ http-server-gate @@ -4518,6 +4534,8 @@ date.old %~2025.1.31 verb.old [verb.old check-session-timer=&] == + :: + :: adds web sockets: UIP-125 :: %~2025.1.31 %= $ From 6a6c3d90806029535d09f2c023e158811b8fed71 Mon Sep 17 00:00:00 2001 From: polwex Date: Thu, 5 Mar 2026 00:48:57 +0700 Subject: [PATCH 5/7] lull, eyre, iris: added WebSockets support, following UIP 125 --- pkg/arvo/sys/lull.hoon | 48 +++++++ pkg/arvo/sys/vane/eyre.hoon | 270 ++++++++++++++++++++++++++++++------ pkg/arvo/sys/vane/iris.hoon | 223 +++++++++++++++++++++++++++-- 3 files changed, 492 insertions(+), 49 deletions(-) diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index e071b53909..a2fe6b9020 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -3085,6 +3085,9 @@ :: notification that a cache entry has changed :: [%grow =path] + :: UIP-125 + :: + [%websocket-response wid=@ event=websocket-event] == :: +$ task @@ -3151,7 +3154,29 @@ :: remember (or update) a cache mapping :: [%set-response url=@t entry=(unit cache-entry)] + :: UIP-125 + :: + [%websocket-event ws-id=@ event=websocket-event] + [%websocket-handshake ws-id=@ secure=? =address =request:http] + + == + :: UIP-125 + :: + +$ websocket-connection + $: app=term + =inbound-request + == + +$ websocket-message + $: opcode=@ud + message=(unit data=octs) == + +$ websocket-event + $% [%accept ~] + [%reject ~] + [%disconnect ~] + [%message message=websocket-message] + == + :: +origin: request origin as specified in an Origin header :: +$ origin @torigin @@ -3956,6 +3981,11 @@ :: %response: response to the caller :: [%http-response =client-response] + :: UIP-125 + :: + [%websocket-handshake id=@ud url=@t] + [%websocket-response id=@ud websocket-event:eyre] + == :: +$ task @@ -3978,6 +4008,24 @@ :: receives http data from outside :: [%receive id=@ud =http-event:http] + :: UIP-125 + :: + [%cancel-websocket id=@ud] + :: receives websocket event from earth + [%websocket-connect app=term url=@t] + :: receives websocket event from earth + :: + [%websocket-event id=@ud event=websocket-event:eyre] + == + + :: UIP-125 + :: + +$ websocket-connection + $: app=term + =duct + id=@ud + url=@t + status=?(%pending %accepted) == :: +client-response: one or more client responses given to the caller :: diff --git a/pkg/arvo/sys/vane/eyre.hoon b/pkg/arvo/sys/vane/eyre.hoon index f65610dab2..d79cd06316 100644 --- a/pkg/arvo/sys/vane/eyre.hoon +++ b/pkg/arvo/sys/vane/eyre.hoon @@ -43,7 +43,7 @@ ++ axle $: :: date: date at which http-server's state was updated to this data structure :: - date=%~2025.1.31 + date=%~2025.10.28 :: server-state: state of inbound requests :: =server-state @@ -95,6 +95,8 @@ :: who may have been affected by urbit/urbit#7103 :: check-session-timer=_| + :: UIP 125 + sockets=(map @ud websocket-connection) == :: channel-request: an action requested on a channel :: @@ -638,6 +640,24 @@ |= [wid=@u tan=tang] ^- wall (zing (turn tan |=(a=tank (wash 0^wid a)))) +:: +wall-to-octs: text to binary output +:: +++ wall-to-octs + |= =wall + ^- (unit octs) + :: + ?: =(~ wall) + ~ + :: + :- ~ + %- as-octs:mimes:html + %- crip + %- zing ^- ^wall + %- zing ^- (list ^wall) + %+ turn wall + |= t=tape + ^- ^wall + ~[t "\0a"] :: +internal-server-error: 500 page, with a tang :: ++ internal-server-error @@ -802,7 +822,7 @@ =^ ?(invalid=@uv [suv=@uv =identity som=(list move)]) state (session-for-request:authentication request) ?@ - - :: the request provided a session cookie that's not (or no longer) + :: the request provided a session coocokie that's not (or no longer) :: valid. to make sure they're aware, tell them 401 :: ::NOTE some code duplication with below, but request handling deserves @@ -1021,6 +1041,79 @@ %^ return-static-data-on-duct 404 'text/html' (error-page 404 authenticated url.request ~) == + ++ ws-event + |= [wid=@ event=websocket-event] + =/ conn (~(get by connections.state) duct) + :: ~& ws-conn=conn + ?~ conn `state + ?. ?=(%app -.action.u.conn) `state + =/ url url.request.inbound-request.u.conn + =/ pat=(unit path) (rush url stap) + ?~ pat ~& error-parsing-path=pat `state + =/ app app.action.u.conn + =/ identity identity.u.conn + =/ wsid (scot %ud wid) + :: ~& >> ws-event=[identity app pat wsid] + :: TODO damn how + :: ~& eyre-ws-event=-.event + ?+ -.event `state + %message + :_ state + :~ %+ deal-as + /run-ws-app-request/[wsid] + :^ identity our app + :+ %poke %websocket-server-message + !>([wid u.pat message.event]) + == + %disconnect + =. connections.state (~(del by connections.state) duct) + :_ state + :~ %+ deal-as + /ws-watch-response/[wsid] + [identity our app %leave ~] + == + == + ++ ws-handshake + |= [wid=@ secure=? =address:eyre =request:http] + ^- [(list move) server-state] + + =/ host=(unit @t) (get-header:http 'host' header-list.request) + =/ [=action suburl=@t] + (get-action-for-binding host url.request) + :: TODO enable other actions + ?. ?=(%app -.action) `state + + :: TODO!! get clear what all the identity thing has to be + =/ app app.action + =^ ?(invalid=@uv [@uv identity (list move)]) state + (session-for-request:authentication request) + =/ [session-id=@uv =identity som=(list move)] + ?@ - ~& invalid-session=- + [invalid [%fake *@p] ~] - + + =/ authenticated ?=(%ours -.identity) + + =/ connection=outstanding-connection + [action [authenticated secure address request] [session-id identity] ~ 0] + + =. connections.state + (~(put by connections.state) duct connection) + :: eyre-id is assigned way up in this arm + =/ wsid (scot %ud wid) + :_ state + ~& som=som + %+ weld som + :~ %+ deal-as + /ws-watch-response/[wsid] + [identity our app %watch /websocket-server/[wsid]] + :: + %+ deal-as + /run-ws-app-request/[wsid] + :^ identity our app + :+ %poke %websocket-handshake + !>(`[@ inbound-request:eyre]`[wid inbound-request.connection]) + == + :: +handle-ip: respond with the requester's ip :: ++ handle-ip @@ -1046,7 +1139,10 @@ ++ galaxy-for |= =ship ^- @p - (rear (^^saxo:title rof /ames our now ship)) + =/ next (^^sein:title rof /eyre our now ship) + ?: ?=(%czar (clan:title next)) + next + $(ship next) :: ++ handle-sponsor |= [=identity =request:http] @@ -2400,7 +2496,7 @@ :: =/ mode=?(%json %jam) (find-channel-mode %'GET' header-list.request) - =^ [exit=? c=cord moves=(list move)] state + =^ [exit=? =wall moves=(list move)] state :: the request may include a 'Last-Event-Id' header :: =/ maybe-last-event-id=(unit @ud) @@ -2418,7 +2514,7 @@ =^ mos state %^ return-static-data-on-duct 403 'text/html' (error-page 403 | url.request ~) - [[& '' mos] state] + [[& ~ mos] state] :: make sure the request "mode" doesn't conflict with a prior request :: ::TODO or could we change that on the spot, given that only a single @@ -2428,7 +2524,7 @@ %^ return-static-data-on-duct 406 'text/html' =; msg=tape (error-page 406 %.y url.request msg) "channel already established in {(trip mode.channel)} mode" - [[& '' mos] state] + [[& ~ mos] state] :: when opening an event-stream, we must cancel our timeout timer :: if there's no duct already bound. else, kill the old request, :: we will replace its duct at the end of this arm @@ -2457,12 +2553,12 @@ :: :: combine the remaining queued events to send to the client :: - =; event-replay=cord + =; event-replay=wall [[| - cancel-moves] state] - %- roll :_ - |=([a=cord b=cord] (cat 3 a b)) + %- zing + %- flop =/ queue events.channel - =| events=(list cord) + =| events=(list wall) |- ^+ events ?: =(~ queue) @@ -2473,9 +2569,9 @@ :: since conversion failure also gets caught during first receive. :: we can't do anything about this, so consider it unsupported. =/ said - (channel-event-to-cord channel request-id channel-event) + (channel-event-to-tape channel request-id channel-event) ?~ said $ - $(events [(event-cord-to-event-stream id +.u.said) events]) + $(events [(event-tape-to-wall id +.u.said) events]) ?: exit [moves state] :: send the start event to the client :: @@ -2492,7 +2588,7 @@ :: instead. some clients won't consider the connection established :: until they've heard some bytes come over the wire. :: - ?. =(~ c) (some (as-octs:mimes:html c)) + ?. =(~ wall) (wall-to-octs wall) (some (as-octs:mimes:html ':\0a')) :: complete=%.n @@ -2800,8 +2896,8 @@ (sign-to-channel-event sign u.channel request-id) ?~ maybe-channel-event [~ state] =/ =channel-event u.maybe-channel-event - =/ said=(unit (quip move cord)) - (channel-event-to-cord u.channel request-id channel-event) + =/ said=(unit (quip move tape)) + (channel-event-to-tape u.channel request-id channel-event) =? moves ?=(^ said) (weld moves -.u.said) =* sending &(?=([%| *] state.u.channel) ?=(^ said)) @@ -2824,9 +2920,8 @@ :* %response %continue :: ^= data - :- ~ - %- as-octs:mimes:html - (event-cord-to-event-stream next-id +:(need said)) + %- wall-to-octs + (event-tape-to-wall next-id +:(need said)) :: complete=%.n == @@ -2887,10 +2982,9 @@ :* %response %continue :: ^= data - :- ~ - %- as-octs:mimes:html - %+ event-cord-to-event-stream next-id - +:(need (channel-event-to-cord u.channel request-id %kick ~)) + %- wall-to-octs + %+ event-tape-to-wall next-id + +:(need (channel-event-to-tape u.channel request-id %kick ~)) :: complete=%.n == @@ -2924,15 +3018,15 @@ ?. ?=([~ ~ *] des) ((trace 0 |.("no desk for app {}")) ~) `!<(=desk q.u.u.des) - :: +channel-event-to-cord: render channel-event from request-id in specified mode + :: +channel-event-to-tape: render channel-event from request-id in specified mode :: - ++ channel-event-to-cord + ++ channel-event-to-tape |= [=channel request-id=@ud =channel-event] - ^- (unit (quip move cord)) + ^- (unit (quip move tape)) ?- mode.channel %json %+ bind (channel-event-to-json channel request-id channel-event) - |=((quip move json) [+<- (en:json:html +<+)]) - %jam =- `[~ (scot %uw (jam -))] + |=((quip move json) [+<- (trip (en:json:html +<+))]) + %jam =- `[~ (scow %uw (jam -))] [request-id channel-event] == :: +channel-event-to-json: render channel event as json channel event @@ -3005,13 +3099,14 @@ == == :: - ++ event-cord-to-event-stream - ~% %eyre-cord-to-event-stream ..part ~ - |= [event-id=@ud data=cord] - ^- cord - %^ cat 3 - (cat 3 (cat 3 'id: ' (crip (a-co:co event-id))) '\0a') - (cat 3 (cat 3 'data: ' data) '\0a\0a') + ++ event-tape-to-wall + ~% %eyre-tape-to-wall ..part ~ + |= [event-id=@ud =tape] + ^- wall + :~ (weld "id: " (a-co:co event-id)) + (weld "data: " tape) + "" + == :: ++ on-channel-heartbeat |= channel-id=@t @@ -3113,6 +3208,27 @@ :: where we perform logging and state cleanup for connections that we're :: done with. :: + ++ handle-ws-response + |= [wid=@ event=websocket-event] + ^- [(list move) server-state] + =. connections.state + ?: ?=(%reject -.event) (~(del by connections.state) duct) + ?: ?=(%disconnect -.event) (~(del by connections.state) duct) + connections.state + =. sockets.state + ?: ?=(%reject -.event) (~(del by sockets.state) wid) + ?: ?=(%disconnect -.event) (~(del by sockets.state) wid) + ?: ?=(%accept -.event) + =/ outstanding (~(get by connections.state) duct) + ?~ outstanding ~& >>> eyre-ws-error=[wid event] sockets.state + =/ req=inbound-request inbound-request.u.outstanding + :: TODO this is bad + ?> ?=(%app -.action.u.outstanding) + (~(put by sockets.state) wid +.action.u.outstanding req) + sockets.state + + [[duct %give %websocket-response [wid event]]~ state] + ++ handle-response |= =http-event:http ^- [(list move) server-state] @@ -3555,7 +3671,6 @@ ~/ %eyre-call |= [=duct dud=(unit goof) wrapped-task=(hobo task)] ^- [(list move) _http-server-gate] - ~> %spin.['call/eyre'] :: =/ task=task ((harden task) wrapped-task) :: @@ -3852,6 +3967,14 @@ :: %set-response =^ moves server-state.ax (set-response:server +.task) + [moves http-server-gate] + %websocket-event + =^ moves server-state.ax (ws-event:server +.task) + [moves http-server-gate] + + + %websocket-handshake + =^ moves server-state.ax (ws-handshake:server +.task) [moves http-server-gate] == :: @@ -3859,7 +3982,6 @@ ~/ %eyre-take |= [=wire =duct dud=(unit goof) =sign] ^- [(list move) _http-server-gate] - ~> %spin.['take/eyre'] => %= . sign ?: ?=(%gall -.sign) @@ -3886,13 +4008,61 @@ %channel channel %acme acme-ack %conversion-cache `http-server-gate + %run-ws-app-request run-ws-app-request + %ws-watch-response watch-ws-response == :: + ++ watch-ws-response + =/ event-args [[eny duct now rof] server-state.ax] + ?> ?=([@ *] t.wire) + ?+ sign `http-server-gate + [%gall %unto %watch-ack *] + ?~ p.p.sign + :: received a positive acknowledgment: take no action + :: + [~ http-server-gate] + :: we have an error; propagate it to the client + :: + ~& gall-error=u.p.p.sign + =/ 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] + :: + [%gall %unto %kick ~] + =/ handle-ws-response handle-ws-response:(per-server-event event-args) + =^ moves server-state.ax + :: TODO not great + =/ wids (head (flop wire)) + =/ wid (slav %ud wids) + (handle-ws-response wid [%disconnect ~]) + [moves http-server-gate] + :: + [%gall %unto %fact *] + =/ mark p.cage.p.sign + ?. ?=(%websocket-response mark) + =/ handle-gall-error + handle-gall-error:(per-server-event event-args) + =^ moves server-state.ax + (handle-gall-error leaf+"eyre bad mark {(trip mark)}" ~) + [moves http-server-gate] + =/ event !<([@ websocket-event] q.cage.p.sign) + =/ handle-ws-response handle-ws-response:(per-server-event event-args) + =^ moves server-state.ax + (handle-ws-response event) + [moves http-server-gate] + + == + ++ run-ws-app-request + + `http-server-gate + ++ run-app-request :: ?> ?=([%gall %unto *] sign) :: :: + :: ~& run-app-req-eyre=p.sign ?> ?=([%poke-ack *] p.sign) ?> ?=([@ *] t.wire) ?~ p.p.sign @@ -3920,6 +4090,7 @@ [~ http-server-gate] :: we have an error; propagate it to the client :: + ~& eyre-watch-response-gall-error=duct =/ handle-gall-error handle-gall-error:(per-server-event event-args) =^ moves server-state.ax (handle-gall-error u.p.p.sign) @@ -4134,7 +4305,8 @@ [date=%~2023.4.11 server-state-3] [date=%~2023.5.15 server-state-4] [date=%~2024.8.20 server-state-4] - [date=%~2025.1.31 server-state] + [date=%~2025.1.31 server-state-5] + [date=%~2025.10.28 server-state] == :: +$ server-state-0 @@ -4246,11 +4418,24 @@ ports=[insecure=@ud secure=(unit @ud)] outgoing-duct=duct verb=@ + == + +$ server-state-5 + $: bindings=(list [=binding =duct =action]) + cache=(map url=@t [aeon=@ud val=(unit cache-entry)]) + =cors-registry + connections=(map duct outstanding-connection) + auth=authentication-state + =channel-state + domains=(set turf) + =http-config + ports=[insecure=@ud secure=(unit @ud)] + outgoing-duct=duct + verb=@ + check-session-timer=_| == -- |= old=axle-any ^+ http-server-gate - ~> %spin.['load/eyre'] ?- -.old :: :: adds /~/name @@ -4366,8 +4551,13 @@ date.old %~2025.1.31 verb.old [verb.old check-session-timer=&] == - :: %~2025.1.31 + %= $ + date.old %~2025.10.28 + check-session-timer.old [check-session-timer.old sockets=~] + == + :: + %~2025.10.28 http-server-gate(ax old) :: == @@ -4381,7 +4571,6 @@ ^- roon |= [lyc=gang pov=path car=term bem=beam] ^- (unit (unit cage)) - ~> %spin.['scry/eyre'] =* ren car =* why=shop &/p.bem =* syd q.bem @@ -4559,3 +4748,4 @@ == == -- + diff --git a/pkg/arvo/sys/vane/iris.hoon b/pkg/arvo/sys/vane/iris.hoon index bdcfe1b42d..f12593a325 100644 --- a/pkg/arvo/sys/vane/iris.hoon +++ b/pkg/arvo/sys/vane/iris.hoon @@ -29,8 +29,11 @@ $: %d :: :: - $% [%flog =flog:dill] - == == == + $% [%flog =flog:dill] + == + == + [%g $>(%deal task:gall)] + == -- :: more structures :: @@ -38,7 +41,7 @@ +$ axle $: :: date: date at which iris state was updated to this data structure :: - date=%~2025.7.17 + date=%~2026.1.1 :: :: =state @@ -46,7 +49,10 @@ :: +state:client: state relating to open outbound HTTP connections :: +$ state - $: :: next-id: monotonically increasing id number for the next connection + $: :: sockets: ongoing websocket connections + :: + sockets=(map @ud websocket-connection) + :: next-id: monotonically increasing id number for the next connection :: next-id=@ud :: connection-by-id: open connections to the @@ -328,6 +334,94 @@ connection-by-id (~(del by connection-by-id.state) id) connection-by-duct (~(del by connection-by-duct.state) duct.u.con) == + :: UIP-125 + :: + ++ ws-connect + |= [desk=term url=@t] + ~& iris-ws-connect=[desk url duct] + + ?: (~(has by connection-by-duct.state) duct) + ~& "cant sent second ws-connect on same duct" `state + :: TODO ... the wid comes from vere tho...? + =^ id next-id.state [next-id.state +(next-id.state)] + + =/ wc=websocket-connection [desk duct id url %pending] + =. sockets.state (~(put by sockets.state) id wc) + :: :: keep track of the duct for cancellation + + :: This sends it to Vere to actually do the request + :- [outbound-duct.state %give %websocket-handshake id url]~ + state + ++ cleanup-ws + |= wid=@ud + ^- [(list move) ^state] + ?~ con=(~(get by sockets.state) wid) + `state + =. sockets.state (~(del by sockets.state) wid) + :_ state + :~ (leave-agent wid app.u.con) + == + + :: incoming websockets event to be sent BY VERE NOT USERSPACE + ++ ws-event + |= [wid=@ud event=websocket-event:eyre] + ~& iris-ws-event=[wid -.event duct] + =/ wc (~(get by sockets.state) wid) + ?~ wc `state + =/ wc u.wc + ~& wc=wc + =^ moves state + ?- -.event + %accept + =. wc wc(status %accepted) + =. sockets.state (~(put by sockets.state) wid wc) + :_ state + :~ (watch-agent wid app.wc) + == + %message :_ state + :~ (poke-agent [wid +.event] app.wc) + == + %reject (cleanup-ws wid) + + %disconnect (cleanup-ws wid) + == + =/ m2 (ws-response wc event) + [(welp m2 moves) state] + + ++ ws-response + |= [wc=websocket-connection event=websocket-event:eyre] + ~& ws-response=wc + :~ :* + duct.wc + %give + %websocket-response + id.wc + event + == == + + ++ ws-cancel + |= wid=@ud + =. sockets.state (~(del by sockets.state) wid) + :_ state + :: TODO this goes to vere + :~ [outbound-duct.state %give %cancel-request wid] + == + + ++ watch-agent + |= [wid=@ud app=term] ^- move + =/ wids (scot %ud wid) + =/ =note [%g %deal [our our /iris] app %watch /websocket-client/[wids]] + [duct %pass /ws-watch/[wids] note] + ++ leave-agent + |= [wid=@ud app=term] ^- move + ~& iris-leave-agent=[wid app] + =/ wids (scot %ud wid) + =/ =note [%g %deal [our our /iris] app %leave ~] + [duct %pass /ws-watch/[wids] note] + ++ poke-agent + |= [msg=[@ud websocket-message:eyre] app=term] ^- move + =/ =note [%g %deal [our our /iris] app %poke %websocket-client-message !>(msg)] + [duct %pass /iris-ws-poke note] -- -- :: end the =~ @@ -402,15 +496,71 @@ %receive =^ moves state.ax (receive:client +.task) [moves iris-gate] + :: UIP-125 + :: + %websocket-connect + =^ moves state.ax (ws-connect:client +.task) + [moves iris-gate] + %websocket-event + =^ moves state.ax (ws-event:client +.task) + [moves iris-gate] + %cancel-websocket + =^ moves state.ax (ws-cancel:client +.task) + [moves iris-gate] == :: http-client issues no requests to other vanes :: ++ take - |= [=wire =duct dud=(unit goof) sign=*] + |= [wire=(pole knot) =duct dud=(unit goof) hin=sign-arvo] ^- [(list move) _iris-gate] ~> %spin.['take/iris'] + ~& iris-take=[wire duct] ?< ?=(^ dud) - !! + :_ iris-gate + ?+ wire ~ + [%ws-watch wids=@t ~] =/ wid (slav %ud wids.wire) + ~& iris-ws-take=-.hin + ?+ -.hin ~ + %gall + ?> ?=(%unto +<.hin) + ~& hin=-.p.hin + ?+ -.p.hin ~ + ?(%poke-ack %watch-ack) + ?~ p.p.hin ~ + ~ + %kick + =/ event-args [[eny duct now rof] state.ax] + =/ client (per-client-event event-args) + =^ movs state.ax (cleanup-ws:client wid) + movs + %fact + =* cag cage.p.hin + :: This comes from agent, goes to vere + ~& > iris-take-ws-fact=p.cag + ?+ p.cag ~&(bad-fact+p.cag !!) + %message =/ msg !<(websocket-message:eyre q.cag) + :~ [outbound-duct.state.ax %give %websocket-response wid %message msg] + == + %disconnect + ~& iris-take-ws-disconnect=wid + =/ event-args [[eny duct now rof] state.ax] + =/ client (per-client-event event-args) + =^ movs state.ax (cleanup-ws:client wid) + %+ welp movs + :~ [outbound-duct.state.ax %give %websocket-response wid %disconnect ~] + == + :: =/ =tang !<(tang q.cag) + :: :: %- (slog 'khan-fact' tang) + :: :: [hen %give %arow %| p.cag tang]~ + :: ~ + :: :: + :: %thread-done + :: :: [hen %give %arow %& %noun q.cag]~ + :: ~ + == + == + == + == :: ++ iris-gate ..$ :: +load: migrate old state to new state (called on vane reload) @@ -419,7 +569,8 @@ => |% +$ axle-any $% [date=%~2019.2.8 state=state-0] - [date=%~2025.7.17 =state] + [date=%~2025.7.17 state=state-1] + [date=%~2026.1.1 =state] == :: +$ state-0 @@ -436,6 +587,12 @@ bytes-read=@ud expected-size=(unit @ud) == + +$ state-1 + $: next-id=@ud + connection-by-id=(map @ud [=duct =in-progress-http-request]) + connection-by-duct=(map duct @ud) + outbound-duct=duct + == -- |= old=axle-any ^+ iris-gate @@ -457,8 +614,15 @@ :- remaining-redirects=0 +.r(expected-size [expected-size.r *request:http]) == + :: %~2025.7.17 - iris-gate(ax old) + =/ new-ax=axle + :- %~2026.1.1 + :- *(map @ud websocket-connection) + state.old + iris-gate(ax new-ax) + :: + %~2026.1.1 iris-gate(ax old) == :: +stay: produce current state :: @@ -470,6 +634,46 @@ |= [lyc=gang pov=path car=term bem=beam] ^- (unit (unit cage)) ~> %spin.['scry/iris'] + :: UIP-125 + :: scry state of open sockets + ~& >> iris-scry=[lyc=lyc pov=pov car=car bem=bem syd=q.bem] + ?. ?=(%x car) [~ ~] + =/ caller +<.pov + ?: ?=(%ws q.bem) + ~& iris-ws-scry-id=s.bem + ?+ s.bem ~ + ~ ``noun+!>(sockets.state.ax) + + [%app ~] + =| conns=(list [wid=@ud url=@t status=$?(%accepted %pending)]) + =/ sockets ~(tap by sockets.state.ax) + :: pass a (unit websocket-connection) + :- ~ :- ~ :- %noun !> + |- ?~ sockets conns + =/ socket=websocket-connection:iris q.i.sockets + ?. .=(app.socket caller) $(sockets t.sockets) + =. conns :_ conns [id.socket url.socket status.socket] + $(sockets t.sockets) + [%id @ ~] + ~& caller=caller + =/ wid (slav %ud i.t.s.bem) + =/ socket (~(get by sockets.state.ax) wid) + ?~ socket ``noun+!>(~) + ?. .=(app.u.socket caller) ~ + ``noun+!>(`[id.u.socket url.u.socket status.u.socket]) + + [%url @ ~] + =/ sockets ~(tap by sockets.state.ax) + :: pass a (unit websocket-connection) + :- ~ :- ~ :- %noun !> + |- ?~ sockets ~ + =/ socket=websocket-connection:iris q.i.sockets + ?. .=(app.socket caller) $(sockets t.sockets) + ?: .=(url.socket i.t.s.bem) `[id.socket url.socket status.socket] + $(sockets t.sockets) + == + :: /socket scry + :: =* ren car =* why=shop &/p.bem =* syd q.bem @@ -478,7 +682,7 @@ :: ?. ?=(%& -.why) ~ =* his p.why - ?: &(?=(%x ren) =(tyl //whey) =([~ ~] lyc)) + ?: &(=(tyl //whey) =([~ ~] lyc)) =/ maz=(list mass) :~ nex+&+next-id.state.ax outbound+&+outbound-duct.state.ax @@ -489,3 +693,4 @@ ``mass+!>(maz) [~ ~] -- + From cf18acaa85186731a09503737c3b0eb855caee72 Mon Sep 17 00:00:00 2001 From: Tinnus Napbus Date: Wed, 11 Mar 2026 23:23:12 +1300 Subject: [PATCH 6/7] gw: iris: fix +scry and +load --- pkg/arvo/sys/vane/iris.hoon | 94 +++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 51 deletions(-) diff --git a/pkg/arvo/sys/vane/iris.hoon b/pkg/arvo/sys/vane/iris.hoon index 7aab4dff6a..a2c78e0f15 100644 --- a/pkg/arvo/sys/vane/iris.hoon +++ b/pkg/arvo/sys/vane/iris.hoon @@ -615,9 +615,10 @@ == :: %~2025.7.17 - =/ new-ax=axle - [%~2026.1.1 *(map @ud websocket-connection) state.old] - iris-gate(ax new-ax) + %= $ + date.old %~2026.1.1 + state.old [*(map @ud websocket-connection) state.old] + == :: %~2026.1.1 iris-gate(ax old) @@ -632,52 +633,6 @@ |= [lyc=gang pov=path car=term bem=beam] ^- (unit (unit cage)) ~> %spin.['scry/iris'] - :: UIP-125 - :: scry state of open sockets - ~& >> iris-scry=[lyc=lyc pov=pov car=car bem=bem syd=q.bem] - ?. ?=(%x car) [~ ~] - =/ caller +<.pov - ?: ?=(%ws q.bem) - ~& iris-ws-scry-id=s.bem - ?+ s.bem ~ - ~ ``noun+!>(sockets.state.ax) - :: - [%app ~] - =| conns=(list [wid=@ud url=@t status=$?(%accepted %pending)]) - =/ sockets ~(tap by sockets.state.ax) - :: pass a (unit websocket-connection) - :^ ~ ~ %noun - !> - |- - ?~ sockets conns - =/ socket=websocket-connection:iris q.i.sockets - ?. =(app.socket caller) $(sockets t.sockets) - =. conns - :_ conns [id.socket url.socket status.socket] - $(sockets t.sockets) - :: - [%id @ ~] - ~& caller=caller - =/ wid (slav %ud i.t.s.bem) - =/ socket (~(get by sockets.state.ax) wid) - ?~ socket ``noun+!>(~) - ?. =(app.u.socket caller) ~ - ``noun+!>(`[id.u.socket url.u.socket status.u.socket]) - :: - [%url @ ~] - =/ sockets ~(tap by sockets.state.ax) - :: pass a (unit websocket-connection) - :^ ~ ~ %noun - !> - |- - ?~ sockets ~ - =/ socket=websocket-connection:iris q.i.sockets - ?. =(app.socket caller) $(sockets t.sockets) - ?: =(url.socket i.t.s.bem) `[id.socket url.socket status.socket] - $(sockets t.sockets) - == - :: /socket scry - :: =* ren car =* why=shop &/p.bem =* syd q.bem @@ -686,7 +641,9 @@ :: ?. ?=(%& -.why) ~ =* his p.why - ?: &(?=(%x ren) =(tyl //whey) =([~ ~] lyc)) + ?. =([~ ~] lyc)) ~ + :: + ?: &(?=(%x ren) =(tyl //whey)) =/ maz=(list mass) :~ nex+&+next-id.state.ax outbound+&+outbound-duct.state.ax @@ -695,5 +652,40 @@ axle+&+ax == ``mass+!>(maz) - [~ ~] + :: + ~& >> iris-scry=[lyc=lyc pov=pov car=car bem=bem syd=q.bem] + ~& iris-ws-scry-id=tyl + ?. =([%$ our] why) ~ + ?. &(?=(%x ren) ?=(%$ syd)) ~ + ?+ tyl ~ + [%ws ~] ``noun+!>(sockets.state.ax) + :: + [%ws app=@ ~] + :^ ~ ~ %noun + !> ^- (list [wid=@ud url=@t status=?(%accepted %pending)]) + %+ murn ~(tap by sockets.state.ax) + |= [wid=@ud conn=websocket-connection] + ^- (unit [wid=@ud url=@t status=?(%accepted %pending)] + ?. =(app.tyl app.socket) ~ + `[id url status]:conn + :: + [%ws app=@ %id id=@ ~] + =/ wid (slav %ud id.tyl) + ?~ suc=(~(get by sockets.state.ax) wid) + ``noun+!>(~) + ?. =(app.u.suc app.tyl) [~ ~] + ``noun+!>(`[id url status]:u.suc) + :: + [%ws app=@ %url url=@ ~] + =/ sockets ~(tap by sockets.state.ax) + :: pass a (unit websocket-connection) + :^ ~ ~ %noun + !> + |- ^- [wid=@ud url=@t status=?(%accepted %pending)] + ?~ sockets ~ + =/ socket=websocket-connection q.i.sockets + ?. =(app.socket app.tyl) $(sockets t.sockets) + ?. =(url.socket url.tyl) $(sockets t.sockets) + `[id url status]:socket + == -- From 97804882aaf146b49b609dfeb78f56e2ff78a44a Mon Sep 17 00:00:00 2001 From: Tinnus Napbus Date: Wed, 11 Mar 2026 23:32:19 +1300 Subject: [PATCH 7/7] gw: iris: add %g %deal to note type --- pkg/arvo/sys/vane/iris.hoon | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/pkg/arvo/sys/vane/iris.hoon b/pkg/arvo/sys/vane/iris.hoon index a2c78e0f15..0ff5aa74f0 100644 --- a/pkg/arvo/sys/vane/iris.hoon +++ b/pkg/arvo/sys/vane/iris.hoon @@ -30,7 +30,16 @@ :: :: $% [%flog =flog:dill] - == == == + == == + :: + :: %g: to gall + :: + $: %g + :: + :: + $% [%deal p=sack q=term r=deal:gall] + == == + == -- :: more structures :: @@ -499,13 +508,13 @@ %receive =^ moves state.ax (receive:client +.task) [moves iris-gate] - :: UIP-125 + :: UIP-125 :: %websocket-connect =^ moves state.ax (ws-connect:client +.task) [moves iris-gate] - %websocket-event :: + %websocket-event =^ moves state.ax (ws-event:client +.task) [moves iris-gate] ::