190 lines
5.6 KiB
JavaScript
Raw Permalink Normal View History

2025-04-19 15:38:48 +08:00
import { isBrowser, getLocation, getQueryString, detectEnv, appendToQueryString, } from "@walletconnect/utils";
import NetworkMonitor from "./network";
const WS = typeof global.WebSocket !== "undefined" ? global.WebSocket : require("ws");
class SocketTransport {
constructor(opts) {
this.opts = opts;
this._queue = [];
this._events = [];
this._subscriptions = [];
this._protocol = opts.protocol;
this._version = opts.version;
this._url = "";
this._netMonitor = null;
this._socket = null;
this._nextSocket = null;
this._subscriptions = opts.subscriptions || [];
this._netMonitor = opts.netMonitor || new NetworkMonitor();
if (!opts.url || typeof opts.url !== "string") {
throw new Error("Missing or invalid WebSocket url");
}
this._url = opts.url;
this._netMonitor.on("online", () => this._socketCreate());
}
set readyState(value) {
}
get readyState() {
return this._socket ? this._socket.readyState : -1;
}
set connecting(value) {
}
get connecting() {
return this.readyState === 0;
}
set connected(value) {
}
get connected() {
return this.readyState === 1;
}
set closing(value) {
}
get closing() {
return this.readyState === 2;
}
set closed(value) {
}
get closed() {
return this.readyState === 3;
}
open() {
this._socketCreate();
}
close() {
this._socketClose();
}
send(message, topic, silent) {
if (!topic || typeof topic !== "string") {
throw new Error("Missing or invalid topic field");
}
this._socketSend({
topic: topic,
type: "pub",
payload: message,
silent: !!silent,
});
}
subscribe(topic) {
this._socketSend({
topic: topic,
type: "sub",
payload: "",
silent: true,
});
}
on(event, callback) {
this._events.push({ event, callback });
}
_socketCreate() {
if (this._nextSocket) {
return;
}
const url = getWebSocketUrl(this._url, this._protocol, this._version);
this._nextSocket = new WS(url);
if (!this._nextSocket) {
throw new Error("Failed to create socket");
}
this._nextSocket.onmessage = (event) => this._socketReceive(event);
this._nextSocket.onopen = () => this._socketOpen();
this._nextSocket.onerror = (event) => this._socketError(event);
this._nextSocket.onclose = () => {
setTimeout(() => {
this._nextSocket = null;
this._socketCreate();
}, 1000);
};
}
_socketOpen() {
this._socketClose();
this._socket = this._nextSocket;
this._nextSocket = null;
this._queueSubscriptions();
this._pushQueue();
}
_socketClose() {
if (this._socket) {
this._socket.onclose = () => {
};
this._socket.close();
}
}
_socketSend(socketMessage) {
const message = JSON.stringify(socketMessage);
if (this._socket && this._socket.readyState === 1) {
this._socket.send(message);
}
else {
this._setToQueue(socketMessage);
this._socketCreate();
}
}
async _socketReceive(event) {
let socketMessage;
try {
socketMessage = JSON.parse(event.data);
}
catch (error) {
return;
}
this._socketSend({
topic: socketMessage.topic,
type: "ack",
payload: "",
silent: true,
});
if (this._socket && this._socket.readyState === 1) {
const events = this._events.filter(event => event.event === "message");
if (events && events.length) {
events.forEach(event => event.callback(socketMessage));
}
}
}
_socketError(e) {
const events = this._events.filter(event => event.event === "error");
if (events && events.length) {
events.forEach(event => event.callback(e));
}
}
_queueSubscriptions() {
const subscriptions = this._subscriptions;
subscriptions.forEach((topic) => this._queue.push({
topic: topic,
type: "sub",
payload: "",
silent: true,
}));
this._subscriptions = this.opts.subscriptions || [];
}
_setToQueue(socketMessage) {
this._queue.push(socketMessage);
}
_pushQueue() {
const queue = this._queue;
queue.forEach((socketMessage) => this._socketSend(socketMessage));
this._queue = [];
}
}
function getWebSocketUrl(_url, protocol, version) {
var _a, _b;
const url = _url.startsWith("https")
? _url.replace("https", "wss")
: _url.startsWith("http")
? _url.replace("http", "ws")
: _url;
const splitUrl = url.split("?");
const params = isBrowser()
? {
protocol,
version,
env: "browser",
host: ((_a = getLocation()) === null || _a === void 0 ? void 0 : _a.host) || "",
}
: {
protocol,
version,
env: ((_b = detectEnv()) === null || _b === void 0 ? void 0 : _b.name) || "",
};
const queryString = appendToQueryString(getQueryString(splitUrl[1] || ""), params);
return splitUrl[0] + "?" + queryString;
}
export default SocketTransport;
//# sourceMappingURL=index.js.map