guter zwischenstand

This commit is contained in:
2026-03-14 16:23:35 +01:00
parent 5bb0d345da
commit 1a4a22eafd
28 changed files with 1486 additions and 1231 deletions

View File

@@ -1,6 +1,11 @@
import { FRAME, DATA, ZEPHYR_ERRORS } from './constants';
import { protocolInfo, fsInfo } from '../store';
import { protocolInfo, fsInfo, transferStats, resetTransferStats, transferDetails } from '../store';
import { addToast } from '../toast';
import { SETTINGS } from '../settings';
import { crc32 } from './crc32';
let lastUiUpdate = 0;
let currentFileCrc32 = 0;
export type FrameSender = (buffer: ArrayBuffer) => Promise<void>;
@@ -90,30 +95,42 @@ export function parseIncomingFrame(view: DataView, sender: FrameSender) {
break;
case FRAME.FILE_START:
fileTransfer.totalBytes = view.getUint32(3, true);
currentFileCrc32 = 0;
const totalBytes = view.getUint32(3, true);
const nowStart = performance.now();
transferStats.update(s => ({
...s,
bytesTotal: totalBytes,
bytesDone: 0,
currentFileName: s.pendingFileName || s.currentFileName,
fileStartTime: nowStart,
bulkStartTime: s.bulkStartTime === 0 ? nowStart : s.bulkStartTime
}));
// Parser-interne Metriken (Watchdog etc.)
fileTransfer.totalBytes = totalBytes;
fileTransfer.receivedBytes = 0;
fileTransfer.lastReceivedBytes = 0;
fileTransfer.stalledSeconds = 0;
fileTransfer.active = true;
fileTransfer.startTime = performance.now();
fileTransfer.startTime = nowStart;
lastUiUpdate = 0;
console.log(`[FILE_GET] Stream gestartet. Erwartete Größe: ${fileTransfer.totalBytes} Bytes.`);
fileTransfer.metricsTimer = setInterval(() => {
if (!fileTransfer.active) return;
// Watchdog-Logik: Prüfen ob seit der letzten Sekunde Daten kamen
if (fileTransfer.receivedBytes === fileTransfer.lastReceivedBytes) {
fileTransfer.stalledSeconds++;
if (fileTransfer.stalledSeconds >= 5) { // 5 Sekunden Timeout
console.warn("[FILE_GET] Übertragung abgebrochen: Timeout (Keine Daten empfangen).");
if (fileTransfer.metricsTimer) clearInterval(fileTransfer.metricsTimer);
fileTransfer.active = false;
// Hier optional einen Toast anzeigen lassen, falls importiert:
// addToast("Dateitransfer abgebrochen (Timeout)", "error");
addToast("Dateitransfer abgebrochen (Timeout)", "error");
if (fileGetReject) {
fileGetReject(new Error("Timeout beim Dateitransfer"));
@@ -123,18 +140,9 @@ case FRAME.FILE_START:
return;
}
} else {
// Daten fließen -> Watchdog zurücksetzen
fileTransfer.stalledSeconds = 0;
fileTransfer.lastReceivedBytes = fileTransfer.receivedBytes;
}
const elapsedSec = (performance.now() - fileTransfer.startTime) / 1000;
const speedKB = (fileTransfer.receivedBytes / 1024) / elapsedSec;
const percent = fileTransfer.totalBytes > 0
? ((fileTransfer.receivedBytes / fileTransfer.totalBytes) * 100).toFixed(1)
: "0.0";
console.log(`[FILE_GET] Fortschritt: ${percent}% | Speed: ${speedKB.toFixed(2)} KB/s`);
}, 1000);
// Initiale Credits (z.B. 64)
@@ -145,32 +153,61 @@ case FRAME.FILE_START:
case FRAME.FILE_CHUNK:
if (!fileTransfer.active) break;
const chunkData = new Uint8Array(view.buffer, 3, payloadLength);
currentFileCrc32 = crc32(chunkData, currentFileCrc32);
const previousReceived = fileTransfer.receivedBytes;
fileTransfer.receivedBytes += payloadLength;
fileTransfer.credits--;
// Nachladen, sobald die Credits auf 32 fallen (Dein Vorschlag)
const nowChunk = performance.now();
if (nowChunk - lastUiUpdate > SETTINGS.ui.transferUpdateIntervalMs) {
const delta = fileTransfer.receivedBytes - previousReceived; // Das Delta seit dem letzten Paket
transferStats.update(s => ({
...s,
bytesDone: fileTransfer.receivedBytes,
overallDone: s.overallDone + (fileTransfer.receivedBytes - s.bytesDone)
}));
console.log("[FILE_GET] Fortschritt: " + ((fileTransfer.receivedBytes / fileTransfer.totalBytes) * 100).toFixed(2) + "%");
lastUiUpdate = nowChunk;
}
if (fileTransfer.credits <= 64) {
fileTransfer.credits = 128;
sendCredits(fileTransfer.credits, sender);
}
break;
case FRAME.FILE_END:
if (fileTransfer.metricsTimer) {
clearInterval(fileTransfer.metricsTimer);
fileTransfer.metricsTimer = null;
}
transferStats.update(s => {
return {
...s,
bytesDone: s.bytesTotal,
};
});
// Watchdog stoppen
if (fileTransfer.metricsTimer) clearInterval(fileTransfer.metricsTimer);
fileTransfer.active = false;
const buzzerCrc32 = view.getUint32(3, true);
const crc32 = view.getUint32(3, true);
console.log(`[CRC] Lokal: 0x${currentFileCrc32.toString(16).toUpperCase()}`);
console.log(`[CRC] Buzzer: 0x${buzzerCrc32.toString(16).toUpperCase()}`);
const totalElapsed = (performance.now() - fileTransfer.startTime) / 1000;
const avgSpeed = (fileTransfer.receivedBytes / 1024) / totalElapsed;
console.log(`[FILE_GET] Stream beendet.`);
console.log(`[FILE_GET] Empfangen: ${fileTransfer.receivedBytes} Bytes in ${totalElapsed.toFixed(2)}s.`);
console.log(`[FILE_GET] Durchschnitt: ${avgSpeed.toFixed(2)} KB/s`);
console.log(`[FILE_GET] Zephyr CRC32: 0x${crc32.toString(16).toUpperCase().padStart(8, '0')}`);
if (currentFileCrc32 === buzzerCrc32) {
console.log("%c[CRC] Match! Datei ist integer.", "color: green; font-weight: bold;");
} else {
console.error("[CRC] Mismatch! Datei beschädigt.");
addToast("CRC Fehler: Datei wurde fehlerhaft übertragen.", "error");
if (fileGetReject) fileGetReject(new Error("CRC Mismatch"));
break;
}
if (fileGetResolve) {
fileGetResolve(true);
@@ -281,8 +318,8 @@ const fileTransfer = {
startTime: 0,
totalBytes: 0,
receivedBytes: 0,
lastReceivedBytes: 0, // NEU: Für die Timeout-Berechnung
stalledSeconds: 0, // NEU: Zähler für Stillstand
lastReceivedBytes: 0,
stalledSeconds: 0,
credits: 0,
metricsTimer: null as ReturnType<typeof setInterval> | null
};
@@ -301,7 +338,7 @@ export function buildFileGetRequest(path: string): ArrayBuffer {
view.setUint8(0, FRAME.REQUEST);
view.setUint16(1, 1 + pathBytes.length, true);
view.setUint8(3, DATA.FILE_GET);
const uint8Buffer = new Uint8Array(buffer);
uint8Buffer.set(pathBytes, 4);