import crc32 from 'buffer-crc32' ; export default class HttpMap { url : string ; constructor ( args ) { this . url = /\/$/ . test ( args . url ) ? args . url : `${ args . url }/` ; } /**
     * loads meta.json file from names directory and reads number of hash_bits used
     */ async readMeta ( ) { const meta = await this . loadFile ( 'meta.json' ) ; const { compress , track_names : tracks } = meta ; const hashHexCharacters = Math . ceil ( meta . hash_bits / 4 ) ; return { hashHexCharacters , compress , tracks } ; } async getHashHexCharacters ( ) { const meta = await this . readMeta ( ) ; return meta . hashHexCharacters ; } async getCompress ( ) { const meta = await this . readMeta ( ) ; return meta . compress ; } async getTrackNames ( ) { const meta = await this . readMeta ( ) ; return meta . tracks ; } param key async get ( key ) { const bucket = await this . getBucket ( key ) ; return bucket [ key ] ; } param key async getBucket ( key ) { const bucketIdent = this . hash ( key ) ; const hexToDirPath = await this . hexToDirPath ( bucketIdent ) ; return this . loadFile ( hexToDirPath ) ; } param id async loadFile ( id ) { const response = await fetch ( `${ this . url }${ id }` ) ; if ( ! response . ok ) { throw new Error ( `HTTP ${ response . status } ${ response . statusText }` ) ; } return response . json ( ) ; } param hex async hexToDirPath ( hex ) { const hashHexCharacters = await this . getHashHexCharacters ( ) ; if ( hashHexCharacters ) { const compress = await this . getCompress ( ) ; while ( hex . length < 8 ) { hex = `0${ hex }` ; } hex = hex . substr ( 8 - hashHexCharacters ) ; const dirpath = [ ] ; for ( let i = 0 ; i < hex . length ; i += 3 ) { dirpath . push ( hex . substring ( i , i + 3 ) ) ; } return `${ dirpath . join ( '/' ) }.json${ compress ? 'z' : '' }` ; } return '' ; } hash ( data ) { return crc32 ( Buffer . from ( data ) ) . toString ( 'hex' ) . toLowerCase ( ) . replace ( '-' , 'n' ) ; } }