mirror of
https://github.com/vector-im/hydrogen-web.git
synced 2024-12-26 21:15:21 +01:00
98 lines
2.7 KiB
JavaScript
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})
|
||
|
}
|