Chat-Anhaenge: Korrekturen aus dem Code-Review

- Kamerafotos in anderen Formaten (z. B. HEIF von Android-Kameras) werden
  wie Dateien angenommen statt abgelehnt
- Dateinamen nach Zeichen kuerzen: ein halbiertes Emoji machte den Anhang
  unabrufbar (encodeURIComponent)
- Endet eine Aufnahme von selbst (Headset getrennt, Anruf), bleibt die
  Sprachnachricht erhalten statt "zu kurz"
- Kamera-App nur auf iOS/iPadOS/Android; Touch-Laptops bekommen die Kamera
  im Browser statt eines Dateidialogs
- Knapp neben dem Chat abgelegte Dateien oeffnet der Browser nicht mehr
  selbst (Portal bliebe sonst stehen); Datei-Felder bleiben Ablagen
- Fehler beim Ausliefern kommt als JSON statt mit dem Dateityp
- Server liest hoechstens 4 Uploads gleichzeitig ein (Speicher), weitere
  warten; abgebrochene Wartende geben ihren Platz frei

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Opus 5.5 committed 2026-09-26 14:01:17 +00:00
1 parent 35d98da977
commit 06e9a0fe8d
4 files changed
+57 -8

No files matched your search

+27 -1
View File
@@ -34,8 +34,34 @@ export function sanitizeMessage(doc) {
}
}
const parseRaw = express.raw({ type: 'application/octet-stream', limit: config.chat.maxFileBytes })
// Jeder Upload liegt bis zu 25 MB im Speicher: nur config.chat.maxParallelUploads gleichzeitig einlesen,
// weitere warten (ihr Body bleibt so lange ungelesen im Netzwerkpuffer)
let activeUploads = 0
const waitingUploads = []
function startWaitingUploads() {
while (activeUploads < config.chat.maxParallelUploads && waitingUploads.length) waitingUploads.shift()()
}
function uploadSlot(_req, res, next) {
let state = 'waiting'
// 'close' kommt nach der Antwort oder wenn der Browser abbricht - auch waehrend des Wartens
res.once('close', () => {
if (state === 'active') activeUploads -= 1
state = 'closed'
startWaitingUploads()
})
waitingUploads.push(() => {
if (state !== 'waiting') return // abgebrochen, bevor er dran war
state = 'active'
activeUploads += 1
next()
})
startWaitingUploads()
}
/** Chat-Anhang als rohe Bytes (Content-Type application/octet-stream), Metadaten in X-Headern. */
export const rawUpload = express.raw({ type: 'application/octet-stream', limit: config.chat.maxFileBytes })
export const rawUpload = [uploadSlot, parseRaw]
/** Fehler beim Einlesen eines Uploads verstaendlich beantworten (auch fuer den Admin-Router). */
export function uploadErrors(err, _req, res, next) {