1+ import * as base64 from 'base64-js'
2+ import { assert , Type } from './common'
3+ import * as r from '../read'
4+
5+ interface Sig {
6+ sig : string
7+ }
8+ interface SigAndType extends Sig {
9+ type : Type < any >
10+ }
11+ interface TypeCache {
12+ [ name : string ] : SigAndType
13+ }
14+ interface SigAndBuffer extends Sig {
15+ type : string
16+ }
17+ interface ComposedCache {
18+ [ name : string ] : SigAndBuffer
19+ }
20+
21+ const typeCache : TypeCache = { }
22+ function saveTypeCache ( ) {
23+ const composedCache : ComposedCache = { }
24+ for ( const type in typeCache ) {
25+ composedCache [ type ] = {
26+ sig : typeCache [ type ] . sig ,
27+ type : base64 . fromByteArray ( new Uint8Array ( typeCache [ type ] . type . toBuffer ( ) ) )
28+ }
29+ }
30+ localStorage . typeCache = JSON . stringify ( composedCache )
31+ }
32+ if ( localStorage . typeCache ) {
33+ const composedCache : ComposedCache = JSON . parse ( localStorage . typeCache )
34+ for ( const typeName in composedCache ) {
35+ typeCache [ typeName ] = {
36+ sig : composedCache [ typeName ] . sig ,
37+ type : r . type ( base64 . toByteArray ( composedCache [ typeName ] . type ) . buffer )
38+ }
39+ }
40+ }
41+
42+ export interface DownloadOptions {
43+ name : string
44+ url : string
45+ options ?: RequestInit
46+ }
47+ export function download ( { name, url, options} : DownloadOptions ) : Promise < any > {
48+ assert . instanceOf ( name , String )
49+ assert . instanceOf ( url , String )
50+ options = options || { }
51+ assert . instanceOf ( options , Object )
52+ const typeInCache = typeCache [ name ]
53+ if ( typeInCache ) {
54+ if ( options . headers ) {
55+ const { headers} = options
56+ if ( headers . constructor !== Headers ) options . headers = new Headers ( headers )
57+ }
58+ else options . headers = new Headers
59+ ; ( options . headers as Headers ) . set ( 'sig' , typeCache [ name ] . sig )
60+ }
61+ return fetch ( url , options )
62+ . then ( response => {
63+ if ( ! response . ok ) throw new Error ( 'Received status of ' + String ( response . status ) )
64+ const sig = response . headers . get ( 'sig' ) !
65+ if ( typeInCache && typeInCache . sig === sig ) {
66+ return response . arrayBuffer ( )
67+ . then ( buffer => {
68+ const value = r . value ( { buffer, type : typeInCache . type } )
69+ return Promise . resolve ( value )
70+ } )
71+ }
72+ else {
73+ return response . arrayBuffer ( )
74+ . then ( buffer => {
75+ const readType = r . _consumeType ( buffer , 0 )
76+ const type = readType . value
77+ const value = r . value ( { buffer, offset : readType . length , type} )
78+ typeCache [ name ] = { sig, type}
79+ saveTypeCache ( )
80+ return Promise . resolve ( value )
81+ } )
82+ }
83+ } )
84+ }
85+ export * from './common'
86+ ( window as any ) . sb = exports
0 commit comments