v0.0.49: индикатор распаковки архивов, разделение фаз (загрузка/обработка), таймауты SSE на ingress 1800с
Deploy drhider / validate (push) Canceled after 0s
Deploy drhider / validate (push) Canceled after 0s
This commit is contained in:
@@ -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
@@ -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
@@ -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-блок «Идёт обработка» с тикающим таймером
|
||||
|
||||
Reference in New Issue
Block a user