hydrogen-web/src/matrix/room/sending/SendQueue.js
Bruno Windels c5b2d0c8b2 WIP
2019-06-28 00:52:54 +02:00

98 lines
2.7 KiB
JavaScript

class Sender {
constructor({hsApi}) {
this._hsApi = hsApi;
this._slotRequests = [];
this._sendScheduled = false;
this._offline = false;
this._waitTime = 0;
}
// this should really be per roomId to avoid head-of-line blocking
acquireSlot() {
let request;
const promise = new Promise((resolve) => request = {resolve});
this._slotRequests.push(request);
if (!this._sendScheduled) {
this._startNextSlot();
}
return promise;
}
async _startNextSlot() {
if (this._waitTime !== 0) {
await Platform.delay(this._waitTime);
}
const request = this._slotRequests.unshift();
this._currentSlot = new SenderSlot(this);
request.resolve(this._currentSlot);
}
_discardSlot(slot) {
if (slot === this._currentSlot) {
this._currentSlot = null;
this._sendScheduled = true;
Promise.resolve().then(() => this._startNextSlot());
}
}
async _doSend(slot, callback) {
this._sendScheduled = false;
if (slot !== this._currentSlot) {
throw new Error("slot is not active");
}
try {
// loop is left by return or throw
while(true) {
try {
return await callback(this._hsApi);
} catch (err) {
if (err instanceof HomeServerError && err.errcode === "M_LIMIT_EXCEEDED") {
await Platform.delay(err.retry_after_ms);
} else {
throw err;
}
}
}
} catch (err) {
if (err instanceof NetworkError) {
this._offline = true;
// went offline, probably want to notify SendQueues somehow
}
throw err;
} finally {
this._currentSlot = null;
if (!this._offline && this._slotRequests.length) {
this._sendScheduled = true;
Promise.resolve().then(() => this._startNextSlot());
}
}
}
}
class SenderSlot {
constructor(sender) {
this._sender = sender;
}
sendEvent(pendingEvent) {
return this._sender._doSend(this, async hsApi => {
const request = hsApi.send(
pendingEvent.roomId,
pendingEvent.eventType,
pendingEvent.txnId,
pendingEvent.content
);
const response = await request.response();
return response.event_id;
});
}
discard() {
this._sender._discardSlot(this);
}
}
export default class SendQueue {
constructor({sender})
}