sfccxt
Version:
A JavaScript / Python / PHP cryptocurrency trading library with support for 130+ exchanges
79 lines (70 loc) • 2.47 kB
JavaScript
"use strict";
/* ------------------------------------------------------------------------ */
const { now, sleep } = require ('./time');
/* ------------------------------------------------------------------------ */
class Throttle {
constructor (config) {
this.config = {
refillRate: 1.0,
delay: 0.001,
capacity: 1.0,
maxCapacity: 2000,
tokens: 0,
cost: 1.0,
};
Object.assign (this.config, config);
this.queue = [];
this.running = false;
}
async loop () {
let lastTimestamp = now ();
while (this.running) {
const { resolver, cost } = this.queue[0];
if (this.config['tokens'] >= 0) {
this.config['tokens'] -= cost;
resolver ();
this.queue.shift ();
// contextswitch
await Promise.resolve ();
if (this.queue.length === 0) {
this.running = false;
}
} else {
await sleep (this.config['delay'] * 1000);
const current = now ();
const elapsed = current - lastTimestamp;
lastTimestamp = current;
const tokens = this.config['tokens'] + (this.config['refillRate'] * elapsed);
this.config['tokens'] = Math.min (tokens, this.config['capacity']);
}
}
}
}
function throttle (config) {
function inner (cost = undefined) {
let resolver;
const promise = new Promise ((resolve, reject) => {
resolver = resolve;
});
if (this.queue.length > this.config['maxCapacity']) {
throw new Error ('throttle queue is over maxCapacity (' + this.config['maxCapacity'].toString () + '), see https://github.com/ccxt/ccxt/issues/11645#issuecomment-1195695526');
}
cost = (cost === undefined) ? this.config['cost'] : cost;
this.queue.push ({ resolver, cost });
if (!this.running) {
this.running = true;
this.loop ();
}
return promise;
}
const instance = new Throttle (config);
const bound = inner.bind (instance);
// useful for inspecting the tokenBucket
bound.config = instance.config;
bound.queue = instance.queue;
return bound;
}
module.exports = {
throttle,
};
// ----------------------------------------