diff options
Diffstat (limited to 'compat/lustre_websocket/src/lustre_websocket.gleam')
-rw-r--r-- | compat/lustre_websocket/src/lustre_websocket.gleam | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/compat/lustre_websocket/src/lustre_websocket.gleam b/compat/lustre_websocket/src/lustre_websocket.gleam new file mode 100644 index 0000000..ce46a4a --- /dev/null +++ b/compat/lustre_websocket/src/lustre_websocket.gleam @@ -0,0 +1,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" |