79 lines
2.8 KiB
JavaScript
79 lines
2.8 KiB
JavaScript
/**
|
||
* putToVm — отправка одного файла в буфер методом HTTP PUT (сырое бинарное тело).
|
||
*
|
||
* @param {Blob|File} file Файл для отправки.
|
||
* @param {string} url Полный целевой URL в буфере.
|
||
* @param {Object} options Опции отправки:
|
||
* @param {function(number, number, number): void} [options.onProgress] Колбэк прогресса (pct, loaded, total).
|
||
* @param {function(XMLHttpRequest): void} [options.onXHR] Колбэк регистрации XHR для прямого контроля.
|
||
* @param {AbortSignal} [options.signal] Сигнал прерывания запроса (AbortController.signal).
|
||
* @param {number} [options.timeoutMs=300000] Таймаут в миллисекундах (по умолчанию 300с).
|
||
* @returns {Promise<void>} Разрешается при ответе 2xx, отклоняется при ошибке или прерывании.
|
||
*/
|
||
export function putToVm(file, url, options = {}) {
|
||
return new Promise((resolve, reject) => {
|
||
const xhr = new XMLHttpRequest();
|
||
|
||
if (options.onXHR) {
|
||
options.onXHR(xhr);
|
||
}
|
||
|
||
const abortHandler = () => {
|
||
xhr.abort();
|
||
reject(new DOMException('Upload aborted', 'AbortError'));
|
||
};
|
||
|
||
if (options.signal) {
|
||
if (options.signal.aborted) {
|
||
reject(new DOMException('Upload aborted', 'AbortError'));
|
||
return;
|
||
}
|
||
options.signal.addEventListener('abort', abortHandler, { once: true });
|
||
}
|
||
|
||
xhr.open('PUT', url);
|
||
xhr.timeout = options.timeoutMs || 300000;
|
||
|
||
xhr.upload.onprogress = (e) => {
|
||
if (e.lengthComputable && options.onProgress) {
|
||
const pct = Math.round((e.loaded / e.total) * 100);
|
||
options.onProgress(pct, e.loaded, e.total);
|
||
}
|
||
};
|
||
|
||
xhr.onload = () => {
|
||
if (options.signal) {
|
||
options.signal.removeEventListener('abort', abortHandler);
|
||
}
|
||
if (xhr.status >= 200 && xhr.status < 300) {
|
||
resolve();
|
||
} else {
|
||
reject(new Error(`Буфер: HTTP ${xhr.status} ${xhr.statusText}`));
|
||
}
|
||
};
|
||
|
||
xhr.onerror = () => {
|
||
if (options.signal) {
|
||
options.signal.removeEventListener('abort', abortHandler);
|
||
}
|
||
reject(new Error('Сетевая ошибка при отправке в буфер'));
|
||
};
|
||
|
||
xhr.ontimeout = () => {
|
||
if (options.signal) {
|
||
options.signal.removeEventListener('abort', abortHandler);
|
||
}
|
||
reject(new Error(`Таймаут ожидания ответа буфера (${Math.round(xhr.timeout / 1000)}с)`));
|
||
};
|
||
|
||
xhr.onabort = () => {
|
||
if (options.signal) {
|
||
options.signal.removeEventListener('abort', abortHandler);
|
||
}
|
||
reject(new DOMException('Upload aborted', 'AbortError'));
|
||
};
|
||
|
||
xhr.send(file);
|
||
});
|
||
}
|