diff --git a/src/classes/adapter.ts b/src/classes/adapter.ts index 95a742ea..d7798b25 100644 --- a/src/classes/adapter.ts +++ b/src/classes/adapter.ts @@ -2,7 +2,13 @@ import { Logger } from './logger'; import { Buffer } from './buffer'; import { Reactive } from './reactive'; import { - AdapterPropName, AdapterPropType, EMPTY_ITEM, getDefaultAdapterProps, methodPreResult, reactiveConfigStorage + AdapterPropName, + AdapterPropType, + EMPTY_ITEM, + getDefaultAdapterProps, + methodPausedResult, + methodPreResult, + reactiveConfigStorage } from './adapter/props'; import { wantedUtils } from './adapter/wanted'; import { Viewport } from './viewport'; @@ -42,9 +48,10 @@ type InitializationParams = { } const ADAPTER_PROPS_STUB = getDefaultAdapterProps(); +const ALLOWED_METHODS_WHEN_PAUSED = ADAPTER_PROPS_STUB.filter(v => !!v.allowedWhenPaused).map(v => v.name); const _has = (obj: unknown, prop: string): boolean => - typeof obj === 'object' && obj !== null && Object.prototype.hasOwnProperty.call(obj, prop); + !!obj && typeof obj === 'object' && Object.prototype.hasOwnProperty.call(obj, prop); const convertAppendArgs = (prepend: boolean, options: unknown, eof?: boolean) => { let result = options as AdapterAppendOptions & AdapterPrependOptions; @@ -113,16 +120,32 @@ export class Adapter implements IAdapter { private relax$: Reactive | null; private relaxRun: Promise | null; - private getPromisifiedMethod(method: MethodResolver, defaultMethod: MethodResolver) { + private shouldIgnorePausedMethod(method: MethodResolver) { + const methodName = method.name as AdapterPropName; + return this.paused && !ALLOWED_METHODS_WHEN_PAUSED.includes(methodName); + } + + private getPausedMethodResult(method: MethodResolver) { + this.logger?.log?.(() => 'scroller is paused: ' + method.name + ' method is ignored'); + return Promise.resolve(methodPausedResult); + } + + private getPromisifiedMethod(method: MethodResolver, args: unknown[]) { + return new Promise(resolve => { + if (this.relax$) { + this.relax$.once(value => resolve(value)); + } + method.apply(this, args); + }); + } + + private getWorkflowRunnerMethod(method: MethodResolver, defaultMethod: MethodResolver) { return (...args: unknown[]): Promise => - this.relax$ - ? new Promise(resolve => { - if (this.relax$) { - this.relax$.once(value => resolve(value)); - } - method.apply(this, args); - }) - : defaultMethod.apply(this, args); + !this.relax$ + ? defaultMethod.apply(this, args) + : this.shouldIgnorePausedMethod(method) + ? this.getPausedMethodResult(method) + : this.getPromisifiedMethod(method, args); } constructor(context: IAdapter | null, getWorkflow: WorkflowGetter, logger: Logger) { @@ -251,7 +274,7 @@ export class Adapter implements IAdapter { if (type === AdapterPropType.Function) { value = (value as () => void).bind(this); } else if (type === AdapterPropType.WorkflowRunner) { - value = this.getPromisifiedMethod(value as MethodResolver, defaultValue as MethodResolver); + value = this.getWorkflowRunnerMethod(value as MethodResolver, defaultValue as MethodResolver); } else if (type === AdapterPropType.Reactive && reactivePropsStore[name]) { value = (context as IAdapter)[name]; } else if (name === AdapterPropName.augmented) { diff --git a/src/classes/adapter/props.ts b/src/classes/adapter/props.ts index f5ca85b9..db888a6a 100644 --- a/src/classes/adapter/props.ts +++ b/src/classes/adapter/props.ts @@ -62,6 +62,12 @@ export const methodPreResult: AdapterMethodResult = { details: 'Adapter is not initialized' }; +export const methodPausedResult: AdapterMethodResult = { + immediate: true, + success: true, + details: 'Scroller is paused' +}; + const noopWF = () => Promise.resolve(methodPreResult); const emptyPackageInfo: IPackages = { @@ -186,7 +192,8 @@ export const getDefaultAdapterProps = (): IAdapterProp[] => [ { type: Type.WorkflowRunner, name: Name.reset, - value: noopWF + value: noopWF, + allowedWhenPaused: true }, { type: Type.WorkflowRunner, @@ -241,7 +248,8 @@ export const getDefaultAdapterProps = (): IAdapterProp[] => [ { type: Type.WorkflowRunner, name: Name.resume, - value: noopWF + value: noopWF, + allowedWhenPaused: true }, { type: Type.WorkflowRunner, diff --git a/src/interfaces/adapter.ts b/src/interfaces/adapter.ts index 15561fa3..2e344591 100644 --- a/src/interfaces/adapter.ts +++ b/src/interfaces/adapter.ts @@ -38,6 +38,7 @@ export interface IAdapterProp { wanted?: boolean; onDemand?: boolean; permanent?: boolean; + allowedWhenPaused?: boolean; } export interface ItemAdapter { diff --git a/src/processes/adapter/pause.ts b/src/processes/adapter/pause.ts index 0b1ddf6d..f37606fe 100644 --- a/src/processes/adapter/pause.ts +++ b/src/processes/adapter/pause.ts @@ -6,24 +6,19 @@ export default class Pause extends BaseAdapterProcessFactory(AdapterProcess.paus static run(scroller: Scroller, options?: { resume: boolean }): void { const resume = !!options?.resume; - if (!resume) { - if (!scroller.state.paused.get()) { - scroller.logger.log('pause scroller'); - scroller.state.paused.set(true); - } else { - scroller.logger.log('pause scroller (cancelled)'); - } - return; - } - - if (!scroller.state.paused.get()) { - scroller.logger.log('resume scroller (cancelled)'); + // pause branch + if (!resume && !scroller.state.paused.get()) { + scroller.logger.log('pause scroller'); + scroller.state.paused.set(true); + scroller.workflow.call({ + process: AdapterProcess.pause, + status: ProcessStatus.done + }); return; } scroller.logger.log('resume scroller'); scroller.state.paused.set(false); - scroller.workflow.call({ process: AdapterProcess.pause, status: ProcessStatus.next diff --git a/src/workflow.ts b/src/workflow.ts index 46d76586..c3c05615 100644 --- a/src/workflow.ts +++ b/src/workflow.ts @@ -101,9 +101,11 @@ export class Workflow { } const { process, status } = processSubject; // if the scroller is paused, any process other than "pause" and "reset" should be blocked - if (this.scroller.state.paused.get() && process !== AdapterProcess.pause && process !== AdapterProcess.reset) { - this.scroller.logger.log('scroller is paused: ' + process + ' process is ignored'); - return; + if (this.scroller.state.paused.get()) { + if (![AdapterProcess.pause, AdapterProcess.reset].includes(process as AdapterProcess)) { + this.scroller.logger.log('scroller is paused: ' + process + ' process is ignored'); + return; + } } if (process && process.startsWith('adapter') && status !== Status.next) { this.adapterRun$.set(processSubject);