Отладка производительности

This commit is contained in:
RoyceDa
2026-03-20 22:25:33 +02:00
parent 5032d92f8e
commit f269046c46

View File

@@ -10,93 +10,80 @@ function toUint8Array(input: KeyInput): Uint8Array {
return new Uint8Array(u8.slice().buffer); return new Uint8Array(u8.slice().buffer);
} }
function buildNonce(timestamp: unknown): Uint8Array { /**
* Переиспользуемый процессор фреймов.
* Один экземпляр на sender/receiver — нет аллокаций на каждый фрейм.
*/
function createFrameProcessor(key: Uint8Array) {
// Переиспользуемые буферы — не создаём новые на каждый фрейм
const nonce = new Uint8Array(12); const nonce = new Uint8Array(12);
const ts = typeof timestamp === "number" const nonceView = new DataView(nonce.buffer);
? timestamp
: typeof timestamp === "bigint" return function processFrame(data: ArrayBuffer): ArrayBuffer {
? Number(timestamp) // Переиспользуем nonce буфер
: 0; nonce.fill(0);
new DataView(nonce.buffer).setUint32(8, ts >>> 0, false); nonceView.setUint32(8, (data.byteLength ^ (data.byteLength << 8)) >>> 0, false);
return nonce;
const input = new Uint8Array(data);
const output = chacha20(key, nonce, input);
return output.buffer as ArrayBuffer;
};
} }
function processFrame(data: ArrayBuffer, key: Uint8Array, timestamp: unknown): ArrayBuffer { function createTransform(processFrame: (data: ArrayBuffer) => ArrayBuffer) {
const nonce = buildNonce(timestamp); return new TransformStream<any, any>({
const input = new Uint8Array(data); transform(frame, controller) {
// ChaCha20 симметричный: encrypt === decrypt, тот же размер try {
const output = chacha20(key, nonce, input); const start = performance.now();
return output.buffer as ArrayBuffer; frame.data = processFrame(frame.data);
const elapsed = performance.now() - start;
if (elapsed > 1) {
console.warn(`E2EE slow frame: ${elapsed.toFixed(2)}ms`);
}
controller.enqueue(frame);
} catch (e) {
// не рвём поток — пропускаем фрейм как есть
console.error("E2EE frame failed:", e);
controller.enqueue(frame);
}
}
});
} }
export async function attachSenderE2EE(sender: RTCRtpSender, keyInput: KeyInput): Promise<void> { export async function attachSenderE2EE(sender: RTCRtpSender, keyInput: KeyInput): Promise<void> {
if (senderAttached.has(sender)) { if (senderAttached.has(sender)) return;
return;
}
senderAttached.add(sender); senderAttached.add(sender);
const key = toUint8Array(keyInput); const key = toUint8Array(keyInput);
if (key.byteLength !== 32) { if (key.byteLength !== 32) throw new Error(`E2EE key must be 32 bytes, got ${key.byteLength}`);
throw new Error(`E2EE key must be 32 bytes, got ${key.byteLength}`);
}
const anySender = sender as any; const anySender = sender as any;
if (!anySender.createEncodedStreams) { if (!anySender.createEncodedStreams) throw new Error("createEncodedStreams not available on RTCRtpSender");
throw new Error("createEncodedStreams is not available on RTCRtpSender");
}
const { readable, writable } = anySender.createEncodedStreams(); const { readable, writable } = anySender.createEncodedStreams();
const processFrame = createFrameProcessor(key);
const enc = new TransformStream<any, any>({ readable
// Синхронный transform — нет async, нет накопления очереди .pipeThrough(createTransform(processFrame))
transform(frame, controller) { .pipeTo(writable)
try { .catch((e) => console.error("Sender E2EE pipeline failed:", e));
frame.data = processFrame(frame.data, key, frame.timestamp);
controller.enqueue(frame);
} catch (e) {
console.error("Sender E2EE frame failed:", e);
controller.enqueue(frame);
}
}
});
readable.pipeThrough(enc).pipeTo(writable).catch((e) => {
console.error("Sender E2EE pipeline failed:", e);
});
} }
export async function attachReceiverE2EE(receiver: RTCRtpReceiver, keyInput: KeyInput): Promise<void> { export async function attachReceiverE2EE(receiver: RTCRtpReceiver, keyInput: KeyInput): Promise<void> {
if (receiverAttached.has(receiver)) { if (receiverAttached.has(receiver)) return;
return;
}
receiverAttached.add(receiver); receiverAttached.add(receiver);
const key = toUint8Array(keyInput); const key = toUint8Array(keyInput);
if (key.byteLength !== 32) { if (key.byteLength !== 32) throw new Error(`E2EE key must be 32 bytes, got ${key.byteLength}`);
throw new Error(`E2EE key must be 32 bytes, got ${key.byteLength}`);
}
const anyReceiver = receiver as any; const anyReceiver = receiver as any;
if (!anyReceiver.createEncodedStreams) { if (!anyReceiver.createEncodedStreams) throw new Error("createEncodedStreams not available on RTCRtpReceiver");
throw new Error("createEncodedStreams is not available on RTCRtpReceiver");
}
const { readable, writable } = anyReceiver.createEncodedStreams(); const { readable, writable } = anyReceiver.createEncodedStreams();
const processFrame = createFrameProcessor(key);
const dec = new TransformStream<any, any>({ readable
// Синхронный transform — нет async, нет накопления очереди .pipeThrough(createTransform(processFrame))
transform(frame, controller) { .pipeTo(writable)
try { .catch((e) => console.error("Receiver E2EE pipeline failed:", e));
frame.data = processFrame(frame.data, key, frame.timestamp);
controller.enqueue(frame);
} catch (e) {
console.error("Receiver E2EE frame failed:", e);
controller.enqueue(frame);
}
}
});
readable.pipeThrough(dec).pipeTo(writable).catch((e) => {
console.error("Receiver E2EE pipeline failed:", e);
});
} }