From a2cd7bb88ffb6336367f7a02836515a8a61e7005 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Sat, 11 Jul 2026 00:20:13 +0400 Subject: [PATCH] =?UTF-8?q?fix:=20close=20WS=20on=20client=20after=20last?= =?UTF-8?q?=20chunk,=20no=20DONE=20needed,=20bump=201.0.13=E2=86=921.0.14?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- site/app.py | 4 +--- site/static/app.js | 38 +++++++++++++++++++------------------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/site/app.py b/site/app.py index 0ecb451..84f31e7 100644 --- a/site/app.py +++ b/site/app.py @@ -7,7 +7,7 @@ from flask_sock import Sock app = Flask(__name__) sock = Sock(app) -VERSION = '1.0.13' +VERSION = '1.0.14' @app.route('/') @@ -29,8 +29,6 @@ def ws_upload(ws): chunk = ws.receive() if chunk is None: break - if isinstance(chunk, str) and chunk == 'DONE': - break total += len(chunk) elapsed = round((time.time() - t0) * 1000) ws.send(json.dumps({'ok': True, 'bytes': total, 'elapsed_ms': elapsed})) diff --git a/site/static/app.js b/site/static/app.js index bf9b089..7ee3478 100644 --- a/site/static/app.js +++ b/site/static/app.js @@ -200,25 +200,20 @@ async function uploadAll() { function uploadFileWS(url, f, idx) { return new Promise(function (resolve, reject) { var ws = new WebSocket(url); - var CHUNK = 64 * 1024; // 64KB chunks + var CHUNK = 64 * 1024; var offset = 0; var startTime = Date.now(); var lastProgress = 0; + var timer; ws.binaryType = 'arraybuffer'; ws.onopen = function () { - // Шлём заголовок: имя файла + размер - ws.send(JSON.stringify({ name: f.name, size: f.size })); - - // Читаем и шлём чанки var reader = new FileReader(); reader.onload = function (e) { ws.send(e.target.result); offset += CHUNK; - if (offset < f.size) { - // Прогресс каждые 10% var pct = Math.round(offset / f.size * 100); if (pct - lastProgress >= 10) { lastProgress = pct; @@ -227,41 +222,46 @@ function uploadFileWS(url, f, idx) { } readNext(); } else { - // Все чанки отправлены — шлём сигнал завершения - ws.send('DONE'); + // Все чанки ушли — закрываем, сервер поймёт что конец + f.progress = 100; + renderTable(); + ws.close(); } }; - function readNext() { var end = Math.min(offset + CHUNK, f.size); reader.readAsArrayBuffer(f.file.slice(offset, end)); } - readNext(); }; ws.onmessage = function (e) { try { var r = JSON.parse(e.data); - var elapsed = Date.now() - startTime; + clearTimeout(timer); f.progress = 100; renderTable(); ws.close(); - resolve({ bytes: r.bytes, elapsed_ms: elapsed }); + resolve({ bytes: r.bytes, elapsed_ms: Date.now() - startTime }); } catch (err) { reject(new Error('Bad response')); } }; - ws.onerror = function () { - reject(new Error('WebSocket error')); - }; + ws.onerror = function () { reject(new Error('WebSocket error')); }; - ws.onclose = function (e) { - if (e.code !== 1000 && offset < f.size) { - reject(new Error('WS closed (' + e.code + ')')); + ws.onclose = function () { + // Если файл не до конца — ошибка + if (offset < f.size) { + reject(new Error('WS closed early')); } }; + + // Таймаут на случай зависания + timer = setTimeout(function () { + ws.close(); + reject(new Error('Timeout')); + }, 300000); }); }