Redesign the desktop workspace with task sidebars, live filters, clearer settings, and an accessible update dialog. Harden encrypted backup imports, configuration persistence, history retention, queue snapshots, shutdown recovery, and update installation ordering. Publish verified Windows artifacts and refreshed English documentation.
44 lines
1.1 KiB
JavaScript
44 lines
1.1 KiB
JavaScript
/**
|
|
* Token-bucket speed limiter for bandwidth throttling.
|
|
* maxBytesPerSec = 0 means unlimited (passthrough).
|
|
*/
|
|
class Throttle {
|
|
constructor(maxBytesPerSec) {
|
|
this.maxBps = maxBytesPerSec || 0;
|
|
this.tokens = this.maxBps;
|
|
this.lastRefill = Date.now();
|
|
}
|
|
|
|
async consume(bytes, signal) {
|
|
if (this.maxBps <= 0) return; // unlimited
|
|
|
|
while (bytes > 0) {
|
|
if (signal && signal.aborted) return;
|
|
this._refill();
|
|
const available = Math.min(bytes, Math.floor(this.tokens));
|
|
if (available > 0) {
|
|
this.tokens -= available;
|
|
bytes -= available;
|
|
}
|
|
if (bytes > 0) {
|
|
if (signal && signal.aborted) return;
|
|
// Wait 50ms for tokens to refill
|
|
await new Promise((r) => setTimeout(r, 50));
|
|
}
|
|
}
|
|
}
|
|
|
|
_refill() {
|
|
const now = Date.now();
|
|
const elapsed = (now - this.lastRefill) / 1000;
|
|
this.tokens = Math.min(this.maxBps, this.tokens + elapsed * this.maxBps);
|
|
this.lastRefill = now;
|
|
}
|
|
|
|
updateRate(maxBytesPerSec) {
|
|
this.maxBps = maxBytesPerSec || 0;
|
|
}
|
|
}
|
|
|
|
module.exports = Throttle;
|