@skyway-sdk/rtc-api-client
Version:
The official Next Generation JavaScript SDK for SkyWay
146 lines • 6.48 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.EventJitterBuffer = exports.EventObserverImpl = void 0;
const common_1 = require("@skyway-sdk/common");
const errors_1 = require("../errors");
const util_1 = require("../util");
const log = new common_1.Logger('packages/rtc-api-client/src/infrastructure/eventObserver.ts');
class EventObserverImpl {
constructor(appId, client, channelDto, config) {
this.onEvent = new common_1.Event();
this._disposer = [];
const eventBuffer = new EventJitterBuffer(channelDto.version, (expectNextVersion) => __awaiter(this, void 0, void 0, function* () {
// ここで回復できなければシステム継続不能
yield client.subscribeChannelEvents({
appId,
channelId: channelDto.id,
offset: expectNextVersion,
});
yield new Promise((r) => setTimeout(r, config.eventSubscribeTimeout));
if (eventBuffer.packetLostHappened) {
log.error((0, util_1.createError)({
operationName: 'EventObserverImpl.eventJitterBuffer',
info: Object.assign(Object.assign({}, errors_1.errors.internalError), { detail: 'failed to resolve event lost' }),
channelId: channelDto.id,
appId,
path: log.prefix,
}));
}
}));
this._disposer = [
client.onEvent.add(({ channelId, event }) => __awaiter(this, void 0, void 0, function* () {
if (channelId === channelDto.id) {
eventBuffer.push({ event, version: event.data.channel.version });
}
})).removeListener,
eventBuffer.onEvent.add((e) => {
this.onEvent.emit(e);
}).removeListener,
];
}
dispose() {
this._disposer.forEach((d) => {
d();
});
this.onEvent.removeAllListeners();
}
}
exports.EventObserverImpl = EventObserverImpl;
/**@internal */
class EventJitterBuffer {
constructor(presentVersion, onPacketLost, packetLifetime = 1000) {
this.presentVersion = presentVersion;
this.onPacketLost = onPacketLost;
this.packetLifetime = packetLifetime;
this.onEvent = new common_1.Event();
this.eventBuffer = {};
this.packetLostHappened = false;
}
get expectNextVersion() {
return this.presentVersion + 1;
}
push(eventFrame) {
const incomingVersion = eventFrame.version;
if (incomingVersion < this.expectNextVersion) {
log.debug('duplicate event', Object.assign(Object.assign({}, eventFrame), { presentVersion: this.presentVersion }));
return;
}
if (incomingVersion > this.expectNextVersion) {
log.debug('maybe miss order event received', Object.assign(Object.assign({}, eventFrame), { presentVersion: this.presentVersion }));
this.eventBuffer[incomingVersion] = eventFrame;
this.handlePacketLifetime();
return;
}
// expected version event received
if (this.packetLostHappened) {
log.warn('event packetLost resolved', (0, util_1.createWarnPayload)({
operationName: 'EventJitterBuffer.push',
detail: 'event packetLost resolved',
payload: { eventFrame },
}));
this.packetLostHappened = false;
}
this.eventBuffer[incomingVersion] = eventFrame;
this.resolveEvents();
}
handlePacketLifetime() {
const [oldestBufferedEvent] = Object.keys(this.eventBuffer)
.sort()
.map((key) => this.eventBuffer[Number(key)]);
if (this.packetLifeTimer === undefined && oldestBufferedEvent) {
log.debug('set event packetLost timer', Object.assign(Object.assign({}, oldestBufferedEvent), { presentVersion: this.presentVersion }));
this.packetLifeTimer = setTimeout(() => __awaiter(this, void 0, void 0, function* () {
if (this.presentVersion < oldestBufferedEvent.version) {
log.warn('event packetLost', (0, util_1.createWarnPayload)({
operationName: 'EventJitterBuffer.handlePacketLifetime',
detail: 'eventPacket lost',
payload: {
oldestBufferedEvent,
eventBufferLength: Object.keys(this.eventBuffer).length,
presentVersion: this.presentVersion,
},
}));
if (this.packetLostHappened) {
return;
}
else {
this.packetLostHappened = true;
yield this.onPacketLost(this.expectNextVersion);
}
}
this.packetLifeTimer = undefined;
this.handlePacketLifetime();
}), this.packetLifetime);
}
}
resolveEvents() {
const resolve = [];
for (let i = this.expectNextVersion;; i++) {
const frame = this.eventBuffer[i];
if (frame) {
resolve.push(frame);
delete this.eventBuffer[i];
}
else {
break;
}
}
if (resolve.length > 0) {
this.presentVersion = resolve.slice(-1)[0].version;
resolve.forEach((frame) => {
this.onEvent.emit(frame.event);
});
}
}
}
exports.EventJitterBuffer = EventJitterBuffer;
//# sourceMappingURL=eventObserver.js.map