-
Notifications
You must be signed in to change notification settings - Fork 1
Streaming bed file in analyzer #259
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: master
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 | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,112 @@ | ||||||||||||||
| import init, { | ||||||||||||||
| bedParserNew, | ||||||||||||||
| bedParserUpdate, | ||||||||||||||
| bedParserFinish, | ||||||||||||||
| bedParserFree, | ||||||||||||||
| } from '@databio/gtars'; | ||||||||||||||
|
|
||||||||||||||
| let wasmReady = false; | ||||||||||||||
|
|
||||||||||||||
| async function ensureWasm() { | ||||||||||||||
| if (wasmReady) return; | ||||||||||||||
| await init(); | ||||||||||||||
| wasmReady = true; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| async function processStream( | ||||||||||||||
| reader: ReadableStreamDefaultReader<Uint8Array>, | ||||||||||||||
| totalSize: number, | ||||||||||||||
| parser: number, | ||||||||||||||
| ) { | ||||||||||||||
| let bytesProcessed = 0; | ||||||||||||||
|
|
||||||||||||||
| while (true) { | ||||||||||||||
| const { done, value } = await reader.read(); | ||||||||||||||
| if (done) break; | ||||||||||||||
|
|
||||||||||||||
| bedParserUpdate(parser, value); | ||||||||||||||
|
|
||||||||||||||
| bytesProcessed += value.length; | ||||||||||||||
| self.postMessage({ | ||||||||||||||
| type: 'progress', | ||||||||||||||
| bytesProcessed, | ||||||||||||||
| totalSize, | ||||||||||||||
| percent: totalSize > 0 ? Math.round((100 * bytesProcessed) / totalSize) : -1, | ||||||||||||||
| }); | ||||||||||||||
|
Comment on lines
+29
to
+35
|
||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| async function processFile(file: File) { | ||||||||||||||
| self.postMessage({ type: 'status', message: 'Loading WASM module...' }); | ||||||||||||||
| await ensureWasm(); | ||||||||||||||
|
|
||||||||||||||
| const parser = bedParserNew(); | ||||||||||||||
|
|
||||||||||||||
| try { | ||||||||||||||
| self.postMessage({ type: 'status', message: 'Processing file...' }); | ||||||||||||||
|
|
||||||||||||||
| const stream = file.stream(); | ||||||||||||||
| const reader = stream.getReader(); | ||||||||||||||
| await processStream(reader, file.size, parser); | ||||||||||||||
|
|
||||||||||||||
| self.postMessage({ type: 'status', message: 'Building RegionSet...' }); | ||||||||||||||
| const entries = bedParserFinish(parser); | ||||||||||||||
|
|
||||||||||||||
| self.postMessage({ type: 'result', entries }); | ||||||||||||||
| } catch (err) { | ||||||||||||||
| bedParserFree(parser); | ||||||||||||||
| throw err; | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| async function processUrl(url: string) { | ||||||||||||||
| self.postMessage({ type: 'status', message: 'Loading WASM module...' }); | ||||||||||||||
| await ensureWasm(); | ||||||||||||||
|
|
||||||||||||||
| self.postMessage({ type: 'status', message: 'Fetching file...' }); | ||||||||||||||
|
|
||||||||||||||
| const fetchUrl = | ||||||||||||||
| url.length === 32 && !url.startsWith('http') | ||||||||||||||
| ? `https://api.bedbase.org/v1/files/files/${url[0]}/${url[1]}/${url}.bed.gz` | ||||||||||||||
| : url; | ||||||||||||||
|
|
||||||||||||||
| const response = await fetch(fetchUrl); | ||||||||||||||
| if (!response.ok) { | ||||||||||||||
| throw new Error(`Failed to fetch BED file: ${response.statusText}`); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| const parser = bedParserNew(); | ||||||||||||||
|
|
||||||||||||||
| try { | ||||||||||||||
| self.postMessage({ type: 'status', message: 'Processing file...' }); | ||||||||||||||
|
|
||||||||||||||
| const contentLength = response.headers.get('content-length'); | ||||||||||||||
| const totalSize = contentLength ? parseInt(contentLength, 10) : 0; | ||||||||||||||
| const reader = response.body!.getReader(); | ||||||||||||||
|
||||||||||||||
| const reader = response.body!.getReader(); | |
| const body = response.body; | |
| if (!body) { | |
| throw new Error('Failed to process BED file: response body is not available as a readable stream.'); | |
| } | |
| const reader = body.getReader(); |
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.
This effect calls initializeAnalysis but doesn’t include it in the dependency array. With
plugin:react-hooks/recommendedenabled and--max-warnings 0, this will fail lint due toreact-hooks/exhaustive-deps. Refactor so the effect satisfies exhaustive-deps without changing the intended “only run when triggerSearch changes” behavior (e.g., make initializeAnalysis stable via refs, or restructure the effect logic accordingly).