UNPKG

@dainprotocol/drift-sdk

Version:

SDK for Drift Protocol

150 lines (149 loc) 5.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.WebSocketAccountSubscriber = void 0; const utils_1 = require("./utils"); class WebSocketAccountSubscriber { constructor(accountName, program, accountPublicKey, decodeBuffer, resubOpts, commitment) { var _a; this.isUnsubscribing = false; this.accountName = accountName; this.program = program; this.accountPublicKey = accountPublicKey; this.decodeBufferFn = decodeBuffer; this.resubOpts = resubOpts; if (((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.resubTimeoutMs) < 1000) { console.log('resubTimeoutMs should be at least 1000ms to avoid spamming resub'); } this.receivingData = false; this.commitment = commitment !== null && commitment !== void 0 ? commitment : this.program.provider.opts.commitment; } async subscribe(onChange) { var _a; if (this.listenerId != null || this.isUnsubscribing) { return; } this.onChange = onChange; if (!this.dataAndSlot) { await this.fetch(); } this.listenerId = this.program.provider.connection.onAccountChange(this.accountPublicKey, (accountInfo, context) => { var _a; if ((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.resubTimeoutMs) { this.receivingData = true; clearTimeout(this.timeoutId); this.handleRpcResponse(context, accountInfo); this.setTimeout(); } else { this.handleRpcResponse(context, accountInfo); } }, this.commitment); if ((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.resubTimeoutMs) { this.receivingData = true; this.setTimeout(); } } setData(data, slot) { const newSlot = slot || 0; if (this.dataAndSlot && this.dataAndSlot.slot > newSlot) { return; } this.dataAndSlot = { data, slot, }; } setTimeout() { var _a; if (!this.onChange) { throw new Error('onChange callback function must be set'); } this.timeoutId = setTimeout(async () => { var _a; if (this.isUnsubscribing) { // If we are in the process of unsubscribing, do not attempt to resubscribe return; } if (this.receivingData) { if ((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.logResubMessages) { console.log(`No ws data from ${this.accountName} in ${this.resubOpts.resubTimeoutMs}ms, resubscribing`); } await this.unsubscribe(true); this.receivingData = false; await this.subscribe(this.onChange); } }, (_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.resubTimeoutMs); } async fetch() { const rpcResponse = await this.program.provider.connection.getAccountInfoAndContext(this.accountPublicKey, this.program.provider.opts.commitment); this.handleRpcResponse(rpcResponse.context, rpcResponse === null || rpcResponse === void 0 ? void 0 : rpcResponse.value); } handleRpcResponse(context, accountInfo) { const newSlot = context.slot; let newBuffer = undefined; if (accountInfo) { newBuffer = accountInfo.data; } if (!this.bufferAndSlot) { this.bufferAndSlot = { buffer: newBuffer, slot: newSlot, }; if (newBuffer) { const account = this.decodeBuffer(newBuffer); this.dataAndSlot = { data: account, slot: newSlot, }; this.onChange(account); } return; } if (newSlot < this.bufferAndSlot.slot) { return; } const oldBuffer = this.bufferAndSlot.buffer; if (newBuffer && (!oldBuffer || !newBuffer.equals(oldBuffer))) { this.bufferAndSlot = { buffer: newBuffer, slot: newSlot, }; const account = this.decodeBuffer(newBuffer); this.dataAndSlot = { data: account, slot: newSlot, }; this.onChange(account); } } decodeBuffer(buffer) { if (this.decodeBufferFn) { return this.decodeBufferFn(buffer); } else { return this.program.account[this.accountName].coder.accounts.decode((0, utils_1.capitalize)(this.accountName), buffer); } } unsubscribe(onResub = false) { if (!onResub && this.resubOpts) { this.resubOpts.resubTimeoutMs = undefined; } this.isUnsubscribing = true; clearTimeout(this.timeoutId); this.timeoutId = undefined; if (this.listenerId != null) { const promise = this.program.provider.connection .removeAccountChangeListener(this.listenerId) .then(() => { this.listenerId = undefined; this.isUnsubscribing = false; }); return promise; } else { this.isUnsubscribing = false; } } } exports.WebSocketAccountSubscriber = WebSocketAccountSubscriber;