chunk upload

This commit is contained in:
user committed 2025-02-25 17:01:47 +03:00
1 parent 31dcb52c87
commit 2bc33e0971
3 files changed
+186 -135

No files matched your search

+69 -37
View File
@@ -43,7 +43,7 @@
// Base URL for endpoints
const BASE_URL = "https://my-public-node-1.projscale.dev/api/v1.5/storage";
// Function to append messages to log div
// Append log message to log div
function appendLog(message) {
const logDiv = document.getElementById('log');
const p = document.createElement('p');
@@ -51,7 +51,7 @@
logDiv.appendChild(p);
}
// Function to compute SHA-256 hash of a file in hex using jsSHA library with incremental reading
// Compute SHA-256 hash of a file using jsSHA library (incremental reading)
function computeSHA256(file) {
return new Promise((resolve, reject) => {
const chunkSize = 2097152; // 2MB per chunk
@@ -60,7 +60,7 @@
const shaObj = new jsSHA("SHA-256", "ARRAYBUFFER");
reader.onload = function(e) {
// Update the hash object with the current chunk data
// Update hash with current chunk data
shaObj.update(e.target.result);
offset += chunkSize;
appendLog(`Processed ${Math.min(offset, file.size)} из ${file.size} байт`);
@@ -89,6 +89,70 @@
});
}
// Upload file in chunks (max 80 MB per chunk)
async function uploadFileInChunks(file) {
const maxChunkSize = 80 * 1024 * 1024; // 80 MB
let offset = 0;
let uploadId = null;
try {
appendLog("Starting hash computation...");
const hashHex = await computeSHA256(file);
appendLog(`Computed SHA-256 hash: ${hashHex}`);
while (offset < file.size) {
const chunk = file.slice(offset, Math.min(offset + maxChunkSize, file.size));
appendLog(`Uploading chunk starting at byte ${offset}`);
// Prepare headers for the chunk upload
const headers = {
"X-Content-SHA256": hashHex,
"X-File-Name": btoa(unescape(encodeURIComponent(file.name))), // File name in base64
"X-Chunk-Start": offset.toString(),
"Content-Type": file.type || "application/octet-stream"
};
if (uploadId) {
headers["X-Upload-ID"] = uploadId;
}
const response = await fetch(BASE_URL, {
method: "POST",
headers: headers,
body: chunk
});
if (!response.ok) {
const errorData = await response.json();
appendLog(`Chunk upload failed: ${errorData.error}`);
throw new Error(`Upload failed at offset ${offset}: ${errorData.error}`);
}
const resultData = await response.json();
// Save uploadId from first response if not set
if (!uploadId && resultData.upload_id) {
uploadId = resultData.upload_id;
}
// If final response contains content_id, upload is complete
if (resultData.content_id) {
appendLog(`Upload complete. File ID: ${resultData.content_id}`);
return resultData;
}
// Update offset based on server-reported current size
if (resultData.current_size !== undefined) {
offset = resultData.current_size;
appendLog(`Server reports current_size: ${offset}`);
} else {
appendLog("Unexpected response from server, missing current_size.");
throw new Error("Missing current_size in response");
}
}
} catch (err) {
appendLog(`Error during upload: ${err}`);
throw err;
}
}
// Upload button event listener
document.getElementById('uploadBtn').addEventListener('click', async () => {
const fileInput = document.getElementById('uploadFile');
@@ -101,42 +165,15 @@
}
const file = fileInput.files[0];
appendLog("Starting hash computation...");
try {
// Compute SHA-256 hash of the file in hex format
const hashHex = await computeSHA256(file);
appendLog(`Computed SHA-256 hash: ${hashHex}`);
// Prepare the POST request with file as body and additional header for filename
const encodedFileName = btoa(unescape(encodeURIComponent(file.name)));
const response = await fetch(BASE_URL, {
method: "POST",
headers: {
"X-Content-SHA256": hashHex,
"X-File-Name": encodedFileName, // NEW: передаём имя файла в base64
"Content-Type": file.type || "application/octet-stream"
},
body: file
});
if (!response.ok) {
const errorData = await response.json();
uploadResult.textContent = `Ошибка: ${errorData.error}`;
appendLog(`Upload failed: ${errorData.error}`);
return;
}
const resultData = await response.json();
const resultData = await uploadFileInChunks(file);
uploadResult.textContent = `Файл загружен успешно. content_sha256: ${resultData.content_sha256}`;
appendLog(`Upload successful. Response: ${JSON.stringify(resultData)}`);
} catch (err) {
uploadResult.textContent = "Ошибка при загрузке файла.";
appendLog(`Error during upload: ${err}`);
}
});
// Load file button event listener for streaming
// Load file for streaming (remains unchanged)
document.getElementById('loadFileBtn').addEventListener('click', async () => {
const fileHash = document.getElementById('fileHashInput').value.trim();
const mediaContainer = document.getElementById('mediaContainer');
@@ -147,12 +184,10 @@
return;
}
// Construct file URL
const fileUrl = `${BASE_URL}/${fileHash}`;
appendLog(`Fetching file info for hash: ${fileHash}`);
try {
// Perform a HEAD request to determine Content-Type
const headResponse = await fetch(fileUrl, { method: "HEAD" });
if (!headResponse.ok) {
mediaContainer.textContent = "Файл не найден.";
@@ -164,7 +199,6 @@
appendLog(`Content-Type: ${contentType}`);
let mediaElement;
// Create appropriate element based on Content-Type
if (contentType.startsWith("image/")) {
mediaElement = document.createElement("img");
mediaElement.style.maxWidth = "100%";
@@ -176,12 +210,10 @@
mediaElement = document.createElement("audio");
mediaElement.controls = true;
} else {
// For other types, create a download link
mediaElement = document.createElement("a");
mediaElement.textContent = "Скачать файл";
}
// Set the src or href attribute to stream the file
if (mediaElement.tagName === "A") {
mediaElement.href = fileUrl;
mediaElement.download = "";