Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Refactor: Use a global AbortController to cancel requests on route ch…
…anges

Signed-off-by: Marcel Klehr <[email protected]>
  • Loading branch information
marcelklehr committed Sep 1, 2022
commit 91551854a38abdfef8de397cd29aabfdfc8ff5e8
4 changes: 0 additions & 4 deletions src/components/FaceCover.vue
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,6 @@ export default {
await this.fetchFiles()
},

beforeDestroy() {
this.cancelFilesRequest('Changed view')
},

methods: {
async fetchFiles() {
await this.fetchFaceContent(this.face.basename)
Expand Down
22 changes: 5 additions & 17 deletions src/components/Folder.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
import { mapGetters } from 'vuex'

import getAlbumContent from '../services/AlbumContent'
import cancelableRequest from '../utils/CancelableRequest'
import FolderTagPreview from './FolderTagPreview'
import { abortController } from '../services/RequestHandler'

export default {
name: 'Folder',
Expand All @@ -52,7 +52,6 @@ export default {

data() {
return {
cancelRequest: null,
previewFolder: this.item.injected.fileid,
}
},
Expand Down Expand Up @@ -101,31 +100,20 @@ export default {
}
},

beforeDestroy() {
// cancel any pending requests
if (this.cancelRequest) {
this.cancelRequest('Navigated away')
}
},

methods: {
async getFolderData(filename) {
// init cancellable request
const { request, cancel } = cancelableRequest(getAlbumContent)
this.cancelRequest = cancel

try {
// get data
const { folder, folders, files } = await request(filename, { shared: this.item.injected.showShared })
const { folder, folders, files } = await getAlbumContent(filename, {
shared: this.item.injected.showShared,
signal: abortController.signal,
})
this.$store.dispatch('updateFolders', { fileid: folder.fileid, files, folders })
this.$store.dispatch('updateFiles', { folder, files, folders })
} catch (error) {
if (error.response && error.response.status) {
console.error('Failed to get folder content', filename, error.response)
}
// else we just cancelled the request
} finally {
this.cancelRequest = null
}
},

Expand Down
25 changes: 4 additions & 21 deletions src/components/Tag.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
import { mapGetters } from 'vuex'

import getTaggedImages from '../services/TaggedImages'
import cancelableRequest from '../utils/CancelableRequest'
import FolderTagPreview from './FolderTagPreview'
import { abortController } from '../services/RequestHandler'

export default {
name: 'Tag',
Expand All @@ -51,12 +51,6 @@ export default {
},
},

data() {
return {
cancelRequest: null,
}
},

computed: {
// global lists
...mapGetters([
Expand All @@ -78,29 +72,18 @@ export default {
},
},

beforeDestroy() {
// cancel any pending requests
if (this.cancelRequest) {
this.cancelRequest('Navigated away')
}
},

async created() {
// init cancellable request
const { request, cancel } = cancelableRequest(getTaggedImages)
this.cancelRequest = cancel

try {
// get data
const files = await request(this.item.injected.id)
const files = await getTaggedImages(this.item.injected.id, {
signal: abortController.signal,
})
this.$store.dispatch('updateTag', { id: this.item.injected.id, files })
this.$store.dispatch('appendFiles', files)
} catch (error) {
if (error.response && error.response.status) {
console.error('Failed to get folder content', this.item.injected.id, error.response)
}
} finally {
this.cancelRequest = null
}
},

Expand Down
16 changes: 4 additions & 12 deletions src/mixins/FetchAlbumsMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ import { getCurrentUser } from '@nextcloud/auth'

import client from '../services/DavClient.js'
import logger from '../services/logger.js'
import cancelableRequest from '../utils/CancelableRequest.js'
import { genFileInfo } from '../utils/fileUtils.js'
import { abortController } from '../services/RequestHandler'

export default {
name: 'FetchAlbumsMixin',
Expand All @@ -38,18 +38,13 @@ export default {
return {
errorFetchingAlbums: null,
loadingAlbums: false,
cancelAlbumsRequest: () => { },
}
},

async beforeMount() {
this.fetchAlbums()
},

beforeDestroy() {
this.cancelAlbumsRequest('Changed view')
},

computed: {
...mapGetters([
'albums',
Expand All @@ -66,10 +61,7 @@ export default {
this.loadingAlbums = true
this.errorFetchingAlbums = null

const { request, cancel } = cancelableRequest(client.getDirectoryContents)
this.cancelAlbumsRequest = cancel

const response = await request(`/photos/${getCurrentUser()?.uid}/albums`, {
const response = await client.getDirectoryContents(`/photos/${getCurrentUser()?.uid}/albums`, {
data: `<?xml version="1.0"?>
<d:propfind xmlns:d="DAV:"
xmlns:oc="http://owncloud.org/ns"
Expand All @@ -83,8 +75,9 @@ export default {
</d:prop>
</d:propfind>`,
details: true,

signal: abortController.signal,
})

const albums = response.data
.filter(album => album.filename !== '/photos/admin/albums')
.map(album => genFileInfo(album))
Expand Down Expand Up @@ -121,7 +114,6 @@ export default {
logger.error(t('photos', 'Failed to fetch albums list.'), error)
showError(t('photos', 'Failed to fetch albums list.'))
} finally {
this.cancelAlbumsRequest = () => { }
this.loadingAlbums = false
}
},
Expand Down
24 changes: 6 additions & 18 deletions src/mixins/FetchFacesMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ import { getCurrentUser } from '@nextcloud/auth'

import client from '../services/DavClient.js'
import logger from '../services/logger.js'
import cancelableRequest from '../utils/CancelableRequest.js'
import DavRequest from '../services/DavRequest'
import { genFileInfo } from '../utils/fileUtils'
import { abortController } from '../services/RequestHandler'

export default {
name: 'FetchFacesMixin',
Expand All @@ -40,20 +40,13 @@ export default {
loadingFaces: false,
errorFetchingFiles: null,
loadingFiles: false,
cancelFacesRequest: () => { },
cancelFilesRequest: () => {},
}
},

async beforeMount() {
this.fetchFaces()
},

beforeDestroy() {
this.cancelFacesRequest('Changed view')
this.cancelFilesRequest('Changed view')
},

computed: {
...mapGetters([
'faces',
Expand All @@ -78,10 +71,9 @@ export default {
this.loadingFaces = true
this.errorFetchingFaces = null

const { request, cancel } = cancelableRequest(client.getDirectoryContents)
this.cancelFacesRequest = cancel

const faces = await request(`/recognize/${getCurrentUser()?.uid}/faces/`)
const faces = await client.getDirectoryContents(`/recognize/${getCurrentUser()?.uid}/faces/`, {
signal: abortController.signal,
})
this.$store.dispatch('addFaces', { faces })
logger.debug(`[FetchFacesMixin] Fetched ${faces.length} new faces: `, faces)
} catch (error) {
Expand All @@ -95,7 +87,6 @@ export default {
logger.error(t('photos', 'Failed to fetch faces list.'), error)
showError(t('photos', 'Failed to fetch faces list.'))
} finally {
this.cancelFacesRequest = () => { }
this.loadingFaces = false
}
},
Expand All @@ -113,14 +104,12 @@ export default {
this.errorFetchingFiles = null
this.loadingFiles = true

const { request, cancel } = cancelableRequest(client.getDirectoryContents)
this.cancelFilesRequest = cancel

let { data: fetchedFiles } = await request(
let { data: fetchedFiles } = await client.getDirectoryContents(
`/recognize/${getCurrentUser()?.uid}/faces/${faceName}`,
{
data: DavRequest,
details: true,
signal: abortController.signal,
}
)

Expand Down Expand Up @@ -150,7 +139,6 @@ export default {
logger.error('Error fetching face files', error)
} finally {
this.loadingFiles = false
this.cancelFilesRequest = () => { }
}
},
},
Expand Down
24 changes: 3 additions & 21 deletions src/mixins/FetchFilesMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@

import logger from '../services/logger.js'
import getPhotos from '../services/PhotoSearch.js'
import cancelableRequest from '../utils/CancelableRequest.js'
import SemaphoreWithPriority from '../utils/semaphoreWithPriority.js'
import { abortController } from '../services/RequestHandler'

export default {
name: 'FetchFilesMixin',
Expand All @@ -33,27 +33,13 @@ export default {
errorFetchingFiles: null,
loadingFiles: false,
doneFetchingFiles: false,
cancelFilesRequest: () => { },
semaphore: new SemaphoreWithPriority(30),
fetchSemaphore: new SemaphoreWithPriority(1),
semaphoreSymbol: null,
fetchedFileIds: [],
}
},

beforeDestroy() {
if (this.cancelFilesRequest) {
this.cancelFilesRequest('Changed view')
}
},

beforeRouteLeave(from, to, next) {
if (this.cancelFilesRequest) {
this.cancelFilesRequest('Changed view')
}
return next()
},

watch: {
$route() {
this.resetFetchFilesState()
Expand All @@ -80,16 +66,14 @@ export default {
this.loadingFiles = true
this.semaphoreSymbol = semaphoreSymbol

const { request, cancel } = cancelableRequest(getPhotos)
this.cancelFilesRequest = cancel

const numberOfImagesPerBatch = 1000

// Load next batch of images
const fetchedFiles = await request(path, {
const fetchedFiles = await getPhotos(path, {
firstResult: this.fetchedFileIds.length,
nbResults: numberOfImagesPerBatch,
...options,
signal: abortController.signal,
})

// If we get less files than requested that means we got to the end
Expand Down Expand Up @@ -126,7 +110,6 @@ export default {
console.error(error)
} finally {
this.loadingFiles = false
this.cancelFilesRequest = () => { }
this.semaphore.release(semaphoreSymbol)
this.fetchSemaphore.release(fetchSemaphoreSymbol)
}
Expand All @@ -139,7 +122,6 @@ export default {
this.errorFetchingFiles = null
this.loadingFiles = false
this.fetchedFileIds = []
this.cancelFilesRequest = () => { }
},
},
}
10 changes: 9 additions & 1 deletion src/router/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import areTagsInstalled from '../services/AreTagsInstalled.js'
import { imageMimes, videoMimes } from '../services/AllowedMimes.js'

import isRecognizeInstalled from '../services/IsRecognizeInstalled.js'
import { cancelAll } from '../services/RequestHandler.js'

const Folders = () => import('../views/Folders')
const Albums = () => import('../views/Albums')
Expand Down Expand Up @@ -56,7 +57,7 @@ const parsePathParams = (path) => {
return `/${Array.isArray(path) ? path.join('/') : path || ''}`
}

export default new Router({
const router = new Router({
mode: 'history',
// if index.php is in the url AND we got this far, then it's working:
// let's keep using index.php in the url
Expand Down Expand Up @@ -179,3 +180,10 @@ export default new Router({
},
],
})

router.beforeResolve((from, to, next) => {
cancelAll()
next()
})

export default router
9 changes: 9 additions & 0 deletions src/services/RequestHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export let abortController = new AbortController()

/**
* Cancel all running http requests
*/
export function cancelAll() {
abortController.abort()
abortController = new AbortController()
}
Loading