Skip to content

Commit

Permalink
Add chunked upload with tus-js-client
Browse files Browse the repository at this point in the history
Added chunked upload with tus-js-client if the server supports it.

Co-authored-by: Vincent Petry <[email protected]>
  • Loading branch information
LukasHirt and Vincent Petry committed Apr 23, 2020
1 parent d366363 commit 6dc0246
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 10 deletions.
30 changes: 22 additions & 8 deletions apps/files/src/mixins.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@ export default {
'highlightedFile',
'publicLinkPassword',
'fileSortField',
'currentFolder',
'fileSortDirectionDesc'
]),
...mapGetters(['getToken', 'capabilities']),
...mapGetters(['getToken', 'capabilities', 'configuration']),

_sidebarOpen() {
return this.highlightedFile !== null
Expand Down Expand Up @@ -408,14 +409,27 @@ export default {
} else {
basePath = this.path || ''
relativePath = pathUtil.join(basePath, relativePath)
promise = this.uploadQueue.add(() =>
this.$client.files.putFileContents(relativePath, file, {
onProgress: progress => {
this.$_ocUpload_onProgress(progress, file)
},
overwrite: overwrite
// FIXME: this might break if relativePath is not the currentFolder
// and is a mount point that has no chunk support
if (this.browserSupportsChunked && this.currentFolder.isChunkedUploadSupported) {
promise = this.uploadQueue.add(() => {
return this.uploadChunkedFile(file, pathUtil.dirname(relativePath), {
chunkSize: this.configuration.uploadChunkSize,
emitProgress: progress => {
this.$_ocUpload_onProgress(progress, file)
}
})
})
)
} else {
promise = this.uploadQueue.add(() =>
this.$client.files.putFileContents(relativePath, file, {
onProgress: progress => {
this.$_ocUpload_onProgress(progress, file)
},
overwrite: overwrite
})
)
}
}

promise
Expand Down
3 changes: 2 additions & 1 deletion apps/files/src/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ function _buildFile(file) {
},
isReceivedShare: function() {
return this.permissions.indexOf('S') >= 0
}
},
isChunkedUploadSupported: !!(file.getTusSupport && file.getTusSupport())
}
}

Expand Down
9 changes: 9 additions & 0 deletions changelog/unreleased/3345
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Enhancement: Add chunked upload with tus-js-client

Whenever the backend server advertises TUS support, uploading files will
use TUS as well for uploading, which makes it possible to resume failed uploads.
It is also possible to optionally set a chunk size by setting a numeric value
for "uploadChunkSize" in bytes in config.json.

https://github.com/owncloud/phoenix/issues/67
https://github.com/owncloud/phoenix/pull/3345
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
"rimraf": "^3.0.0",
"start-server-and-test": "^1.9.1",
"style-loader": "^1.0.0",
"tus-js-client": "^1.8.0",
"url-search-params-polyfill": "^8.0.0",
"vue": "^2.6.10",
"vue-clipboard2": "^0.3.1",
Expand Down
2 changes: 2 additions & 0 deletions src/phoenix.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import coreTranslations from '../l10n/translations.json'

import MediaSource from './plugins/mediaSource.js'
import PhoenixPlugin from './plugins/phoenix'
import ChunkedUpload from './plugins/upload'

// --- Drag Drop ----

Expand Down Expand Up @@ -64,6 +65,7 @@ Vue.use(VueMeta, {
// optional pluginOptions
refreshOnceOnNavigation: true
})
Vue.use(ChunkedUpload)

Vue.component('drag', Drag)
Vue.component('drop', Drop)
Expand Down
56 changes: 56 additions & 0 deletions src/plugins/upload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import tus from 'tus-js-client'

export default {
install(Vue) {
Vue.mixin({
computed: {
browserSupportsChunked() {
return tus.isSupported
}
},
methods: {
uploadChunkedFile(file, path, options) {
return new Promise((resolve, reject) => {
const headers = this.$client.helpers.buildHeaders()
delete headers['OCS-APIREQUEST']
var mtime = null
if (file.lastModifiedDate) {
mtime = file.lastModifiedDate.getTime() / 1000
}
if (file.lastModified) {
mtime = file.lastModified / 1000
}
const upload = new tus.Upload(file, {
endpoint: this.$client.files.getFileUrlV2(path),
headers: headers,
chunkSize: options.chunkSize || Infinity,
retryDelays: [0, 3000, 5000, 10000, 20000],
metadata: {
filename: file.name,
filetype: file.type,
size: file.size,
mtime: mtime
},

onError: error => {
console.error(`Error uploading file "${file}" to "${path}"`, error)
reject(error)
},

onProgress: (bytesUploaded, bytesTotal) => {
options.emitProgress({ loaded: bytesUploaded, total: bytesTotal })
},

onSuccess: () => {
resolve(`File ${upload.file.name} was successfully uploaded`)
}
})

upload.start()
return upload
})
}
}
})
}
}
1 change: 1 addition & 0 deletions src/store/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const mutations = {
state.auth = config.auth
state.openIdConnect = config.openIdConnect
state.rootFolder = config.rootFolder === undefined ? '/' : config.rootFolder
state.uploadChunkSize = config.uploadChunkSize === undefined ? Infinity : config.uploadChunkSize
state.state = config.state === undefined ? 'working' : config.state
state.applications = config.applications === undefined ? [] : config.applications
if (config.corrupted) state.corrupted = config.corrupted
Expand Down
101 changes: 100 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1956,6 +1956,11 @@ buffer-crc32@^0.2.1, buffer-crc32@^0.2.13, buffer-crc32@~0.2.3:
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=

buffer-from@^0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-0.1.2.tgz#15f4b9bcef012044df31142c14333caf6e0260d0"
integrity sha512-RiWIenusJsmI2KcvqQABB83tLxCByE3upSP8QU3rJDMVFGPWLvPQJt/O1Su9moRWeH7d+Q2HYb68f6+v+tw2vg==

buffer-from@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
Expand Down Expand Up @@ -2386,6 +2391,14 @@ colors@^1.1.2, colors@^1.3.3, colors@^1.4.0:
resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==

combine-errors@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/combine-errors/-/combine-errors-3.0.3.tgz#f4df6740083e5703a3181110c2b10551f003da86"
integrity sha1-9N9nQAg+VwOjGBEQwrEFUfAD2oY=
dependencies:
custom-error-instance "2.1.1"
lodash.uniqby "4.5.0"

combined-stream@^1.0.6, combined-stream@~1.0.6:
version "1.0.8"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
Expand Down Expand Up @@ -2824,6 +2837,11 @@ cuint@^0.2.2:
resolved "https://registry.yarnpkg.com/cuint/-/cuint-0.2.2.tgz#408086d409550c2631155619e9fa7bcadc3b991b"
integrity sha1-QICG1AlVDCYxFVYZ6fp7ytw7mRs=

[email protected]:
version "2.1.1"
resolved "https://registry.yarnpkg.com/custom-error-instance/-/custom-error-instance-2.1.1.tgz#3cf6391487a6629a6247eb0ca0ce00081b7e361a"
integrity sha1-PPY5FIemYppiR+sMoM4ACBt+Nho=

cyclist@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9"
Expand Down Expand Up @@ -3887,7 +3905,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2:
assign-symbols "^1.0.0"
is-extendable "^1.0.1"

[email protected], extend@~3.0.2:
[email protected], extend@^3.0.2, extend@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
Expand Down Expand Up @@ -5400,6 +5418,11 @@ join-path@^1.1.1:
url-join "0.0.1"
valid-url "^1"

js-base64@^2.4.9:
version "2.5.2"
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.2.tgz#313b6274dda718f714d00b3330bbae6e38e90209"
integrity sha512-Vg8czh0Q7sFBSUMWWArX/miJeBWYBPpdU/3M/DKSaekLMqrqVPaedp+5mZhie/r0lgrcaYBfwXatEew6gwgiQQ==

js-stringify@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/js-stringify/-/js-stringify-1.0.2.tgz#1736fddfd9724f28a3682adc6230ae7e4e9679db"
Expand Down Expand Up @@ -5839,11 +5862,36 @@ lodash._basefor@^3.0.0:
resolved "https://registry.yarnpkg.com/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2"
integrity sha1-dVC06SGO8J+tJDQ7YSAhx5tMIMI=

lodash._baseiteratee@~4.7.0:
version "4.7.0"
resolved "https://registry.yarnpkg.com/lodash._baseiteratee/-/lodash._baseiteratee-4.7.0.tgz#34a9b5543572727c3db2e78edae3c0e9e66bd102"
integrity sha1-NKm1VDVycnw9sueO2uPA6eZr0QI=
dependencies:
lodash._stringtopath "~4.8.0"

lodash._basetostring@~4.12.0:
version "4.12.0"
resolved "https://registry.yarnpkg.com/lodash._basetostring/-/lodash._basetostring-4.12.0.tgz#9327c9dc5158866b7fa4b9d42f4638e5766dd9df"
integrity sha1-kyfJ3FFYhmt/pLnUL0Y45XZt2d8=

lodash._baseuniq@~4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8"
integrity sha1-DrtE5FaBSveQXGIS+iybLVG4Qeg=
dependencies:
lodash._createset "~4.0.0"
lodash._root "~3.0.0"

lodash._bindcallback@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e"
integrity sha1-5THCdkTPi1epnhftlbNcdIeJOS4=

lodash._createset@~4.0.0:
version "4.0.3"
resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26"
integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY=

lodash._getnative@^3.0.0:
version "3.9.1"
resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
Expand All @@ -5854,6 +5902,18 @@ lodash._isiterateecall@^3.0.0:
resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c"
integrity sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=

lodash._root@~3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692"
integrity sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=

lodash._stringtopath@~4.8.0:
version "4.8.0"
resolved "https://registry.yarnpkg.com/lodash._stringtopath/-/lodash._stringtopath-4.8.0.tgz#941bcf0e64266e5fc1d66fed0a6959544c576824"
integrity sha1-lBvPDmQmbl/B1m/tCmlZVExXaCQ=
dependencies:
lodash._basetostring "~4.12.0"

[email protected]:
version "3.0.3"
resolved "https://registry.yarnpkg.com/lodash.clone/-/lodash.clone-3.0.3.tgz#84688c73d32b5a90ca25616963f189252a997043"
Expand Down Expand Up @@ -5917,11 +5977,24 @@ lodash.merge@^4.6.1, lodash.merge@^4.6.2:
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==

lodash.throttle@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4"
integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=

lodash.union@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88"
integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=

[email protected]:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.5.0.tgz#a3a17bbf62eeb6240f491846e97c1c4e2a5e1e21"
integrity sha1-o6F7v2LutiQPSRhG6XwcTipeHiE=
dependencies:
lodash._baseiteratee "~4.7.0"
lodash._baseuniq "~4.6.0"

lodash@^4.15.0, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.3, lodash@^4.17.4:
version "4.17.15"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
Expand Down Expand Up @@ -7526,6 +7599,14 @@ promise@^8.0.3:
dependencies:
asap "~2.0.6"

proper-lockfile@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-2.0.1.tgz#159fb06193d32003f4b3691dd2ec1a634aa80d1d"
integrity sha1-FZ+wYZPTIAP0s2kd0uwaY0qoDR0=
dependencies:
graceful-fs "^4.1.2"
retry "^0.10.0"

proxy-addr@~2.0.5:
version "2.0.6"
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf"
Expand Down Expand Up @@ -8125,6 +8206,11 @@ ret@~0.1.10:
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==

retry@^0.10.0:
version "0.10.1"
resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4"
integrity sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=

retry@^0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
Expand Down Expand Up @@ -9220,6 +9306,19 @@ tunnel-agent@^0.6.0:
dependencies:
safe-buffer "^5.0.1"

tus-js-client@^1.8.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/tus-js-client/-/tus-js-client-1.8.0.tgz#0402357bdaa90e9dee6f6734c24473808bff272b"
integrity sha512-qPX3TywqzxocTxUZtcS8X7Aik72SVMa0jKi4hWyfvRV+s9raVzzYGaP4MoJGaF0yOgm2+b6jXaVEHogxcJ8LGw==
dependencies:
buffer-from "^0.1.1"
combine-errors "^3.0.3"
extend "^3.0.2"
js-base64 "^2.4.9"
lodash.throttle "^4.1.1"
proper-lockfile "^2.0.1"
url-parse "^1.4.3"

tweetnacl@^0.14.3, tweetnacl@~0.14.0:
version "0.14.5"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
Expand Down

0 comments on commit 6dc0246

Please sign in to comment.