Skip to content

Commit

Permalink
Use etag as cache buster
Browse files Browse the repository at this point in the history
Signed-off-by: Louis Chemineau <louis@chmn.me>
  • Loading branch information
artonge committed Jun 15, 2023
1 parent a50e7ad commit 4dbe731
Show file tree
Hide file tree
Showing 11 changed files with 155 additions and 40 deletions.
4 changes: 2 additions & 2 deletions js/viewer-main.js

Large diffs are not rendered by default.

44 changes: 44 additions & 0 deletions js/viewer-main.js.LICENSE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,50 @@
*
*/

/**
* @copyright Copyright (c) 2021 John Molakvoæ <skjnldsv@protonmail.com>
*
* @author John Molakvoæ <skjnldsv@protonmail.com>
*
* @license AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

/**
* @copyright Copyright (c) 2022 John Molakvoæ <skjnldsv@protonmail.com>
*
* @author John Molakvoæ <skjnldsv@protonmail.com>
*
* @license AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

/**
* @license nested-property https://github.com/cosmosio/nested-property
*
Expand Down
2 changes: 1 addition & 1 deletion js/viewer-main.js.map

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"@nextcloud/axios": "^2.3.0",
"@nextcloud/dialogs": "^4.0.1",
"@nextcloud/event-bus": "^3.0.2",
"@nextcloud/files": "^3.0.0-beta.10",
"@nextcloud/initial-state": "^2.0.0",
"@nextcloud/l10n": "^2.1.0",
"@nextcloud/logger": "^2.5.0",
Expand Down
17 changes: 16 additions & 1 deletion src/components/ImageEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import { basename, dirname, extname, join } from 'path'
import { emit } from '@nextcloud/event-bus'
import { showError, showSuccess } from '@nextcloud/dialogs'
import axios from '@nextcloud/axios'
import { Node } from '@nextcloud/files'
import logger from '../services/logger.js'
import translations from '../models/editorTranslations.js'
import { rawStat } from '../services/FileInfo.js'
let TABS, TOOLS
Expand Down Expand Up @@ -179,7 +181,20 @@ export default {
emit('files:node:created', { fileid: parseInt(response?.headers?.['oc-fileid']?.split('oc')[0]) || null })
} else {
this.$emit('updated')
emit('files:node:updated', { fileid: this.fileid })
const updatedFile = await rawStat(origin, decodeURI(pathname))
const node = new Node({
id: Number.parseInt(this.fileid),
source: this.src,
mtime: new Date(updatedFile.lastmod),
...updatedFile,
attributes: {
...updatedFile,
...updatedFile.props,
},
})
emit('files:node:updated', { fileid: this.fileid, node })
}
} catch (error) {
logger.error('Error saving image', { error })
Expand Down
9 changes: 1 addition & 8 deletions src/components/Images.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
:mime="mime"
:src="src"
:fileid="fileid"
@updated="onUpdate"
@close="onClose" />

<img v-else-if="data !== null"
Expand All @@ -35,7 +34,7 @@
loaded,
zoomed: zoomRatio !== 1
}"
:src="`${data}${cacheBuster}`"
:src="data"
:style="{
marginTop: shiftY + 'px',
marginLeft: shiftX + 'px',
Expand Down Expand Up @@ -82,8 +81,6 @@ export default {
shiftY: 0,
zoomRatio: 1,
fallback: false,
cacheBuster: '',
cacheBusterCounter: 0,
}
},
Expand Down Expand Up @@ -267,10 +264,6 @@ export default {
this.fallback = true
}
},
onUpdate() {
this.cacheBuster = `?buster=${this.cacheBusterCounter++}`
},
},
}
</script>
Expand Down
5 changes: 4 additions & 1 deletion src/mixins/PreviewUrl.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export default {
previewUrl: this.previewUrl,
hasPreview: this.hasPreview,
davPath: this.davPath,
etag: this.$attrs.etag || '',
})
},

Expand All @@ -65,9 +66,10 @@ export default {
* @param {boolean} data.hasPreview have the file an existing preview ?
* @param {string} data.davPath the absolute dav path
* @param {string} data.filename the file name
* @param {string} data.etag the etag of the file
* @return {string} the absolute url
*/
getPreviewIfAny({ fileid, filename, previewUrl, hasPreview, davPath }) {
getPreviewIfAny({ fileid, filename, previewUrl, hasPreview, davPath, etag }) {
if (previewUrl) {
return previewUrl
}
Expand All @@ -76,6 +78,7 @@ export default {
+ `&x=${Math.floor(screen.width * devicePixelRatio)}`
+ `&y=${Math.floor(screen.height * devicePixelRatio)}`
+ '&a=true'
+ (etag !== undefined ? `&etag=${etag.replace(/&quot;/g, '')}` : '')

if (hasPreview) {
// TODO: find a nicer standard way of doing this?
Expand Down
2 changes: 1 addition & 1 deletion src/services/DavClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import axios from '@nextcloud/axios'

import { getRootPath, getToken, isPublic } from '../utils/davUtils.js'

// Add this so the server knows it is an request from the browserg
// Add this so the server knows it is an request from the browser
axios.defaults.headers['X-Requested-With'] = 'XMLHttpRequest'

// force our axios
Expand Down
75 changes: 49 additions & 26 deletions src/services/FileInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,41 +22,64 @@

import client from './DavClient.js'
import { genFileInfo } from '../utils/fileUtils.js'
import { createClient } from 'webdav'

const statData = `<?xml version="1.0"?>
<d:propfind xmlns:d="DAV:"
xmlns:oc="http://owncloud.org/ns"
xmlns:nc="http://nextcloud.org/ns"
xmlns:ocs="http://open-collaboration-services.org/ns">
<d:prop>
<d:getlastmodified />
<d:getcontenttype />
<d:resourcetype />
<d:getetag />
<oc:fileid />
<oc:permissions />
<oc:size />
<d:getcontentlength />
<nc:has-preview />
<nc:mount-type />
<nc:is-encrypted />
<ocs:share-permissions />
<oc:tags />
<oc:favorite />
<oc:comments-unread />
<oc:owner-id />
<oc:owner-display-name />
<oc:share-types />
</d:prop>
</d:propfind>`

/**
* Retrieve the files list
*
* @param {string} path the path relative to the user root
* @param {object} [options] optional options for axios
* @return {Array} the file list
* @return {Promise<Array>} the file list
*/
export default async function(path, options) {
const response = await client.stat(path, Object.assign({
data: `<?xml version="1.0"?>
<d:propfind xmlns:d="DAV:"
xmlns:oc="http://owncloud.org/ns"
xmlns:nc="http://nextcloud.org/ns"
xmlns:ocs="http://open-collaboration-services.org/ns">
<d:prop>
<d:getlastmodified />
<d:getcontenttype />
<d:resourcetype />
<oc:fileid />
<oc:permissions />
<oc:size />
<d:getcontentlength />
<nc:has-preview />
<nc:mount-type />
<nc:is-encrypted />
<ocs:share-permissions />
<oc:tags />
<oc:favorite />
<oc:comments-unread />
<oc:owner-id />
<oc:owner-display-name />
<oc:share-types />
</d:prop>
</d:propfind>`,
data: statData,
details: true,
}, options))
return genFileInfo(response.data)
}

/**
* Retrieve the files list
*
* @param {string} origin
* @param {string} path the path relative to the user root
* @param {object} [options] optional options for axios
* @return {Promise<object>} the file list
*/
export async function rawStat(origin, path, options) {
const response = await createClient(origin).stat(path, {
...options,
data: statData,
details: true,
})

return response.data
}
11 changes: 11 additions & 0 deletions src/views/Viewer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,7 @@ export default {
// React to Files' Sidebar events.
subscribe('files:sidebar:opened', this.handleAppSidebarOpen)
subscribe('files:sidebar:closed', this.handleAppSidebarClose)
subscribe('files:node:updated', this.handleFileUpdated)
subscribe('viewer:trapElements:changed', this.handleTrapElementsChange)
window.addEventListener('keydown', this.keyboardDeleteFile)
window.addEventListener('keydown', this.keyboardDownloadFile)
Expand Down Expand Up @@ -968,6 +969,16 @@ export default {
this.trapElements = []
},
// Update etag of updated file to break cache.
async handleFileUpdated({ fileid, node }) {
const index = this.fileList.findIndex(({ fileid: currentFileId }) => currentFileId === fileid)
this.fileList.splice(index, 1, { ...node, etag: node.etag })
if (node.fileid === this.currentFile.fileid) {
this.currentFile.etag = node.etag
}
},
onResize() {
const sidebar = document.querySelector('aside.app-sidebar')
if (sidebar) {
Expand Down

0 comments on commit 4dbe731

Please sign in to comment.