Skip to content

Commit ca0aef4

Browse files
committed
Refactor: Use a global AbortController to cancel requests on route changes
Signed-off-by: Marcel Klehr <[email protected]>
1 parent ce20da5 commit ca0aef4

12 files changed

Lines changed: 55 additions & 216 deletions

File tree

src/components/FaceCover.vue

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,6 @@ export default {
103103
await this.fetchFiles()
104104
},
105105
106-
beforeDestroy() {
107-
this.cancelFilesRequest('Changed view')
108-
},
109-
110106
methods: {
111107
async fetchFiles() {
112108
await this.fetchFaceContent(this.face.basename)

src/components/Folder.vue

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232
import { mapGetters } from 'vuex'
3333
3434
import getAlbumContent from '../services/AlbumContent'
35-
import cancelableRequest from '../utils/CancelableRequest'
3635
import FolderTagPreview from './FolderTagPreview'
36+
import { abortController } from '../services/RequestHandler'
3737
3838
export default {
3939
name: 'Folder',
@@ -52,7 +52,6 @@ export default {
5252
5353
data() {
5454
return {
55-
cancelRequest: null,
5655
previewFolder: this.item.injected.fileid,
5756
}
5857
},
@@ -101,31 +100,20 @@ export default {
101100
}
102101
},
103102
104-
beforeDestroy() {
105-
// cancel any pending requests
106-
if (this.cancelRequest) {
107-
this.cancelRequest('Navigated away')
108-
}
109-
},
110-
111103
methods: {
112104
async getFolderData(filename) {
113-
// init cancellable request
114-
const { request, cancel } = cancelableRequest(getAlbumContent)
115-
this.cancelRequest = cancel
116-
117105
try {
118106
// get data
119-
const { folder, folders, files } = await request(filename, { shared: this.item.injected.showShared })
107+
const { folder, folders, files } = await getAlbumContent(filename, {
108+
shared: this.item.injected.showShared,
109+
signal: abortController.signal,
110+
})
120111
this.$store.dispatch('updateFolders', { fileid: folder.fileid, files, folders })
121112
this.$store.dispatch('updateFiles', { folder, files, folders })
122113
} catch (error) {
123114
if (error.response && error.response.status) {
124115
console.error('Failed to get folder content', filename, error.response)
125116
}
126-
// else we just cancelled the request
127-
} finally {
128-
this.cancelRequest = null
129117
}
130118
},
131119

src/components/Tag.vue

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@
3333
import { mapGetters } from 'vuex'
3434
3535
import getTaggedImages from '../services/TaggedImages'
36-
import cancelableRequest from '../utils/CancelableRequest'
3736
import FolderTagPreview from './FolderTagPreview'
37+
import { abortController } from '../services/RequestHandler'
3838
3939
export default {
4040
name: 'Tag',
@@ -51,12 +51,6 @@ export default {
5151
},
5252
},
5353
54-
data() {
55-
return {
56-
cancelRequest: null,
57-
}
58-
},
59-
6054
computed: {
6155
// global lists
6256
...mapGetters([
@@ -78,29 +72,18 @@ export default {
7872
},
7973
},
8074
81-
beforeDestroy() {
82-
// cancel any pending requests
83-
if (this.cancelRequest) {
84-
this.cancelRequest('Navigated away')
85-
}
86-
},
87-
8875
async created() {
89-
// init cancellable request
90-
const { request, cancel } = cancelableRequest(getTaggedImages)
91-
this.cancelRequest = cancel
92-
9376
try {
9477
// get data
95-
const files = await request(this.item.injected.id)
78+
const files = await getTaggedImages(this.item.injected.id, {
79+
signal: abortController.signal,
80+
})
9681
this.$store.dispatch('updateTag', { id: this.item.injected.id, files })
9782
this.$store.dispatch('appendFiles', files)
9883
} catch (error) {
9984
if (error.response && error.response.status) {
10085
console.error('Failed to get folder content', this.item.injected.id, error.response)
10186
}
102-
} finally {
103-
this.cancelRequest = null
10487
}
10588
},
10689

src/mixins/FetchAlbumsMixin.js

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ import { getCurrentUser } from '@nextcloud/auth'
2828

2929
import client from '../services/DavClient.js'
3030
import logger from '../services/logger.js'
31-
import cancelableRequest from '../utils/CancelableRequest.js'
3231
import { genFileInfo } from '../utils/fileUtils.js'
32+
import { abortController } from '../services/RequestHandler'
3333

3434
export default {
3535
name: 'FetchAlbumsMixin',
@@ -38,18 +38,13 @@ export default {
3838
return {
3939
errorFetchingAlbums: null,
4040
loadingAlbums: false,
41-
cancelAlbumsRequest: () => { },
4241
}
4342
},
4443

4544
async beforeMount() {
4645
this.fetchAlbums()
4746
},
4847

49-
beforeDestroy() {
50-
this.cancelAlbumsRequest('Changed view')
51-
},
52-
5348
computed: {
5449
...mapGetters([
5550
'albums',
@@ -66,10 +61,7 @@ export default {
6661
this.loadingAlbums = true
6762
this.errorFetchingAlbums = null
6863

69-
const { request, cancel } = cancelableRequest(client.getDirectoryContents)
70-
this.cancelAlbumsRequest = cancel
71-
72-
const response = await request(`/photos/${getCurrentUser()?.uid}/albums`, {
64+
const response = await client.getDirectoryContents(`/photos/${getCurrentUser()?.uid}/albums`, {
7365
data: `<?xml version="1.0"?>
7466
<d:propfind xmlns:d="DAV:"
7567
xmlns:oc="http://owncloud.org/ns"
@@ -83,8 +75,9 @@ export default {
8375
</d:prop>
8476
</d:propfind>`,
8577
details: true,
86-
78+
signal: abortController.signal,
8779
})
80+
8881
const albums = response.data
8982
.filter(album => album.filename !== '/photos/admin/albums')
9083
.map(album => genFileInfo(album))
@@ -121,7 +114,6 @@ export default {
121114
logger.error(t('photos', 'Failed to fetch albums list.'), error)
122115
showError(t('photos', 'Failed to fetch albums list.'))
123116
} finally {
124-
this.cancelAlbumsRequest = () => { }
125117
this.loadingAlbums = false
126118
}
127119
},

src/mixins/FetchFacesMixin.js

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ import { getCurrentUser } from '@nextcloud/auth'
2727

2828
import client from '../services/DavClient.js'
2929
import logger from '../services/logger.js'
30-
import cancelableRequest from '../utils/CancelableRequest.js'
3130
import DavRequest from '../services/DavRequest'
3231
import { genFileInfo } from '../utils/fileUtils'
32+
import { abortController } from '../services/RequestHandler'
3333

3434
export default {
3535
name: 'FetchFacesMixin',
@@ -40,20 +40,13 @@ export default {
4040
loadingFaces: false,
4141
errorFetchingFiles: null,
4242
loadingFiles: false,
43-
cancelFacesRequest: () => { },
44-
cancelFilesRequest: () => {},
4543
}
4644
},
4745

4846
async beforeMount() {
4947
this.fetchFaces()
5048
},
5149

52-
beforeDestroy() {
53-
this.cancelFacesRequest('Changed view')
54-
this.cancelFilesRequest('Changed view')
55-
},
56-
5750
computed: {
5851
...mapGetters([
5952
'faces',
@@ -78,10 +71,9 @@ export default {
7871
this.loadingFaces = true
7972
this.errorFetchingFaces = null
8073

81-
const { request, cancel } = cancelableRequest(client.getDirectoryContents)
82-
this.cancelFacesRequest = cancel
83-
84-
const faces = await request(`/recognize/${getCurrentUser()?.uid}/faces/`)
74+
const faces = await client.getDirectoryContents(`/recognize/${getCurrentUser()?.uid}/faces/`, {
75+
signal: abortController.signal,
76+
})
8577
this.$store.dispatch('addFaces', { faces })
8678
logger.debug(`[FetchFacesMixin] Fetched ${faces.length} new faces: `, faces)
8779
} catch (error) {
@@ -95,7 +87,6 @@ export default {
9587
logger.error(t('photos', 'Failed to fetch faces list.'), error)
9688
showError(t('photos', 'Failed to fetch faces list.'))
9789
} finally {
98-
this.cancelFacesRequest = () => { }
9990
this.loadingFaces = false
10091
}
10192
},
@@ -113,14 +104,12 @@ export default {
113104
this.errorFetchingFiles = null
114105
this.loadingFiles = true
115106

116-
const { request, cancel } = cancelableRequest(client.getDirectoryContents)
117-
this.cancelFilesRequest = cancel
118-
119-
let { data: fetchedFiles } = await request(
107+
let { data: fetchedFiles } = await client.getDirectoryContents(
120108
`/recognize/${getCurrentUser()?.uid}/faces/${faceName}`,
121109
{
122110
data: DavRequest,
123111
details: true,
112+
signal: abortController.signal,
124113
}
125114
)
126115

@@ -150,7 +139,6 @@ export default {
150139
logger.error('Error fetching face files', error)
151140
} finally {
152141
this.loadingFiles = false
153-
this.cancelFilesRequest = () => { }
154142
}
155143
},
156144
},

src/mixins/FetchFilesMixin.js

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222

2323
import logger from '../services/logger.js'
2424
import getPhotos from '../services/PhotoSearch.js'
25-
import cancelableRequest from '../utils/CancelableRequest.js'
2625
import SemaphoreWithPriority from '../utils/semaphoreWithPriority.js'
26+
import { abortController } from '../services/RequestHandler'
2727

2828
export default {
2929
name: 'FetchFilesMixin',
@@ -33,27 +33,13 @@ export default {
3333
errorFetchingFiles: null,
3434
loadingFiles: false,
3535
doneFetchingFiles: false,
36-
cancelFilesRequest: () => { },
3736
semaphore: new SemaphoreWithPriority(30),
3837
fetchSemaphore: new SemaphoreWithPriority(1),
3938
semaphoreSymbol: null,
4039
fetchedFileIds: [],
4140
}
4241
},
4342

44-
beforeDestroy() {
45-
if (this.cancelFilesRequest) {
46-
this.cancelFilesRequest('Changed view')
47-
}
48-
},
49-
50-
beforeRouteLeave(from, to, next) {
51-
if (this.cancelFilesRequest) {
52-
this.cancelFilesRequest('Changed view')
53-
}
54-
return next()
55-
},
56-
5743
watch: {
5844
$route() {
5945
this.resetFetchFilesState()
@@ -80,16 +66,14 @@ export default {
8066
this.loadingFiles = true
8167
this.semaphoreSymbol = semaphoreSymbol
8268

83-
const { request, cancel } = cancelableRequest(getPhotos)
84-
this.cancelFilesRequest = cancel
85-
8669
const numberOfImagesPerBatch = 1000
8770

8871
// Load next batch of images
89-
const fetchedFiles = await request(path, {
72+
const fetchedFiles = await getPhotos(path, {
9073
firstResult: this.fetchedFileIds.length,
9174
nbResults: numberOfImagesPerBatch,
9275
...options,
76+
signal: abortController.signal,
9377
})
9478

9579
// If we get less files than requested that means we got to the end
@@ -125,7 +109,6 @@ export default {
125109
logger.error('Error fetching files', error)
126110
} finally {
127111
this.loadingFiles = false
128-
this.cancelFilesRequest = () => { }
129112
this.semaphore.release(semaphoreSymbol)
130113
this.fetchSemaphore.release(fetchSemaphoreSymbol)
131114
}
@@ -138,7 +121,6 @@ export default {
138121
this.errorFetchingFiles = null
139122
this.loadingFiles = false
140123
this.fetchedFileIds = []
141-
this.cancelFilesRequest = () => { }
142124
},
143125
},
144126
}

src/router/index.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import areTagsInstalled from '../services/AreTagsInstalled.js'
2929
import { imageMimes, videoMimes } from '../services/AllowedMimes.js'
3030

3131
import isRecognizeInstalled from '../services/IsRecognizeInstalled.js'
32+
import { cancelAll } from '../services/RequestHandler.js'
3233

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

59-
export default new Router({
60+
const router = new Router({
6061
mode: 'history',
6162
// if index.php is in the url AND we got this far, then it's working:
6263
// let's keep using index.php in the url
@@ -179,3 +180,10 @@ export default new Router({
179180
},
180181
],
181182
})
183+
184+
router.beforeResolve((from, to, next) => {
185+
cancelAll()
186+
next()
187+
})
188+
189+
export default router

src/services/RequestHandler.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export let abortController = new AbortController()
2+
3+
/**
4+
* Cancel all running http requests
5+
*/
6+
export function cancelAll() {
7+
abortController.abort()
8+
abortController = new AbortController()
9+
}

0 commit comments

Comments
 (0)