From 1769fb14988922e3a8c85e62c91c8779008db693 Mon Sep 17 00:00:00 2001 From: Oleg Lobanov Date: Fri, 28 Jul 2023 14:41:53 +0200 Subject: [PATCH] Add custom chunked upload handlers --- cmd/root.go | 1 - frontend/src/api/tus.js | 53 +- frontend/src/components/prompts/Replace.vue | 10 +- frontend/src/i18n/en.json | 12 +- frontend/src/store/index.js | 1 + frontend/src/store/mutations.js | 4 + frontend/src/views/files/Listing.vue | 10 + frontend/src/views/settings/Global.vue | 80 +- go.mod | 18 +- go.sum | 1098 +------------------ http/http.go | 9 +- http/tus.go | 122 --- http/tus_handlers.go | 153 +++ http/tus_store.go | 279 ----- http/utils.go | 4 +- settings/storage.go | 1 - settings/tus.go | 5 +- 17 files changed, 271 insertions(+), 1589 deletions(-) delete mode 100644 http/tus.go create mode 100644 http/tus_handlers.go delete mode 100644 http/tus_store.go diff --git a/cmd/root.go b/cmd/root.go index 55c3d23d..dc8b57e8 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -335,7 +335,6 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) { AuthMethod: "", Branding: settings.Branding{}, Tus: settings.Tus{ - Enabled: true, ChunkSize: settings.DefaultTusChunkSize, RetryCount: settings.DefaultTusRetryCount, }, diff --git a/frontend/src/api/tus.js b/frontend/src/api/tus.js index 0e4e67a7..47e443b4 100644 --- a/frontend/src/api/tus.js +++ b/frontend/src/api/tus.js @@ -2,6 +2,7 @@ import * as tus from "tus-js-client"; import { tusEndpoint, tusSettings } from "@/utils/constants"; import store from "@/store"; import { removePrefix } from "@/api/utils"; +import { fetchURL } from "./utils"; const RETRY_BASE_DELAY = 1000; const RETRY_MAX_DELAY = 20000; @@ -12,25 +13,20 @@ export async function upload(url, content = "", overwrite = false, onupload) { throw new Error("Tus.io settings are not defined"); } + url = removePrefix(url); + let resourceUrl = `${tusEndpoint}${url}?override=${overwrite}`; + + await createUpload(resourceUrl); + return new Promise((resolve, reject) => { - const metadata = { - overwrite: overwrite.toString(), - // url is URI encoded and needs to be decoded for metadata first - destination: decodeURIComponent(removePrefix(url)), - }; - var upload = new tus.Upload(content, { - endpoint: tusEndpoint, + let upload = new tus.Upload(content, { + uploadUrl: resourceUrl, chunkSize: tusSettings.chunkSize, retryDelays: computeRetryDelays(tusSettings), parallelUploads: 1, + storeFingerprintForResuming: false, headers: { "X-Auth": store.state.jwt, - // Send the metadata with every request - // If we used the tus client's metadata option, it would only be sent - // with some of the requests. - "Upload-Metadata": Object.entries(metadata) - .map(([key, value]) => `${key} ${btoa(value)}`) - .join(","), }, onError: function (error) { reject("Upload failed: " + error); @@ -43,22 +39,24 @@ export async function upload(url, content = "", overwrite = false, onupload) { } }, onSuccess: function () { - // Remove the upload from the storage when completed. - // Otherwise, old storage keys aren't overwritten, which - // lets resumable uploads fail. - upload._removeFromUrlStorage(); resolve(); }, }); - upload.findPreviousUploads().then(function (previousUploads) { - if (previousUploads.length) { - upload.resumeFromPreviousUpload(previousUploads[0]); - } - }); upload.start(); }); } +async function createUpload(resourceUrl) { + let headResp = await fetchURL(resourceUrl, { + method: "POST", + }); + if (headResp.status !== 201) { + throw new Error( + `Failed to create an upload: ${headResp.status} ${headResp.statusText}` + ); + } +} + function computeRetryDelays(tusSettings) { if (!tusSettings.retryCount || tusSettings.retryCount < 1) { // Disable retries altogether @@ -79,16 +77,7 @@ function computeRetryDelays(tusSettings) { } export async function useTus(content) { - if (!isTusSupported() || !(content instanceof Blob)) { - return false; - } - - // use tus if tus uploads are enabled and the content's size is larger than chunkSize - return ( - tusSettings && - tusSettings.enabled === true && - content.size > tusSettings.chunkSize - ); + return isTusSupported() && content instanceof Blob; } function isTusSupported() { diff --git a/frontend/src/components/prompts/Replace.vue b/frontend/src/components/prompts/Replace.vue index 82ede1d6..a525bbbc 100644 --- a/frontend/src/components/prompts/Replace.vue +++ b/frontend/src/components/prompts/Replace.vue @@ -17,6 +17,14 @@ > {{ $t("buttons.cancel") }} +