104 lines
3.2 KiB
TypeScript
104 lines
3.2 KiB
TypeScript
|
|
|
|
import { WebSocket as _WebSocket } from "./ws.js"; /*-browser*/
|
|
|
|
import { SocketProvider } from "./provider-socket.js";
|
|
|
|
import type { JsonRpcApiProviderOptions} from "./provider-jsonrpc.js";
|
|
import type { Networkish } from "./network.js";
|
|
|
|
/**
|
|
* A generic interface to a Websocket-like object.
|
|
*/
|
|
export interface WebSocketLike {
|
|
onopen: null | ((...args: Array<any>) => any);
|
|
onmessage: null | ((...args: Array<any>) => any);
|
|
onerror: null | ((...args: Array<any>) => any);
|
|
|
|
readyState: number;
|
|
|
|
send(payload: any): void;
|
|
close(code?: number, reason?: string): void;
|
|
}
|
|
|
|
/**
|
|
* A function which can be used to re-create a WebSocket connection
|
|
* on disconnect.
|
|
*/
|
|
export type WebSocketCreator = () => WebSocketLike;
|
|
|
|
/**
|
|
* A JSON-RPC provider which is backed by a WebSocket.
|
|
*
|
|
* WebSockets are often preferred because they retain a live connection
|
|
* to a server, which permits more instant access to events.
|
|
*
|
|
* However, this incurs higher server infrasturture costs, so additional
|
|
* resources may be required to host your own WebSocket nodes and many
|
|
* third-party services charge additional fees for WebSocket endpoints.
|
|
*/
|
|
export class WebSocketProvider extends SocketProvider {
|
|
#connect: null | WebSocketCreator;
|
|
|
|
#websocket: null | WebSocketLike;
|
|
get websocket(): WebSocketLike {
|
|
if (this.#websocket == null) { throw new Error("websocket closed"); }
|
|
return this.#websocket;
|
|
}
|
|
|
|
constructor(url: string | WebSocketLike | WebSocketCreator, network?: Networkish, options?: JsonRpcApiProviderOptions) {
|
|
super(network, options);
|
|
if (typeof(url) === "string") {
|
|
this.#connect = () => { return new _WebSocket(url); };
|
|
this.#websocket = this.#connect();
|
|
} else if (typeof(url) === "function") {
|
|
this.#connect = url;
|
|
this.#websocket = url();
|
|
} else {
|
|
this.#connect = null;
|
|
this.#websocket = url;
|
|
}
|
|
|
|
this.websocket.onopen = async () => {
|
|
try {
|
|
await this._start()
|
|
this.resume();
|
|
} catch (error) {
|
|
console.log("failed to start WebsocketProvider", error);
|
|
// @TODO: now what? Attempt reconnect?
|
|
}
|
|
};
|
|
|
|
this.websocket.onmessage = (message: { data: string }) => {
|
|
this._processMessage(message.data);
|
|
};
|
|
/*
|
|
this.websocket.onclose = (event) => {
|
|
// @TODO: What event.code should we reconnect on?
|
|
const reconnect = false;
|
|
if (reconnect) {
|
|
this.pause(true);
|
|
if (this.#connect) {
|
|
this.#websocket = this.#connect();
|
|
this.#websocket.onopen = ...
|
|
// @TODO: this requires the super class to rebroadcast; move it there
|
|
}
|
|
this._reconnect();
|
|
}
|
|
};
|
|
*/
|
|
}
|
|
|
|
async _write(message: string): Promise<void> {
|
|
this.websocket.send(message);
|
|
}
|
|
|
|
async destroy(): Promise<void> {
|
|
if (this.#websocket != null) {
|
|
this.#websocket.close();
|
|
this.#websocket = null;
|
|
}
|
|
super.destroy();
|
|
}
|
|
}
|