// Copyright 2019-2023 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT import { invoke, Channel } from "@tauri-apps/api/core"; export interface ConnectionConfig { writeBufferSize?: number; maxWriteBufferSize?: number; maxMessageSize?: number; maxFrameSize?: number; acceptUnmaskedFrames?: boolean; headers?: HeadersInit; } export interface MessageKind { type: T; data: D; } export interface CloseFrame { code: number; reason: string; } export type Message = | MessageKind<"Text", string> | MessageKind<"Binary", number[]> | MessageKind<"Ping", number[]> | MessageKind<"Pong", number[]> | MessageKind<"Close", CloseFrame | null>; export default class WebSocket { id: number; private readonly listeners: Array<(arg: Message) => void>; constructor(id: number, listeners: Array<(arg: Message) => void>) { this.id = id; this.listeners = listeners; } static async connect( url: string, config?: ConnectionConfig, ): Promise { const listeners: Array<(arg: Message) => void> = []; const onMessage = new Channel(); onMessage.onmessage = (message: Message): void => { listeners.forEach((l) => { l(message); }); }; if (config?.headers) { config.headers = Array.from(new Headers(config.headers).entries()); } return await invoke("plugin:websocket|connect", { url, onMessage, config, }).then((id) => new WebSocket(id, listeners)); } addListener(cb: (arg: Message) => void): void { this.listeners.push(cb); } async send(message: Message | string | number[]): Promise { let m: Message; if (typeof message === "string") { m = { type: "Text", data: message }; } else if (typeof message === "object" && "type" in message) { m = message; } else if (Array.isArray(message)) { m = { type: "Binary", data: message }; } else { throw new Error( "invalid `message` type, expected a `{ type: string, data: any }` object, a string or a numeric array", ); } await invoke("plugin:websocket|send", { id: this.id, message: m, }); } async disconnect(): Promise { await this.send({ type: "Close", data: { code: 1000, reason: "Disconnected by client", }, }); } }