diff --git a/src/h5web/providers/Provider.tsx b/src/h5web/providers/Provider.tsx index d7c20aa17..c205a2f41 100644 --- a/src/h5web/providers/Provider.tsx +++ b/src/h5web/providers/Provider.tsx @@ -1,6 +1,7 @@ import { ReactNode, useMemo } from 'react'; import { createFetchStore } from 'react-suspense-fetch'; -import { ProviderApi, ProviderContext } from './context'; +import { ProviderContext } from './context'; +import type { ProviderApi } from './api'; import type { Entity } from './models'; import { isGroup } from '../guards'; diff --git a/src/h5web/providers/api.ts b/src/h5web/providers/api.ts new file mode 100644 index 000000000..ad8837c9c --- /dev/null +++ b/src/h5web/providers/api.ts @@ -0,0 +1,57 @@ +import axios, { + AxiosInstance, + AxiosRequestConfig, + AxiosResponse, + CancelTokenSource, +} from 'axios'; +import { Entity, ProviderError, ValueRequestParams } from './models'; + +interface ValueRequest { + params: ValueRequestParams; + cancelSource: CancelTokenSource; +} + +export abstract class ProviderApi { + public readonly filepath: string; + public readonly cancelledValueRequests = new Set(); + + protected readonly client: AxiosInstance; + protected readonly valueRequests = new Set(); + + public constructor(filepath: string, config?: AxiosRequestConfig) { + this.filepath = filepath; + this.client = axios.create(config); + } + + public cancelValueRequests(): void { + // Cancel every active value request + this.valueRequests.forEach((request) => { + request.cancelSource.cancel(ProviderError.Cancelled); + + // Save request so params can later be evicted from the values store (cf. `Provider.tsx`) + this.cancelledValueRequests.add(request); + }); + + this.valueRequests.clear(); + } + + protected async cancellableFetchValue( + endpoint: string, + params: ValueRequestParams + ): Promise> { + const cancelSource = axios.CancelToken.source(); + const request = { params, cancelSource }; + this.valueRequests.add(request); + + try { + const { token: cancelToken } = cancelSource; + return await this.client.get(endpoint, { cancelToken }); + } finally { + // Remove cancellation source when request fulfills + this.valueRequests.delete(request); + } + } + + public abstract getEntity(path: string): Promise; + public abstract getValue(params: ValueRequestParams): Promise; +} diff --git a/src/h5web/providers/context.ts b/src/h5web/providers/context.ts index 8bde96b79..9992910b1 100644 --- a/src/h5web/providers/context.ts +++ b/src/h5web/providers/context.ts @@ -1,69 +1,6 @@ import { createContext } from 'react'; -import { Entity, ProviderError } from './models'; +import type { Entity, ValueRequestParams } from './models'; import type { FetchStore } from 'react-suspense-fetch'; -import axios, { - AxiosInstance, - AxiosRequestConfig, - CancelTokenSource, - AxiosResponse, -} from 'axios'; - -// https://github.com/microsoft/TypeScript/issues/15300#issuecomment-771916993 -// eslint-disable-next-line @typescript-eslint/consistent-type-definitions -export type ValueRequestParams = { - path: string; - selection?: string; -}; - -interface ValueRequest { - params: ValueRequestParams; - cancelSource: CancelTokenSource; -} - -export abstract class ProviderApi { - public readonly filepath: string; - public readonly cancelledValueRequests = new Set(); - - protected readonly client: AxiosInstance; - protected readonly valueRequests = new Set(); - - public constructor(filepath: string, config?: AxiosRequestConfig) { - this.filepath = filepath; - this.client = axios.create(config); - } - - public cancelValueRequests(): void { - // Cancel every active value request - this.valueRequests.forEach((request) => { - request.cancelSource.cancel(ProviderError.Cancelled); - - // Save request so params can later be evicted from the values store (cf. `Provider.tsx`) - this.cancelledValueRequests.add(request); - }); - - this.valueRequests.clear(); - } - - protected async cancellableFetchValue( - endpoint: string, - params: ValueRequestParams - ): Promise> { - const cancelSource = axios.CancelToken.source(); - const request = { params, cancelSource }; - this.valueRequests.add(request); - - try { - const { token: cancelToken } = cancelSource; - return await this.client.get(endpoint, { cancelToken }); - } finally { - // Remove cancellation source when request fulfills - this.valueRequests.delete(request); - } - } - - public abstract getEntity(path: string): Promise; - public abstract getValue(params: ValueRequestParams): Promise; -} interface ValuesStore extends FetchStore { cancelOngoing: () => void; @@ -76,4 +13,4 @@ interface Context { valuesStore: ValuesStore; } -export const ProviderContext = createContext({} as Context); +export const ProviderContext = createContext({} as Context); diff --git a/src/h5web/providers/hsds/HsdsProvider.tsx b/src/h5web/providers/hsds/HsdsProvider.tsx index 8be243dd6..1add38a5c 100644 --- a/src/h5web/providers/hsds/HsdsProvider.tsx +++ b/src/h5web/providers/hsds/HsdsProvider.tsx @@ -1,5 +1,5 @@ import { ReactNode, useMemo } from 'react'; -import { HsdsApi } from './api'; +import { HsdsApi } from './hsds-api'; import Provider from '../Provider'; interface Props { diff --git a/src/h5web/providers/hsds/api.ts b/src/h5web/providers/hsds/hsds-api.ts similarity index 99% rename from src/h5web/providers/hsds/api.ts rename to src/h5web/providers/hsds/hsds-api.ts index 418893729..72db53c5d 100644 --- a/src/h5web/providers/hsds/api.ts +++ b/src/h5web/providers/hsds/hsds-api.ts @@ -13,6 +13,7 @@ import type { HsdsId, } from './models'; import { + ValueRequestParams, Dataset, Datatype, Entity, @@ -21,7 +22,7 @@ import { ProviderError, } from '../models'; import { assertDefined, assertGroup } from '../../guards'; -import { ValueRequestParams, ProviderApi } from '../context'; +import { ProviderApi } from '../api'; import { assertHsdsDataset, isHsdsGroup, diff --git a/src/h5web/providers/jupyter/JupyterProvider.tsx b/src/h5web/providers/jupyter/JupyterProvider.tsx index 5273996b4..d007b2f37 100644 --- a/src/h5web/providers/jupyter/JupyterProvider.tsx +++ b/src/h5web/providers/jupyter/JupyterProvider.tsx @@ -1,6 +1,6 @@ import { ReactNode, useMemo } from 'react'; -import { JupyterStableApi } from './api'; -import { JupyterDevApi } from './devApi'; +import { JupyterStableApi } from './jupyter-api'; +import { JupyterDevApi } from './jupyter-dev-api'; import Provider from '../Provider'; interface Props { diff --git a/src/h5web/providers/jupyter/api.ts b/src/h5web/providers/jupyter/jupyter-api.ts similarity index 96% rename from src/h5web/providers/jupyter/api.ts rename to src/h5web/providers/jupyter/jupyter-api.ts index 7fbf79339..91c31158a 100644 --- a/src/h5web/providers/jupyter/api.ts +++ b/src/h5web/providers/jupyter/jupyter-api.ts @@ -1,5 +1,11 @@ -import { Group, Dataset, Entity, EntityKind } from '../models'; -import { ValueRequestParams, ProviderApi } from '../context'; +import { + ValueRequestParams, + Group, + Dataset, + Entity, + EntityKind, +} from '../models'; +import { ProviderApi } from '../api'; import { assertGroupContent, isDatasetResponse, diff --git a/src/h5web/providers/jupyter/devApi.ts b/src/h5web/providers/jupyter/jupyter-dev-api.ts similarity index 94% rename from src/h5web/providers/jupyter/devApi.ts rename to src/h5web/providers/jupyter/jupyter-dev-api.ts index b9f032127..4ce343dc2 100644 --- a/src/h5web/providers/jupyter/devApi.ts +++ b/src/h5web/providers/jupyter/jupyter-dev-api.ts @@ -1,5 +1,5 @@ -import { JupyterStableApi } from './api'; -import type { Attribute } from '../models'; +import { JupyterStableApi } from './jupyter-api'; +import type { ValueRequestParams, Attribute } from '../models'; import type { JupyterBaseEntity, JupyterContentGroupResponse, @@ -7,7 +7,6 @@ import type { JupyterMetaResponse, } from './models'; import { assertGroupContent, convertDtype } from './utils'; -import type { ValueRequestParams } from '../context'; interface DevJupyterAttrMeta { name: string; diff --git a/src/h5web/providers/mock/MockProvider.tsx b/src/h5web/providers/mock/MockProvider.tsx index 1b47fb55f..4cb092751 100644 --- a/src/h5web/providers/mock/MockProvider.tsx +++ b/src/h5web/providers/mock/MockProvider.tsx @@ -1,6 +1,6 @@ import { ReactNode, useMemo } from 'react'; import Provider from '../Provider'; -import { MockApi } from './api'; +import { MockApi } from './mock-api'; interface Props { children: ReactNode; diff --git a/src/h5web/providers/mock/api.ts b/src/h5web/providers/mock/mock-api.ts similarity index 95% rename from src/h5web/providers/mock/api.ts rename to src/h5web/providers/mock/mock-api.ts index 2e7f80f85..aac64d742 100644 --- a/src/h5web/providers/mock/api.ts +++ b/src/h5web/providers/mock/mock-api.ts @@ -2,8 +2,8 @@ import axios from 'axios'; import ndarray from 'ndarray'; import unpack from 'ndarray-unpack'; import { assertArrayShape, assertPrintableType } from '../../guards'; -import { ValueRequestParams, ProviderApi } from '../context'; -import type { Entity } from '../models'; +import { ProviderApi } from '../api'; +import type { ValueRequestParams, Entity } from '../models'; import { mockFilepath } from './metadata'; import { assertMockDataset, findMockEntity } from './utils'; diff --git a/src/h5web/providers/models.ts b/src/h5web/providers/models.ts index 202f03187..d61bd5666 100644 --- a/src/h5web/providers/models.ts +++ b/src/h5web/providers/models.ts @@ -1,3 +1,13 @@ +export interface ValueRequestParams { + path: string; + selection?: string; +} + +export enum ProviderError { + NotFound = 'Entity not found', + Cancelled = 'Request cancelled', +} + /* -------------------- */ /* ----- ENTITIES ----- */ @@ -158,8 +168,3 @@ export type Value = D['shape'] extends ScalarShape export type H5WebComplex = [number, number]; export type ComplexArray = (ComplexArray | H5WebComplex)[]; - -export enum ProviderError { - NotFound = 'Entity not found', - Cancelled = 'Request cancelled', -}