@drift-labs/sdk-browser
Version:
SDK for Drift Protocol
121 lines (120 loc) • 5.03 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebSocketProgramAccountSubscriber = void 0;
class WebSocketProgramAccountSubscriber {
constructor(subscriptionName, accountDiscriminator, program, decodeBufferFn, options = {
filters: [],
}, resubOpts) {
var _a;
this.bufferAndSlotMap = new Map();
this.isUnsubscribing = false;
this.receivingData = false;
this.subscriptionName = subscriptionName;
this.accountDiscriminator = accountDiscriminator;
this.program = program;
this.decodeBuffer = decodeBufferFn;
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.options = options;
this.receivingData = false;
}
async subscribe(onChange) {
var _a, _b;
if (this.listenerId != null || this.isUnsubscribing) {
return;
}
this.onChange = onChange;
this.listenerId = this.program.provider.connection.onProgramAccountChange(this.program.programId, (keyedAccountInfo, context) => {
var _a;
if ((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.resubTimeoutMs) {
this.receivingData = true;
clearTimeout(this.timeoutId);
this.handleRpcResponse(context, keyedAccountInfo);
this.setTimeout();
}
else {
this.handleRpcResponse(context, keyedAccountInfo);
}
}, (_a = this.options.commitment) !== null && _a !== void 0 ? _a : this.program.provider.opts.commitment, this.options.filters);
if ((_b = this.resubOpts) === null || _b === void 0 ? void 0 : _b.resubTimeoutMs) {
this.receivingData = true;
this.setTimeout();
}
}
setTimeout() {
var _a;
if (!this.onChange) {
throw new Error('onChange callback function must be set');
}
this.timeoutId = setTimeout(async () => {
var _a, _b;
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.subscriptionName} in ${(_b = this.resubOpts) === null || _b === void 0 ? void 0 : _b.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);
}
handleRpcResponse(context, keyedAccountInfo) {
const newSlot = context.slot;
let newBuffer = undefined;
if (keyedAccountInfo) {
newBuffer = keyedAccountInfo.accountInfo.data;
}
const accountId = keyedAccountInfo.accountId.toBase58();
const existingBufferAndSlot = this.bufferAndSlotMap.get(accountId);
if (!existingBufferAndSlot) {
if (newBuffer) {
this.bufferAndSlotMap.set(accountId, {
buffer: newBuffer,
slot: newSlot,
});
const account = this.decodeBuffer(this.accountDiscriminator, newBuffer);
this.onChange(keyedAccountInfo.accountId, account, context, newBuffer);
}
return;
}
if (newSlot < existingBufferAndSlot.slot) {
return;
}
const oldBuffer = existingBufferAndSlot.buffer;
if (newBuffer && (!oldBuffer || !newBuffer.equals(oldBuffer))) {
this.bufferAndSlotMap.set(accountId, {
buffer: newBuffer,
slot: newSlot,
});
const account = this.decodeBuffer(this.accountDiscriminator, newBuffer);
this.onChange(keyedAccountInfo.accountId, account, context, newBuffer);
}
}
unsubscribe(onResub = false) {
if (!onResub) {
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.WebSocketProgramAccountSubscriber = WebSocketProgramAccountSubscriber;