1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
---
uip: "0125"
title: "%eyre/%iris: Support Websocket"
description: "Support Websocket connections on Eyre/Iris"
author: ~fidwed-sipwyn
status: Stagnant
type: Standards Track
category: Kernel
created: 2024-04-27
---
## Abstract
This proposal adds Websocket functionality that works in a similar manner to the currently `%eyre`/`%iris` HTTP interface. Users who wish to receive Websocket connections will use the existing `%eyre`'s `%connect` `$task` to bind a URL path where the websocket handshakes will arrive (since they are technically also HTTP requests, this should be intuitive). To initiate a connection, users should pass a `%websocket-connect` `$task` to `%iris`. Once the connection is established, the client/server vanes interaction with the apps occurs through `%gall` pokes, facts and subscriptions.
## Motivation
Websocket support will allow Urbit to interact with a wider variety of systems/protocols.
## Specification
- **%eyre** will have a new `$gift` and a new `$task`:
```hoon
:: $gift
::
:: websocket-reponse: event to earth
::
[%websocket-response event=websocket-event]
:: $task
::
:: receives websocket event from earth
::
[%websocket-event event=websocket-event]
```
- And the following new types:
```hoon
:: +websocket-connection: connection to be store in eyre state
::
+$ websocket-connection
$: app=term
=inbound-request
==
:: +websocket-message: websocket message content
::
+$ websocket-message
$: opcode=@ud
message=(unit data=octs)
==
:: +websocket-event: inbound/outbound websocket event
::
+$ websocket-event
$% [%accept ~]
[%reject ~]
[%disconnect ~]
[%message message=websocket-message]
==
::
```
- **%iris** will have two new `$gift`s and two new `$task`s:
```hoon
:: $gift
::
:: %websocket-handshake: outbound websocket-handshake to earth
::
[%websocket-handshake id=@ud url=@t]
:: %websocket-response: event to earth
::
[%websocket-response id=@ud websocket-event:eyre]
:: $task
::
:: request to open websocket connection
::
[%websocket-connect app=term url=@t]
:: receives websocket event from earth
::
[%websocket-event id=@ud event=websocket-event:eyre]
```
- And a new type:
```hoon
:: +websocket-connection: websocket connection stored in iris state
::
+$ websocket-connection
$: app=term
=duct
id=@ud
url=@t
status=?(%pending %accepted)
==
```
- %eyre will share the `$websocket-message` and `$websocket-event` types with %iris.
- The only new `$task` that the app devs will utilize is the `%websocket-connect` from iris.
- The existing `%cancel-request` `$task` from iris will be modified to also cancel websocket requests.
- Server user flow:
- The user exposes their app with the `%eyre`'s `%connect` `$task`.
- When a handshake comes from earth, `%eyre` subscribes to the app's `/websocket-server/[eyre-id]` path and sends a `%websocket-handshake` poke with `[eyre-id inbound-request]`. The `eyre-id` will be used to represent that particular connection.
- In response to `%websocket-handshake`, the user gives a fact with the `%accept` or `%reject` mark on `/websocket-server/[eyre-id]`.
- After `%accept`ed the app can give `%message`s facts on `/websocket-server/[eyre-id]` and receives messages that comes as `%websocket-server-message`s pokes, containing `[eyre-id websocket-message]`.
- If the subscription is kicked, then the connection is closed, or the user can give a fact with the `%disconnect` mark to close it.
- Client user flow:
- The user sends a request to initiate the connection by passing the `%websocket-connect` `$task` to `%iris` with `[app=term url=@t]`.
- The user can cancel the request by using the `%cancel-request` `$task`.
- If the connection succeeds `%iris` will subscribe to `/websocket-client/id`, with `id` representing that particular connection.
- The app can give facts with the `%message` mark on `/websocket-client/id` and receives messages that comes as `%websocket-client-message`s pokes, containing `[id websocket-message]`.
- If the subscription is kicked, then the connection is closed, or the user can give a fact with the `%disconnect` mark to close it.
## Rationale
The approach followed here is a way to add the intended feature while reutilizing some of the existing logic and without adding a new vane.
## Backwards Compatibility
Backwards compatibility is only affected if there are developers currently handling Websocket handshakes in the `%handle-http-request` poke.
## Reference Implementation
Incoming
## Security Considerations
Similar considerations as the currently HTTP implementation.
## Copyright
Copyright and related rights waived via [CC0](../LICENSE.md).
|