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; } }