Skip to content

Commit 120ba8c

Browse files
committed
fix(filen-mobile): prevent concurrent thumbnail generation with isGeneratingRef guard
Add a ref-based mutex to prevent overlapping generate() calls when multiple triggers fire (AppState, httpStore, recycling). Reset the flag in all cleanup paths (recycling, background, port loss, unmount) to avoid stale locks after abort.
1 parent 318c6c5 commit 120ba8c

File tree

1 file changed

+56
-33
lines changed

1 file changed

+56
-33
lines changed

packages/filen-mobile/src/components/drive/item/thumbnail.tsx

Lines changed: 56 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ const Thumbnail = memo(
2929
className?: string
3030
}) => {
3131
const abortControllerRef = useRef<AbortController | null>(null)
32-
const errorRetryCountRef = useRef(0)
32+
const errorRetryCountRef = useRef<number>(0)
33+
const isGeneratingRef = useRef<boolean>(false)
3334

3435
const [localPath, setLocalPath] = useRecyclingState<string | null>(
3536
() => {
@@ -53,6 +54,7 @@ const Thumbnail = memo(
5354

5455
abortControllerRef.current = null
5556
errorRetryCountRef.current = 0
57+
isGeneratingRef.current = false
5658
}
5759
)
5860

@@ -63,54 +65,72 @@ const Thumbnail = memo(
6365
}, [localPath])
6466

6567
const generate = useCallback(async () => {
66-
if (
67-
localPathRef.current ||
68-
(item.type !== "file" && item.type !== "sharedFile") ||
69-
!thumbnails.canGenerate(item) ||
70-
AppState.currentState !== "active"
71-
) {
72-
return
73-
}
68+
const result = await run(async defer => {
69+
if (isGeneratingRef.current) {
70+
return
71+
}
7472

75-
abortControllerRef.current?.abort()
76-
errorRetryCountRef.current = 0
77-
abortControllerRef.current = new AbortController()
73+
isGeneratingRef.current = true
7874

79-
const signal = abortControllerRef.current.signal
80-
let lastError: unknown
75+
defer(() => {
76+
isGeneratingRef.current = false
77+
})
8178

82-
for (let attempt = 0; attempt < MAX_GENERATE_RETRIES; attempt++) {
83-
if (signal.aborted || AppState.currentState !== "active") {
79+
if (
80+
localPathRef.current ||
81+
(item.type !== "file" && item.type !== "sharedFile") ||
82+
!thumbnails.canGenerate(item) ||
83+
AppState.currentState !== "active"
84+
) {
8485
return
8586
}
8687

87-
const result = await run(async () => {
88-
return await thumbnails.generate({
89-
item,
90-
signal
88+
abortControllerRef.current?.abort()
89+
errorRetryCountRef.current = 0
90+
abortControllerRef.current = new AbortController()
91+
92+
const signal = abortControllerRef.current.signal
93+
let lastError: unknown
94+
95+
for (let attempt = 0; attempt < MAX_GENERATE_RETRIES; attempt++) {
96+
if (signal.aborted || AppState.currentState !== "active") {
97+
return
98+
}
99+
100+
const result = await run(async () => {
101+
return await thumbnails.generate({
102+
item,
103+
signal
104+
})
91105
})
92-
})
93106

94-
if (signal.aborted) {
95-
return
96-
}
107+
if (signal.aborted) {
108+
return
109+
}
97110

98-
if (result.success) {
99-
cache.availableThumbnails.set(item.data.uuid, true)
111+
if (result.success) {
112+
cache.availableThumbnails.set(item.data.uuid, true)
100113

101-
setLocalPath(result.data)
114+
setLocalPath(result.data)
102115

103-
return
116+
return
117+
}
118+
119+
lastError = result.error
120+
121+
await new Promise<void>(resolve => setTimeout(resolve, 1000))
104122
}
105123

106-
lastError = result.error
124+
console.error(lastError)
107125

108-
await new Promise<void>(resolve => setTimeout(resolve, 1000))
109-
}
126+
cache.availableThumbnails.set(item.data.uuid, false)
127+
})
110128

111-
console.error(lastError)
129+
if (!result.success) {
130+
console.error(result.error)
112131

113-
cache.availableThumbnails.set(item.data.uuid, false)
132+
return
133+
}
114134
}, [item, setLocalPath])
115135

116136
const generateRef = useRef(generate)
@@ -157,6 +177,7 @@ const Thumbnail = memo(
157177

158178
abortControllerRef.current = null
159179
errorRetryCountRef.current = 0
180+
isGeneratingRef.current = false
160181
}
161182
})
162183

@@ -174,6 +195,7 @@ const Thumbnail = memo(
174195

175196
abortControllerRef.current = null
176197
errorRetryCountRef.current = 0
198+
isGeneratingRef.current = false
177199
}
178200
}
179201
)
@@ -194,6 +216,7 @@ const Thumbnail = memo(
194216

195217
abortControllerRef.current = null
196218
errorRetryCountRef.current = 0
219+
isGeneratingRef.current = false
197220
}
198221
}, [])
199222

0 commit comments

Comments
 (0)