v0.0.49: индикатор распаковки архивов, разделение фаз (загрузка/обработка), таймауты SSE на ingress 1800с
Deploy drhider / validate (push) Canceled after 0s

This commit is contained in:
“Naeel”
2026-08-19 18:49:55 +04:00
parent 4bdcde86b7
commit 7389e1009a
3 changed files with 68 additions and 13 deletions
+39
View File
@@ -0,0 +1,39 @@
# v0.0.49 — индикатор распаковки, разделение фаз, таймауты SSE — 2026-08-19
**Дата:** 2026-08-19
**Версия:** 0.0.48 → 0.0.49
---
## Контекст
Отзыв тестировщика:
1. «После Выбрать файлы долго не респондит — разбирает архивы» → нет индикатора.
2. «По Обфусцировать — двойной проход по файлам» → фазы загрузки и обработки не разделены.
3. «Ошибка: SSE connection failed» → долгое SSE рвалось шлюзом.
## Изменения
### Ingress (kubectl patch, не код)
- `proxy-read-timeout: 600 → 1800`
- `proxy-send-timeout: 600 → 1800`
— шлюз больше не рвёт долгое SSE (было ~10 мин, стало 30 мин).
### `site/templates/index.html`
- **Индикатор распаковки**: при выборе файлов с `.zip``cursor: wait` +
статус «Разбираю архивы…», снимается после распаковки (try/finally).
- **Разделение фаз**:
- Фаза 1: статус «Загрузка (этап 1/2) i/N: имя».
- Фаза 2: статус «Обработка (этап 2/2)…», таймер «Обработка (этап 2/2)… Nс».
- При старте фазы 2 загрузочные статусы сбрасываются на «⏳».
### `site/app.py`
- `VERSION = "0.0.49"`.
## Проверка
- `node --check`, `py_compile` — OK.
- Тесты builder/replacer/scanner/zip — все зелёные.
## Примечание
- Причина «SSE connection failed»: шлюз рвал долгое SSE (proxy-read-timeout 600с).
Таймауты подняты до 1800с. Если обработка > 30 мин — нужно ещё выше или
авто-реконнект EventSource (отложено: реконнект вызывает повторную обработку).
+1 -1
View File
@@ -20,7 +20,7 @@ if _sys_path_root not in sys.path:
sys.path.insert(0, _sys_path_root)
# Версия приложения (меняется при изменениях)
VERSION = "0.0.48"
VERSION = "0.0.49"
def create_app():
+28 -12
View File
@@ -343,16 +343,31 @@ function addFileWithDedup(file) {
fi.addEventListener('change', async () => {
const incoming = Array.from(fi.files);
for (const f of incoming) {
if (f.name.toLowerCase().endsWith('.zip')) {
try {
const nested = await listZipFiles(f);
nested.forEach(x => addFileWithDedup(x));
} catch (err) {
addFileWithDedup(f); // не удалось распаковать — добавить zip как есть
const hasZip = incoming.some(f => f.name.toLowerCase().endsWith('.zip'));
if (hasZip) {
// Распаковка архивов может занять время — показать индикатор
document.body.style.cursor = 'wait';
st.className = 'status progress';
st.textContent = 'Разбираю архивы…';
}
try {
for (const f of incoming) {
if (f.name.toLowerCase().endsWith('.zip')) {
try {
const nested = await listZipFiles(f);
nested.forEach(x => addFileWithDedup(x));
} catch (err) {
addFileWithDedup(f); // не удалось распаковать — добавить zip как есть
}
} else {
addFileWithDedup(f);
}
} else {
addFileWithDedup(f);
}
} finally {
if (hasZip) {
document.body.style.cursor = '';
st.className = '';
st.textContent = '';
}
}
const d = new DataTransfer();
@@ -383,7 +398,7 @@ async function uploadFiles() {
for (let i = 0; i < total; i++) {
const f = files[i], n = i + 1;
st.className = 'status progress';
st.textContent = 'Загрузка ' + n + '/' + total + ': ' + f.name;
st.textContent = 'Загрузка (этап 1/2) ' + n + '/' + total + ': ' + f.name;
try {
const t0 = performance.now();
await new Promise((resolve, reject) => {
@@ -431,15 +446,16 @@ async function uploadFiles() {
}
// Фаза 2: обработка (SSE — прогресс по каждому файлу)
// Сброс загрузочных статусов — теперь этап обработки
for (let i = 0; i < total; i++) ss(i, '<span style="color:#2563eb">⏳</span>');
const fileTimers = {}; // idx -> performance.now()
const fileIntervals = {}; // idx -> setInterval id
st.className = 'status progress';
st.textContent = 'Обработка...';
st.textContent = 'Обработка (этап 2/2)…';
const t0 = performance.now();
const ptimer = setInterval(() => {
const sec = Math.round((performance.now() - t0) / 1000);
st.textContent = 'Обработка... ' + sec + 'с';
st.textContent = 'Обработка (этап 2/2)… ' + sec + 'с';
}, 1000);
// Крупный live-блок «Идёт обработка» с тикающим таймером