p2p-media-loader-core
Version:
P2P Media Loader core functionality
151 lines • 5.31 kB
JavaScript
import * as Utils from "../utils/utils.js";
import * as Command from "./commands/index.js";
export class PeerProtocol {
constructor(connection, peerConfig, eventHandlers, eventTarget) {
Object.defineProperty(this, "connection", {
enumerable: true,
configurable: true,
writable: true,
value: connection
});
Object.defineProperty(this, "peerConfig", {
enumerable: true,
configurable: true,
writable: true,
value: peerConfig
});
Object.defineProperty(this, "eventHandlers", {
enumerable: true,
configurable: true,
writable: true,
value: eventHandlers
});
Object.defineProperty(this, "commandChunks", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "uploadingContext", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "onChunkDownloaded", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "onChunkUploaded", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "onDataReceived", {
enumerable: true,
configurable: true,
writable: true,
value: (data) => {
if (Command.isCommandChunk(data)) {
this.receivingCommandBytes(data);
}
else {
this.eventHandlers.onSegmentChunkReceived(data);
this.onChunkDownloaded(data.byteLength, "p2p", this.connection.idUtf8);
}
}
});
this.onChunkDownloaded =
eventTarget.getEventDispatcher("onChunkDownloaded");
this.onChunkUploaded = eventTarget.getEventDispatcher("onChunkUploaded");
connection.on("data", this.onDataReceived);
}
sendCommand(command) {
const binaryCommandBuffers = Command.serializePeerCommand(command, this.peerConfig.webRtcMaxMessageSize);
for (const buffer of binaryCommandBuffers) {
this.connection.write(buffer);
}
}
stopUploadingSegmentData() {
this.uploadingContext?.stopUploading();
this.uploadingContext = undefined;
}
getUploadingRequestId() {
return this.uploadingContext?.requestId;
}
async splitSegmentDataToChunksAndUploadAsync(data, requestId) {
if (this.uploadingContext) {
throw new Error(`Some segment data is already uploading.`);
}
const chunks = getBufferChunks(data, this.peerConfig.webRtcMaxMessageSize);
const { promise, resolve, reject } = Utils.getControlledPromise();
let isUploadingSegmentData = false;
const uploadingContext = {
stopUploading: () => {
isUploadingSegmentData = false;
},
requestId,
};
this.uploadingContext = uploadingContext;
const sendChunk = () => {
if (!isUploadingSegmentData) {
reject();
return;
}
while (true) {
const chunk = chunks.next().value;
if (!chunk) {
resolve();
break;
}
const drained = this.connection.write(chunk);
this.onChunkUploaded(chunk.byteLength, this.connection.idUtf8);
if (!drained)
break;
}
};
try {
this.connection.on("drain", sendChunk);
isUploadingSegmentData = true;
sendChunk();
await promise;
}
finally {
this.connection.off("drain", sendChunk);
if (this.uploadingContext === uploadingContext) {
this.uploadingContext = undefined;
}
}
}
receivingCommandBytes(buffer) {
if (!this.commandChunks) {
this.commandChunks = new Command.BinaryCommandChunksJoiner((commandBuffer) => {
this.commandChunks = undefined;
const command = Command.deserializeCommand(commandBuffer);
this.eventHandlers.onCommandReceived(command);
});
}
try {
this.commandChunks.addCommandChunk(buffer);
}
catch (err) {
if (!(err instanceof Command.BinaryCommandJoiningError))
return;
this.commandChunks = undefined;
}
}
}
function* getBufferChunks(data, maxChunkSize) {
let bytesLeft = data.byteLength;
while (bytesLeft > 0) {
const bytesToSend = bytesLeft >= maxChunkSize ? maxChunkSize : bytesLeft;
const from = data.byteLength - bytesLeft;
const buffer = data.slice(from, from + bytesToSend);
bytesLeft -= bytesToSend;
yield buffer;
}
}
//# sourceMappingURL=peer-protocol.js.map