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
|
import lustre/effect.{Effect}
pub type WebSocket
pub type WebSocketCloseReason {
// 1000
Normal
// 1001
GoingAway
// 1002
ProtocolError
// 1003
UnexpectedTypeOfData
// 1004 Reserved
// 1005
NoCodeFromServer
// 1006, no close frame
AbnormalClose
// 1007
IncomprehensibleFrame
// 1008
PolicyViolated
// 1009
MessageTooBig
// 1010
FailedExtensionNegotation
// 1011
UnexpectedFailure
// 1015
FailedTLSHandshake
}
pub type WebSocketEvent {
OnOpen(WebSocket)
OnMessage(String)
OnClose(WebSocketCloseReason)
}
/// Initialize a websocket. These constructs are fully asynchronous, so you must provide a wrapper
/// that takes a `WebSocketEvent` and turns it into a lustre message of your application.
pub fn init(path: String, wrapper: fn(WebSocketEvent) -> a) -> Effect(a) {
let ws = do_init(path)
use dispatch <- effect.from
let on_open = fn() { dispatch(wrapper(OnOpen(ws))) }
let on_message = fn(in_msg) { dispatch(wrapper(OnMessage(in_msg))) }
let on_close = fn(code) {
case code {
1000 -> dispatch(wrapper(OnClose(Normal)))
1001 -> dispatch(wrapper(OnClose(GoingAway)))
1002 -> dispatch(wrapper(OnClose(ProtocolError)))
1003 -> dispatch(wrapper(OnClose(UnexpectedTypeOfData)))
1005 -> dispatch(wrapper(OnClose(NoCodeFromServer)))
1006 -> dispatch(wrapper(OnClose(AbnormalClose)))
1007 -> dispatch(wrapper(OnClose(IncomprehensibleFrame)))
1008 -> dispatch(wrapper(OnClose(PolicyViolated)))
1009 -> dispatch(wrapper(OnClose(MessageTooBig)))
1010 -> dispatch(wrapper(OnClose(FailedExtensionNegotation)))
1011 -> dispatch(wrapper(OnClose(UnexpectedFailure)))
1015 -> dispatch(wrapper(OnClose(FailedTLSHandshake)))
}
}
do_register(ws, on_open, on_message, on_close)
}
external fn do_init(path) -> WebSocket =
"./ffi.mjs" "init_websocket"
external fn do_register(
ws: WebSocket,
on_open: fn() -> Nil,
on_message: fn(String) -> Nil,
on_close: fn(Int) -> Nil,
) -> Nil =
"./ffi.mjs" "register_websocket_handler"
/// Send a text message over the web socket. This is asynchronous. There is no
/// expectation of a reply. See `init`. Only works on an Non-Closed socket.
/// Returns a `Effect(a)` that you must pass as second entry in the lustre `update` return.
pub fn send(ws: WebSocket, msg: String) -> Effect(a) {
effect.from(fn(_) { do_send(ws, msg) })
}
external fn do_send(ws: WebSocket, msg: String) -> Nil =
"./ffi.mjs" "send_over_websocket"
|