-
Notifications
You must be signed in to change notification settings - Fork 48
fix(opencv): Handle delayed cv.ready and add timeout #1489
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,16 +3,79 @@ | |
|
|
||
| import type { OpenCVTypes } from '../opencv/interfaces'; | ||
|
|
||
| const READY_CHECK_INTERVAL_MS = 100; | ||
| const OPENCV_LOAD_TIMEOUT_MS = 30_000; | ||
|
|
||
| let opencv: OpenCVTypes | null = null; | ||
| let loadingPromise: Promise<OpenCVTypes> | null = null; | ||
|
|
||
| function delay(ms: number): Promise<void> { | ||
| return new Promise((resolve) => setTimeout(resolve, ms)); | ||
| } | ||
|
|
||
| /** | ||
| * Wait for cv.ready to be available with polling | ||
| * Some OpenCV builds delay initialization of cv.ready | ||
| */ | ||
| const waitForOpenCVReady = async (cv: OpenCVTypes): Promise<void> => { | ||
| const startTime = Date.now(); | ||
|
|
||
| while (Date.now() - startTime < OPENCV_LOAD_TIMEOUT_MS) { | ||
| // Check if cv.ready exists and is a Promise-like object | ||
| if (cv && typeof cv.ready === 'object' && 'then' in cv.ready) { | ||
| try { | ||
| await cv.ready; | ||
| return; // Success | ||
| } catch (error) { | ||
| console.error('Error waiting for cv.ready:', error); | ||
| throw error; | ||
| } | ||
| } | ||
|
|
||
| // Check if cv.ready is already resolved (some builds may have it pre-resolved) | ||
| if (cv && cv.onload && typeof cv.onload === 'function') { | ||
| return; | ||
| } | ||
|
|
||
| // cv.ready not available yet, wait and retry | ||
| await delay(READY_CHECK_INTERVAL_MS); | ||
| } | ||
|
|
||
| throw new Error( | ||
| `Timeout waiting for cv.ready (${OPENCV_LOAD_TIMEOUT_MS}ms). ` + | ||
| 'OpenCV may not be properly built or the file is corrupted.' | ||
| ); | ||
| }; | ||
|
|
||
| export const OpenCVLoader = async (): Promise<OpenCVTypes> => { | ||
| if (opencv) return opencv; | ||
| if (loadingPromise) return loadingPromise; | ||
|
|
||
| const cv: OpenCVTypes = await import('../opencv/4.9.0/opencv.js'); | ||
| loadingPromise = Promise.race([ | ||
| (async () => { | ||
| try { | ||
| const cv: OpenCVTypes = await import('../opencv/4.9.0/opencv.js'); | ||
|
|
||
| if ('ready' in cv) await cv.ready; | ||
| // Wait for cv.ready with polling and timeout | ||
| await waitForOpenCVReady(cv); | ||
|
|
||
| opencv = cv; | ||
| if (!cv.Mat) { | ||
| throw new Error('OpenCV missing essential methods'); | ||
| } | ||
| opencv = cv; | ||
| return opencv; | ||
| } catch (error) { | ||
| loadingPromise = null; | ||
| throw error; | ||
| } | ||
| })(), | ||
| new Promise<never>((_, reject) => | ||
| setTimeout( | ||
| () => reject(new Error(`OpenCV loading timeout (${OPENCV_LOAD_TIMEOUT_MS}ms)`)), | ||
| OPENCV_LOAD_TIMEOUT_MS | ||
| ) | ||
| ), | ||
| ]); | ||
|
Comment on lines
+54
to
+78
|
||
|
|
||
| return opencv; | ||
| return loadingPromise; | ||
| }; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The check for
cv.onloadis ineffective for determining if OpenCV is ready. The presence of anonloadfunction doesn't guarantee initialization is complete. This could lead to returning before OpenCV is actually ready to use, causing subsequent operations to fail.