import type { ArrayShape , AttributeValues , Dataset , Entity , NumericType , } from '@h5web/shared' ; import type { AxiosInstance , AxiosRequestConfig , AxiosResponse , CancelTokenSource , ResponseType , } from 'axios' ; import axios from 'axios' ; import type { ExportFormat , ProgressCallback , ValuesStoreParams , } from './models' ; import { CANCELLED_ERROR_MSG } from './utils' ; interface ValueRequest { storeParams : ValuesStoreParams ; cancelSource : CancelTokenSource ; } export abstract class ProviderApi { public readonly filepath : string ; public readonly cancelledValueRequests = new Set < ValueRequest > ( ) ; protected readonly client : AxiosInstance ; protected readonly valueRequests = new Set < ValueRequest > ( ) ; protected progress = new Map < ValuesStoreParams , number > ( ) ; private readonly progressListeners = new Set < ProgressCallback > ( ) ; public constructor ( filepath , config ? ) { this . filepath = filepath ; this . client = axios . create ( config ) ; } public getExportURL ? ( dataset , selection , format ) ; public addProgressListener ( cb ) { this . progressListeners . add ( cb ) ; cb ( [ ... this . progress . values ( ) ] ) ; } public removeProgressListener ( cb ) { this . progressListeners . delete ( cb ) ; } public cancelValueRequests ( ) { this . valueRequests . forEach ( ( request ) => { request . cancelSource . cancel ( CANCELLED_ERROR_MSG ) ; this . cancelledValueRequests . add ( request ) ; } ) ; this . valueRequests . clear ( ) ; } protected async cancellableFetchValue < T > ( endpoint , storeParams , queryParams , responseType ? ) { const cancelSource = axios . CancelToken . source ( ) ; const request = { storeParams , cancelSource } ; this . valueRequests . add ( request ) ; this . progress . set ( storeParams , 0 ) ; this . notifyProgressChange ( ) ; try { const { token : cancelToken } = cancelSource ; return await this . client . get < T > ( endpoint , { cancelToken , params : queryParams , responseType , onDownloadProgress : ( evt ) => { if ( evt . lengthComputable ) { this . progress . set ( storeParams , evt . loaded / evt . total ) ; this . notifyProgressChange ( ) ; } } , } ) ; } finally { this . valueRequests . delete ( request ) ; this . progress . delete ( storeParams ) ; this . notifyProgressChange ( ) ; } } private notifyProgressChange ( ) { this . progressListeners . forEach ( ( cb ) => cb ( [ ... this . progress . values ( ) ] ) ) ; } public abstract getEntity ( path ) ; public abstract getValue ( params ) ; public abstract getAttrValues ( entity ) ; }