weiro/assets/js/controllers/upload.js

98 lines
2.8 KiB
JavaScript

import { Controller } from "@hotwired/stimulus"
export default class UploadController extends Controller {
static values = {
siteId: Number,
};
upload(ev) {
ev.preventDefault();
this._promptForUpload((files) => {
this._doUploads(files);
})
}
_promptForUpload(onAccept) {
const input = document.createElement('input');
input.type = 'file';
input.accept = 'image/*';
input.multiple = true;
input.onchange = (e) => {
const files = Array.from(e.target.files);
if (files.length > 0) {
onAccept(files);
}
};
input.click();
}
async _doUploads(files) {
for (let file of files) {
await this._doUpload(file);
}
window.location.reload();
}
async _doUpload(file) {
console.log(`Uploading ${file.name}: new pending`);
// Prepare upload of file supplying size and mime-type
let newPending = await (await fetch(`/sites/${this.siteIdValue}/uploads/pending`, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
size: file.size,
mime: file.type,
name: file.name,
})
})).json();
// Upload file in 2 MB blocks
let offset = 0;
let chunkSize = 2 * 1024 * 1024;
while (offset < file.size) {
let chunk = file.slice(offset, offset + chunkSize);
console.log(`Uploading ${file.name}: uploading part`);
await fetch(`/sites/${this.siteIdValue}/uploads/pending/${newPending.guid}`, {
method: 'POST',
headers: {
'Content-Type': 'application/octet-stream'
},
body: chunk
});
offset += chunkSize;
}
// Calculate SHA256 hash
const hash = await this._calculateSHA256(file);
// Finalise upload
console.log(`Uploading ${file.name}: finalise`);
await fetch(`/sites/${this.siteIdValue}/uploads/pending/${newPending.guid}/finalize`, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
hash: hash
})
});
}
async _calculateSHA256(file) {
const arrayBuffer = await file.arrayBuffer();
const hashBuffer = await crypto.subtle.digest('SHA-256', arrayBuffer);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
return hashHex;
}
}