@skyway-sdk/core
Version:
The official Next Generation JavaScript SDK for SkyWay
131 lines • 4.68 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RemoteDataStream = exports.remoteDataStreamMessageBufferMaxSize = void 0;
const common_1 = require("@skyway-sdk/common");
const util_1 = require("../../../util");
const data_1 = require("../local/data");
const base_1 = require("./base");
const log = new common_1.Logger('packages/core/src/media/stream/remote/data.ts');
const textEncoder = new TextEncoder();
/**@internal */
exports.remoteDataStreamMessageBufferMaxSize = 10 * 1024 * 1024;
class RemoteDataStream extends base_1.RemoteStreamBase {
/**@internal */
constructor(id,
/**@internal */
_datachannel) {
super(id, 'data');
this._datachannel = _datachannel;
this._isEnabled = true;
this._bufferingUntilFirstListener = true;
this._bufferedMessages = [];
this._bufferedMessageSize = 0;
this._hasWarnedBufferOverflow = false;
this.contentType = 'data';
this.onData = new common_1.Event(() => {
this._queueFlushBufferedMessages();
});
_datachannel.onmessage = ({ data }) => {
if (!this._isEnabled) {
return;
}
const parsed = this._parseMessage(data);
if (this._bufferingUntilFirstListener) {
this._bufferIncomingMessage(parsed);
return;
}
this.onData.emit(parsed);
};
_datachannel.onclose = () => {
this._clearBufferedMessages();
};
}
/**@internal */
setIsEnabled(b) {
this._isEnabled = b;
if (!b) {
// Streamが無効化された場合はバッファリングしているデータを破棄する
this._clearBufferedMessages();
}
}
_parseMessage(data) {
if (typeof data === 'string' && data.startsWith(data_1.objectFlag)) {
try {
return JSON.parse(data.slice(data_1.objectFlag.length));
}
catch (_a) {
return data;
}
}
return data;
}
_bufferIncomingMessage(data) {
const size = this._estimateMessageSize(data);
if (this._bufferedMessageSize + size >
exports.remoteDataStreamMessageBufferMaxSize) {
if (!this._hasWarnedBufferOverflow) {
log.warn((0, util_1.createWarnPayload)({
operationName: 'RemoteDataStream._bufferIncomingMessage',
detail: 'remote data stream receive buffer overflowed before onData listener was set; dropping newly received data',
payload: {
streamId: this.id,
bufferSize: this._bufferedMessageSize,
incomingDataSize: size,
maxBufferSize: exports.remoteDataStreamMessageBufferMaxSize,
},
}));
this._hasWarnedBufferOverflow = true;
}
return;
}
this._bufferedMessages.push(data);
this._bufferedMessageSize += size;
}
_flushBufferedMessages() {
if (!this._bufferingUntilFirstListener || this.onData.length === 0) {
return;
}
this._bufferingUntilFirstListener = false;
const bufferedMessages = this._bufferedMessages;
this._bufferedMessages = [];
this._bufferedMessageSize = 0;
this._hasWarnedBufferOverflow = false;
// 無効なStreamのデータはユーザに渡さない
if (!this._isEnabled) {
return;
}
bufferedMessages.forEach((data) => {
this.onData.emit(data);
});
}
_clearBufferedMessages() {
this._bufferedMessages = [];
this._bufferedMessageSize = 0;
this._hasWarnedBufferOverflow = false;
}
_estimateMessageSize(data) {
if (typeof data === 'string') {
return textEncoder.encode(data).byteLength;
}
if (data instanceof Blob) {
return data.size;
}
if (data instanceof ArrayBuffer) {
return data.byteLength;
}
if (ArrayBuffer.isView(data)) {
return data.byteLength;
}
return textEncoder.encode(JSON.stringify(data)).byteLength;
}
_queueFlushBufferedMessages() {
if (!this._bufferingUntilFirstListener || this.onData.length === 0) {
return;
}
queueMicrotask(() => {
this._flushBufferedMessages();
});
}
}
exports.RemoteDataStream = RemoteDataStream;
//# sourceMappingURL=data.js.map