Source code

Revision control

Copy as Markdown

Other Tools

console.log(`Creating worker...`);
try {
const channels = new Map();
function getChannel(label) {
const dc = channels.get(label);
if (!dc) throw new Error(`No datachannel found for label ${label}`);
return dc;
}
function reportWorkerError(label, message) {
self.postMessage({ type: 'workerError', label, result: message });
}
function wireEvents(dc) {
const eventTypes = ['open', 'bufferedamountlow', 'error', 'closing', 'close', 'message'];
for (const type of eventTypes) {
dc.addEventListener(type, ({data, origin}) => {
if (type == 'message') {
// Events aren't transferable in general, have to reconstruct :(
self.postMessage({type, label: dc.label, result: {data, origin}});
} else {
self.postMessage({type, label: dc.label});
}
});
}
}
onmessage = ({data}) => {
const { type, label, arg } = data;
try {
switch (type) {
case 'init': {
const channel = arg;
// We do not put errors in an initResponse message; those are for
// RTCDataChannel errors only.
if (channels.has(channel.label)) {
throw new Error('Duplicate RTCDataChannel label');
}
channels.set(channel.label, channel);
wireEvents(channel);
self.postMessage({
type: 'initResponse',
label: channel.label,
result: {
label: channel.label,
ordered: channel.ordered,
maxPacketLifeTime: channel.maxPacketLifeTime,
maxRetransmits: channel.maxRetransmits,
protocol: channel.protocol,
negotiated: channel.negotiated,
id: channel.id,
readyState: channel.readyState,
bufferedAmount: channel.bufferedAmount,
binaryType: channel.binaryType,
bufferedAmountLowThreshold: channel.bufferedAmountLowThreshold,
},
});
break;
}
case 'send': {
// try block is only for RTCDataChannel errors
const channel = getChannel(label);
try {
channel.send(arg);
self.postMessage({ type: 'sendResponse', label, result: undefined });
} catch (e) {
// Man it would be nice if we could do "const error = {...} = e"
const error = { name: e.name, message: e.message };
self.postMessage({ type: 'sendResponse', label, result: { error } });
}
break;
}
case 'close': {
// RTCDataChannel.close() does not throw; any error here is ours
getChannel(label).close();
self.postMessage({ type: 'closeResponse', label, result: undefined });
break;
}
case 'setBufferedAmountLowThreshold': {
// This is fire-and-forget called by a setter, any error will be
// dealt with by the code in _errorPromise.
getChannel(label).bufferedAmountLowThreshold = arg;
break;
}
case 'setBinaryType': {
// This is fire-and-forget called by a setter
getChannel(label).binaryType = arg;
break;
}
case 'queryState': {
const channel = getChannel(label);
self.postMessage({
type: 'queryStateResponse',
label,
result: {
id: channel.id,
readyState: channel.readyState,
bufferedAmount: channel.bufferedAmount,
},
});
break;
}
default:
console.log(`Unknown type`);
reportWorkerError(label, `Received unknown message type: ${type}`);
}
} catch (err) {
console.log(`Unhandled error`);
reportWorkerError(label, `In handling ${type} request, got ${err.message}`);
}
};
} catch (e) {
console.log(`Creation failed! ${e.message}`);
}