mirror of
https://github.com/Dangoware/confetti-box.git
synced 2025-04-19 15:22:57 -05:00
Added poorly implemented progress for chunked uploads
This commit is contained in:
parent
9b80670961
commit
4875445325
2 changed files with 112 additions and 16 deletions
16
src/lib.rs
16
src/lib.rs
|
@ -203,7 +203,7 @@ impl ChunkedResponse {
|
|||
|
||||
/// Start a chunked upload. Response contains all the info you need to continue
|
||||
/// uploading chunks.
|
||||
#[post("/upload/chunked", data = "<file_info>")]
|
||||
#[post("/upload/chunked", data = "<file_info>", rank = 1)]
|
||||
pub async fn chunked_upload_start(
|
||||
db: &State<Arc<RwLock<Chunkbase>>>,
|
||||
settings: &State<Settings>,
|
||||
|
@ -238,11 +238,12 @@ pub async fn chunked_upload_start(
|
|||
}))
|
||||
}
|
||||
|
||||
#[post("/upload/chunked?<uuid>", data = "<data>")]
|
||||
#[post("/upload/chunked?<uuid>&<offset>", data = "<data>")]
|
||||
pub async fn chunked_upload_continue(
|
||||
chunk_db: &State<Arc<RwLock<Chunkbase>>>,
|
||||
data: Data<'_>,
|
||||
uuid: String,
|
||||
offset: u64,
|
||||
) -> Result<(), io::Error> {
|
||||
let uuid = Uuid::parse_str(&uuid).map_err(|e| io::Error::other(e))?;
|
||||
let data_stream = data.open(101.megabytes());
|
||||
|
@ -263,7 +264,7 @@ pub async fn chunked_upload_continue(
|
|||
.await?
|
||||
};
|
||||
|
||||
file.seek(io::SeekFrom::Start(chunked_info.offset)).await?;
|
||||
file.seek(io::SeekFrom::Start(offset)).await?;
|
||||
data_stream.stream_to(&mut file).await?.written;
|
||||
file.flush().await?;
|
||||
let position = file.stream_position().await?;
|
||||
|
@ -276,18 +277,11 @@ pub async fn chunked_upload_continue(
|
|||
return Err(io::Error::other("File larger than expected"))
|
||||
}
|
||||
|
||||
chunk_db.write()
|
||||
.unwrap()
|
||||
.mut_chunks()
|
||||
.get_mut(&uuid)
|
||||
.unwrap()
|
||||
.offset = position;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Finalize a chunked upload
|
||||
#[post("/upload/chunked?<uuid>&finish")]
|
||||
#[get("/upload/chunked?<uuid>&finish")]
|
||||
pub async fn chunked_upload_finish(
|
||||
main_db: &State<Arc<RwLock<Mochibase>>>,
|
||||
chunk_db: &State<Arc<RwLock<Chunkbase>>>,
|
||||
|
|
112
web/request.js
112
web/request.js
|
@ -59,6 +59,7 @@ async function pasteSubmit(evt) {
|
|||
|
||||
async function sendFile(files, duration, maxSize) {
|
||||
for (const file of files) {
|
||||
const [linkRow, progressBar, progressText] = await addNewToList(file.name);
|
||||
if (file.size > maxSize) {
|
||||
console.error("Provided file is too large", file.size, "bytes; max", maxSize, "bytes");
|
||||
continue;
|
||||
|
@ -67,6 +68,7 @@ async function sendFile(files, duration, maxSize) {
|
|||
continue;
|
||||
}
|
||||
|
||||
// Get preliminary upload information
|
||||
let chunkedResponse;
|
||||
try {
|
||||
const response = await fetch("/upload/chunked", {
|
||||
|
@ -86,19 +88,119 @@ async function sendFile(files, duration, maxSize) {
|
|||
}
|
||||
|
||||
// Upload the file in `chunk_size` chunks
|
||||
let uploadArray = [];
|
||||
const progressValues = [];
|
||||
for (let start = 0; start < file.size; start += chunkedResponse.chunk_size) {
|
||||
const chunk = file.slice(start, start + chunkedResponse.chunk_size)
|
||||
const url = "/upload/chunked?uuid=" + chunkedResponse.uuid + "&offset=" + start;
|
||||
const ID = progressValues.push(0);
|
||||
|
||||
await fetch("/upload/chunked?uuid=" + chunkedResponse.uuid, { method: 'post', body: chunk }).then(res => res.text())
|
||||
let upload = new Promise(function (resolve, reject) {
|
||||
let request = new XMLHttpRequest();
|
||||
request.open("POST", url, true);
|
||||
request.upload.addEventListener('progress',
|
||||
(p) => {uploadProgress(p, progressBar, progressText, progressValues, file.size, ID);}, true
|
||||
);
|
||||
|
||||
request.onload = () => {
|
||||
if (this.status >= 200 && this.status < 300) {
|
||||
resolve(request.response);
|
||||
} else {
|
||||
reject({status: this.status, statusText: request.statusText});
|
||||
}
|
||||
};
|
||||
request.onerror = () => reject({status: this.status, statusText: request.statusText});
|
||||
request.send(chunk);
|
||||
});
|
||||
|
||||
uploadArray.push(upload);
|
||||
}
|
||||
console.log("Waiting for multiple uploads to complete");
|
||||
console.log(await Promise.allSettled(uploadArray));
|
||||
|
||||
console.log(await fetch("/upload/chunked?uuid=" + chunkedResponse.uuid + "&finish", { method: 'post' }).then(res => res.json()))
|
||||
// Finish the request and update the progress box
|
||||
const result = await fetch("/upload/chunked?uuid=" + chunkedResponse.uuid + "&finish");
|
||||
uploadComplete(result, progressBar, progressText, linkRow);
|
||||
}
|
||||
}
|
||||
|
||||
function networkErrorHandler(err, progressBar, progressText, linkRow) {
|
||||
makeErrored(progressBar, progressText, linkRow, "A network error occured");
|
||||
console.error("A network error occured while uploading", err);
|
||||
async function addNewToList(origFileName) {
|
||||
const uploadedFilesDisplay = document.getElementById("uploadedFilesDisplay");
|
||||
const linkRow = uploadedFilesDisplay.appendChild(document.createElement("div"));
|
||||
const fileName = linkRow.appendChild(document.createElement("p"));
|
||||
const progressBar = linkRow.appendChild(document.createElement("progress"));
|
||||
const progressTxt = linkRow.appendChild(document.createElement("p"));
|
||||
|
||||
fileName.textContent = origFileName;
|
||||
fileName.classList.add("file_name");
|
||||
progressTxt.classList.add("status");
|
||||
progressBar.max="100";
|
||||
progressBar.value="0";
|
||||
|
||||
return [linkRow, progressBar, progressTxt];
|
||||
}
|
||||
|
||||
const sumValues = obj => Object.values(obj).reduce((a, b) => a + b, 0);
|
||||
|
||||
function uploadProgress(progress, progressBar, progressText, progressValues, fileSize, ID) {
|
||||
if (progress.lengthComputable) {
|
||||
progressValues[ID] = progress.loaded;
|
||||
|
||||
const progressPercent = Math.floor((sumValues(progressValues) / fileSize) * 100);
|
||||
if (progressPercent == 100) {
|
||||
progressBar.removeAttribute("value");
|
||||
progressText.textContent = "⏳";
|
||||
} else {
|
||||
progressBar.value = progressPercent;
|
||||
progressText.textContent = progressPercent + "%";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function uploadComplete(response, progressBar, progressText, linkRow) {
|
||||
if (response.status === 200) {
|
||||
const responseJson = await response.json();
|
||||
console.log("Successfully uploaded file", responseJson);
|
||||
makeFinished(progressBar, progressText, linkRow, responseJson);
|
||||
} else if (response.status === 413) {
|
||||
makeErrored(progressBar, progressText, linkRow, TOO_LARGE_TEXT);
|
||||
} else {
|
||||
makeErrored(progressBar, progressText, linkRow, ERROR_TEXT);
|
||||
}
|
||||
}
|
||||
|
||||
function makeErrored(progressBar, progressText, linkRow, errorMessage) {
|
||||
progressText.textContent = errorMessage;
|
||||
progressBar.style.display = "none";
|
||||
linkRow.classList.add("upload_failed");
|
||||
}
|
||||
|
||||
function makeFinished(progressBar, progressText, linkRow, response) {
|
||||
progressText.textContent = "";
|
||||
const link = progressText.appendChild(document.createElement("a"));
|
||||
link.textContent = response.mmid;
|
||||
link.href = "/f/" + response.mmid;
|
||||
link.target = "_blank";
|
||||
|
||||
let button = linkRow.appendChild(document.createElement("button"));
|
||||
button.textContent = "📝";
|
||||
let buttonTimeout = null;
|
||||
button.addEventListener('click', function(_e) {
|
||||
const mmid = response.mmid;
|
||||
if (buttonTimeout) {
|
||||
clearTimeout(buttonTimeout);
|
||||
}
|
||||
navigator.clipboard.writeText(
|
||||
window.location.protocol + "//" + window.location.host + "/f/" + mmid
|
||||
);
|
||||
button.textContent = "✅";
|
||||
buttonTimeout = setTimeout(function() {
|
||||
button.textContent = "📝";
|
||||
}, 750);
|
||||
});
|
||||
|
||||
progressBar.style.display = "none";
|
||||
linkRow.classList.add("upload_done");
|
||||
}
|
||||
|
||||
async function initEverything() {
|
||||
|
|
Loading…
Reference in a new issue