v0.0.58: ВМ-загрузка (паттерн ВМ-буфер+pull) — PUT на ВМ + /api/upload_refs (egress), nginx /drhider-upload/ + CORS + TTL
Deploy drhider / validate (push) Canceled after 0s
Deploy drhider / validate (push) Canceled after 0s
This commit is contained in:
+38
-24
@@ -198,6 +198,7 @@ let fileMeta = new Map(); // имя -> {size, mtime} для дедупа/суф
|
||||
let overNames = new Set(); // имена файлов сверх лимита (не участвуют в обфускации)
|
||||
const MAX_FILE_BYTES = 100 * 1024 * 1024; // 100 МБ на файл
|
||||
const MAX_SESSION_BYTES = 1024 * 1024 * 1024; // 1 ГБ суммарно
|
||||
const VM_UPLOAD_URL = 'https://contracts.kube5s.ru/drhider-upload/'; // ВМ-буфер: PUT больших файлов (шлюз кластера их рвёт)
|
||||
let currentSid = '';
|
||||
let activeES = null; // активный EventSource
|
||||
let activeXHR = null; // активный XHR
|
||||
@@ -434,23 +435,22 @@ async function uploadFiles() {
|
||||
const total = toSend.length;
|
||||
if (total === 0) { st.className = 'status error'; st.textContent = 'Нет файлов для обфускации (все превышают лимит).'; ub.disabled = false; return; }
|
||||
|
||||
// Фаза 1: загрузка (XMLHttpRequest — прогресс в строке)
|
||||
// Фаза 1: загрузка на ВМ-буфер (PUT напрямую на nginx ВМ, минуя шлюз кластера)
|
||||
const token = crypto.randomUUID();
|
||||
const refs = []; // {name, size, url} — для POST /api/upload_refs
|
||||
for (let k = 0; k < total; k++) {
|
||||
const f = toSend[k];
|
||||
const i = sendIdx[k]; // индекс в sf для вывода прогресса
|
||||
const n = k + 1;
|
||||
st.className = 'status progress';
|
||||
st.textContent = 'Загрузка (этап 1/2) ' + n + '/' + total + ': ' + f.name;
|
||||
st.textContent = 'Загрузка на ВМ (этап 1/2) ' + n + '/' + total + ': ' + f.name;
|
||||
try {
|
||||
const t0 = performance.now();
|
||||
const vmUrl = VM_UPLOAD_URL + token + '_' + k; // имя файла в URL не несём (токен-ключ)
|
||||
await new Promise((resolve, reject) => {
|
||||
const fd = new FormData();
|
||||
fd.append('files', f, f.name);
|
||||
if (currentSid) fd.append('session', currentSid);
|
||||
const url = '/api/upload?_=' + Date.now();
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', url);
|
||||
xhr.timeout = 300000; // 300с: загрузка больших файлов нестабильна через шлюз
|
||||
xhr.open('PUT', vmUrl);
|
||||
xhr.timeout = 300000; // 300с: большие файлы
|
||||
xhr.upload.onprogress = function(e) {
|
||||
if (e.lengthComputable) {
|
||||
const pct = Math.round(e.loaded / e.total * 100);
|
||||
@@ -458,35 +458,49 @@ async function uploadFiles() {
|
||||
}
|
||||
};
|
||||
xhr.onload = function() {
|
||||
if (xhr.status === 200) {
|
||||
const data = JSON.parse(xhr.responseText);
|
||||
if (data.ok) {
|
||||
const elapsed = (performance.now() - t0) / 1000;
|
||||
const speed = f.size / elapsed;
|
||||
ss(i, '<span style="color:#22c55e">✓ ' + fs(speed) + '/s</span>');
|
||||
currentSid = data.session;
|
||||
resolve();
|
||||
} else {
|
||||
reject(new Error(data.error));
|
||||
}
|
||||
if (xhr.status >= 200 && xhr.status < 300) {
|
||||
const elapsed = (performance.now() - t0) / 1000;
|
||||
const speed = f.size / elapsed;
|
||||
ss(i, '<span style="color:#22c55e">✓ ' + fs(speed) + '/s</span>');
|
||||
refs.push({ name: f.name, size: f.size, url: vmUrl });
|
||||
resolve();
|
||||
} else {
|
||||
reject(new Error('HTTP ' + xhr.status));
|
||||
reject(new Error('ВМ: HTTP ' + xhr.status));
|
||||
}
|
||||
};
|
||||
xhr.onerror = function() { reject(new Error('Сеть')); };
|
||||
xhr.ontimeout = function() { reject(new Error('Таймаут 300с')); };
|
||||
xhr.onerror = function() { reject(new Error('Сеть (ВМ)')); };
|
||||
xhr.ontimeout = function() { reject(new Error('Таймаут 300с (ВМ)')); };
|
||||
activeXHR = xhr;
|
||||
xhr.send(fd);
|
||||
xhr.send(f); // сырое тело файла
|
||||
});
|
||||
} catch (err) {
|
||||
ss(i, '<span style="color:#ef4444">✗</span>');
|
||||
st.className = 'status error';
|
||||
st.textContent = 'Ошибка загрузки: ' + err.message;
|
||||
st.textContent = 'Ошибка загрузки на ВМ: ' + err.message;
|
||||
ub.disabled = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Шаг 1b: один маленький POST во Flask со ссылками на файлы ВМ (<64КБ)
|
||||
st.className = 'status progress';
|
||||
st.textContent = 'Передача ссылок в сервис…';
|
||||
try {
|
||||
const resp = await fetch('/api/upload_refs', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ session: currentSid, files: refs })
|
||||
});
|
||||
const data = await resp.json();
|
||||
if (!data.ok) throw new Error(data.error || 'HTTP ' + resp.status);
|
||||
currentSid = data.session;
|
||||
} catch (err) {
|
||||
st.className = 'status error';
|
||||
st.textContent = 'Ошибка передачи ссылок: ' + err.message;
|
||||
ub.disabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Фаза 2: обработка (SSE — прогресс по каждому файлу)
|
||||
// Сброс загрузочных статусов — теперь этап обработки (только отправленные)
|
||||
for (let k = 0; k < total; k++) ss(sendIdx[k], '<span style="color:#2563eb">⏳</span>');
|
||||
|
||||
Reference in New Issue
Block a user