Current section
Files
Jump to
Current section
Files
src/gossamer/web_socket.ffi.mjs
// src/gossamer/web_socket.ffi.ts
import * as $webSocket from "./web_socket.mjs";
import { BitArray$BitArray, Result$Error, Result$Ok } from "../../prelude.mjs";
import { toBufferSource } from "../utils/bit_array.ffi.mjs";
import { toArray } from "../utils/list.ffi.mjs";
import { mapIfSome } from "../utils/option.ffi.mjs";
function isValidWebSocketUrl(url) {
let parsed;
try {
parsed = new URL(url);
} catch {
return false;
}
const allowedSchemes = ["ws:", "wss:", "http:", "https:"];
if (!allowedSchemes.includes(parsed.protocol)) return false;
if (parsed.hash !== "") return false;
return true;
}
function toCloseEvent(event) {
return $webSocket.CloseEvent$CloseEvent(
event.code,
event.reason,
event.wasClean
);
}
function toMessageEvent(data) {
if (typeof data === "string") {
return $webSocket.WebSocketEvent$Text(data);
}
if (data instanceof ArrayBuffer) {
return $webSocket.WebSocketEvent$Binary(
BitArray$BitArray(new Uint8Array(data))
);
}
throw new Error(
'gossamer.web_socket: the runtime delivered a binary message that is not an ArrayBuffer despite binaryType being pinned to "arraybuffer". Please file an issue at https://github.com/han-tyumi/gossamer/issues.'
);
}
function toReadyState(value) {
switch (value) {
case 0:
return $webSocket.ReadyState$Connecting();
case 1:
return $webSocket.ReadyState$Open();
case 2:
return $webSocket.ReadyState$Closing();
case 3:
return $webSocket.ReadyState$Closed();
default:
return $webSocket.ReadyState$Closed();
}
}
var build = (url, protocolsList, on_event) => {
if (!isValidWebSocketUrl(url)) {
return Result$Error($webSocket.WebSocketError$InvalidUrl());
}
const protocols = toArray(protocolsList);
let ws;
try {
ws = new WebSocket(url, protocols);
} catch {
return Result$Error($webSocket.WebSocketError$InvalidProtocols());
}
ws.binaryType = "arraybuffer";
mapIfSome(ws, "onopen", on_event, (handler) => () => {
handler($webSocket.WebSocketEvent$Opened(), ws);
});
mapIfSome(ws, "onmessage", on_event, (handler) => (event) => {
handler(toMessageEvent(event.data), ws);
});
mapIfSome(ws, "onerror", on_event, (handler) => () => {
handler($webSocket.WebSocketEvent$Errored(), ws);
});
mapIfSome(ws, "onclose", on_event, (handler) => (event) => {
handler($webSocket.WebSocketEvent$Disconnected(toCloseEvent(event)), ws);
});
return Result$Ok(ws);
};
var info = (socket) => {
return $webSocket.Info$Info(
socket.url,
socket.protocol,
socket.extensions
);
};
var ready_state = (socket) => {
return toReadyState(socket.readyState);
};
var buffered_amount = (socket) => {
return socket.bufferedAmount;
};
var close = (socket) => {
socket.close();
};
var utf8 = new TextEncoder();
var close_with = (socket, code, reason) => {
if (code !== 1e3 && (code < 3e3 || code > 4999)) {
return Result$Error($webSocket.WebSocketError$InvalidCloseCode(code));
}
if (utf8.encode(reason).length > 123) {
return Result$Error($webSocket.WebSocketError$CloseReasonTooLong());
}
socket.close(code, reason);
return Result$Ok(void 0);
};
function checkOpen() {
return Result$Error($webSocket.WebSocketError$NotOpen());
}
var send_blob = (socket, data) => {
if (socket.readyState === WebSocket.CONNECTING) return checkOpen();
socket.send(data);
return Result$Ok(void 0);
};
var send_binary = (socket, data) => {
if (socket.readyState === WebSocket.CONNECTING) return checkOpen();
socket.send(toBufferSource(data));
return Result$Ok(void 0);
};
var send_text = (socket, data) => {
if (socket.readyState === WebSocket.CONNECTING) return checkOpen();
socket.send(data);
return Result$Ok(void 0);
};
export {
buffered_amount,
build,
close,
close_with,
info,
ready_state,
send_binary,
send_blob,
send_text
};