@@ -13,6 +13,39 @@ function getMessage(e: unknown) {
1313 return r . replace ( / \. $ / , '' )
1414}
1515
16+ export function toLocale ( n : number ) {
17+ return n . toLocaleString ( 'en-US' )
18+ }
19+
20+ function r ( s : number ) {
21+ return toLocale ( Number . parseFloat ( s . toPrecision ( 3 ) ) )
22+ }
23+ function sum ( array : Uint8Array [ ] ) {
24+ let sum = 0
25+ for ( const entry of array ) {
26+ sum += entry . length
27+ }
28+ return sum
29+ }
30+ function concatUint8Array ( args : Uint8Array [ ] ) {
31+ const mergedArray = new Uint8Array ( sum ( args ) )
32+ let offset = 0
33+ for ( const entry of args ) {
34+ mergedArray . set ( entry , offset )
35+ offset += entry . length
36+ }
37+ return mergedArray
38+ }
39+ export function getProgressDisplayStr ( current : number , total : number ) {
40+ if ( Math . floor ( total / 1_000_000 ) > 0 ) {
41+ return `${ r ( current / 1_000_000 ) } /${ r ( total / 1_000_000 ) } Mb`
42+ } else if ( Math . floor ( total / 1_000 ) > 0 ) {
43+ return `${ r ( current / 1_000 ) } /${ r ( total / 1_000 ) } Kb`
44+ } else {
45+ return `${ r ( current ) } /${ r ( total ) } }bytes`
46+ }
47+ }
48+
1649export default class RemoteFile implements GenericFilehandle {
1750 protected url : string
1851 private _stat ?: Stats
@@ -89,8 +122,6 @@ export default class RemoteFile implements GenericFilehandle {
89122 }
90123
91124 if ( ( res . status === 200 && position === 0 ) || res . status === 206 ) {
92- const resData = await res . arrayBuffer ( )
93-
94125 // try to parse out the size of the remote file
95126 const contentRange = res . headers . get ( 'content-range' )
96127 const sizeMatch = / \/ ( \d + ) $ / . exec ( contentRange || '' )
@@ -99,8 +130,7 @@ export default class RemoteFile implements GenericFilehandle {
99130 size : parseInt ( sizeMatch [ 1 ] , 10 ) ,
100131 }
101132 }
102-
103- return new Uint8Array ( resData . slice ( 0 , length ) )
133+ return new Uint8Array ( await res . arrayBuffer ( ) )
104134 }
105135
106136 // eslint-disable-next-line unicorn/prefer-ternary
@@ -139,7 +169,7 @@ export default class RemoteFile implements GenericFilehandle {
139169 opts = options
140170 delete opts . encoding
141171 }
142- const { headers = { } , signal, overrides = { } } = opts
172+ const { statusCallback , headers = { } , signal, overrides = { } } = opts
143173 const res = await this . fetch ( this . url , {
144174 headers,
145175 method : 'GET' ,
@@ -152,12 +182,47 @@ export default class RemoteFile implements GenericFilehandle {
152182 if ( res . status !== 200 ) {
153183 throw new Error ( `HTTP ${ res . status } fetching ${ this . url } ` )
154184 }
155- if ( encoding === 'utf8' ) {
156- return res . text ( )
157- } else if ( encoding ) {
158- throw new Error ( `unsupported encoding: ${ encoding } ` )
185+ // Get the total size for progress reporting
186+ const contentLength = res . headers . get ( 'content-length' )
187+ const totalBytes = contentLength ? parseInt ( contentLength , 10 ) : undefined
188+
189+ if ( statusCallback && res . body && totalBytes ) {
190+ const reader = res . body . getReader ( )
191+ const chunks : Uint8Array [ ] = [ ]
192+ let receivedBytes = 0
193+
194+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
195+ while ( true ) {
196+ const { done, value } = await reader . read ( )
197+
198+ if ( done ) {
199+ break
200+ }
201+
202+ chunks . push ( value )
203+ receivedBytes += value . length
204+
205+ statusCallback (
206+ `Downloading ${ getProgressDisplayStr ( receivedBytes , totalBytes ) } ` ,
207+ )
208+ }
209+
210+ if ( encoding === 'utf8' || encoding === 'utf-8' ) {
211+ const decoder = new TextDecoder ( 'utf-8' )
212+ return decoder . decode ( concatUint8Array ( chunks ) )
213+ } else if ( encoding ) {
214+ throw new Error ( `unsupported encoding: ${ encoding } ` )
215+ } else {
216+ return concatUint8Array ( chunks )
217+ }
159218 } else {
160- return new Uint8Array ( await res . arrayBuffer ( ) )
219+ if ( encoding === 'utf8' || encoding === 'utf-8' ) {
220+ return res . text ( )
221+ } else if ( encoding ) {
222+ throw new Error ( `unsupported encoding: ${ encoding } ` )
223+ } else {
224+ return new Uint8Array ( await res . arrayBuffer ( ) )
225+ }
161226 }
162227 }
163228
0 commit comments