diff options
author | crupest <crupest@outlook.com> | 2020-08-26 00:51:35 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2020-08-26 00:51:35 +0800 |
commit | 35494ebade7722e02d0870eb6ce85600831c077d (patch) | |
tree | ff8b3fdf540c3a18870214ad16262593bbb0cb3a /Timeline/ClientApp/src/app/data/DataHub.ts | |
parent | c620d1d66757567f6b0f7abc66bc0f4c02be7ad3 (diff) | |
download | timeline-35494ebade7722e02d0870eb6ce85600831c077d.tar.gz timeline-35494ebade7722e02d0870eb6ce85600831c077d.tar.bz2 timeline-35494ebade7722e02d0870eb6ce85600831c077d.zip |
DataHub v3.0 . Also fix the bug that posts may be wrong if timeline has changed with same name.
Diffstat (limited to 'Timeline/ClientApp/src/app/data/DataHub.ts')
-rw-r--r-- | Timeline/ClientApp/src/app/data/DataHub.ts | 91 |
1 files changed, 59 insertions, 32 deletions
diff --git a/Timeline/ClientApp/src/app/data/DataHub.ts b/Timeline/ClientApp/src/app/data/DataHub.ts index e6be740d..93a9b41f 100644 --- a/Timeline/ClientApp/src/app/data/DataHub.ts +++ b/Timeline/ClientApp/src/app/data/DataHub.ts @@ -9,13 +9,22 @@ export type WithSyncStatus<T> = T & { syncing: boolean }; export class DataLine<TData> { private _current: TData | undefined = undefined; + private _syncPromise: Promise<void> | null = null; private _syncingSubject = new BehaviorSubject<boolean>(false); private _observers: Subscriber<TData>[] = []; constructor( - private config?: { destroyable?: (value: TData | undefined) => boolean } - ) {} + private config: { + sync: () => Promise<void>; + destroyable?: (value: TData | undefined) => boolean; + disableInitSync?: boolean; + } + ) { + if (config.disableInitSync !== true) { + setImmediate(() => void this.sync()); + } + } private subscribe(subscriber: Subscriber<TData>): void { this._observers.push(subscriber); @@ -68,19 +77,33 @@ export class DataLine<TData> { } get isSyncing(): boolean { - return this._syncingSubject.value; + return this._syncPromise != null; } - beginSync(): void { - if (!this._syncingSubject.value) { + sync(): Promise<void> { + if (this._syncPromise == null) { this._syncingSubject.next(true); + this._syncPromise = this.config.sync().then(() => { + this._syncingSubject.next(false); + this._syncPromise = null; + }); } + + return this._syncPromise; } - endSync(): void { - if (this._syncingSubject.value) { - this._syncingSubject.next(false); + syncWithAction( + syncAction: (line: DataLine<TData>) => Promise<void> + ): Promise<void> { + if (this._syncPromise == null) { + this._syncingSubject.next(true); + this._syncPromise = syncAction(this).then(() => { + this._syncingSubject.next(false); + this._syncPromise = null; + }); } + + return this._syncPromise; } get destroyable(): boolean { @@ -88,20 +111,15 @@ export class DataLine<TData> { return ( this._observers.length === 0 && - !this._syncingSubject.value && + !this.isSyncing && (customDestroyable != null ? customDestroyable(this._current) : true) ); } - - endSyncAndNext(value: TData): void { - this.endSync(); - this.next(value); - } } export class DataHub<TKey, TData> { + private sync: (key: TKey, line: DataLine<TData>) => Promise<void>; private keyToString: (key: TKey) => string; - private setup?: (key: TKey, line: DataLine<TData>) => (() => void) | void; private destroyable?: (key: TKey, value: TData | undefined) => boolean; private readonly subscriptionLineMap = new Map<string, DataLine<TData>>(); @@ -109,13 +127,14 @@ export class DataHub<TKey, TData> { private cleanTimerId = 0; // setup is called after creating line and if it returns a function as destroyer, then when the line is destroyed the destroyer will be called. - constructor(config?: { + constructor(config: { + sync: (key: TKey, line: DataLine<TData>) => Promise<void>; keyToString?: (key: TKey) => string; - setup?: (key: TKey, line: DataLine<TData>) => void; destroyable?: (key: TKey, value: TData | undefined) => boolean; }) { + this.sync = config.sync; this.keyToString = - config?.keyToString ?? + config.keyToString ?? ((value): string => { if (typeof value === "string") return value; else @@ -124,8 +143,7 @@ export class DataHub<TKey, TData> { ); }); - this.setup = config?.setup; - this.destroyable = config?.destroyable; + this.destroyable = config.destroyable; } private cleanLines(): void { @@ -148,17 +166,16 @@ export class DataHub<TKey, TData> { } } - private createLine(key: TKey, useSetup = true): DataLine<TData> { + private createLine(key: TKey, disableInitSync = false): DataLine<TData> { const keyString = this.keyToString(key); - const { setup, destroyable } = this; - const newLine = new DataLine<TData>({ + const { destroyable } = this; + const newLine: DataLine<TData> = new DataLine<TData>({ + sync: () => this.sync(key, newLine), destroyable: destroyable != null ? (value) => destroyable(key, value) : undefined, + disableInitSync: disableInitSync, }); this.subscriptionLineMap.set(keyString, newLine); - if (useSetup) { - setup?.(key, newLine); - } if (this.subscriptionLineMap.size === 1) { this.cleanTimerId = window.setInterval(this.cleanLines.bind(this), 20000); } @@ -166,17 +183,17 @@ export class DataHub<TKey, TData> { } getObservable(key: TKey): Observable<TData> { - return this.getLineOrCreateWithSetup(key).getObservable(); + return this.getLineOrCreate(key).getObservable(); } getSyncStatusObservable(key: TKey): Observable<boolean> { - return this.getLineOrCreateWithSetup(key).getSyncStatusObservable(); + return this.getLineOrCreate(key).getSyncStatusObservable(); } getDataWithSyncStatusObservable( key: TKey ): Observable<WithSyncStatus<TData>> { - return this.getLineOrCreateWithSetup(key).getDataWithSyncStatusObservable(); + return this.getLineOrCreate(key).getDataWithSyncStatusObservable(); } getLine(key: TKey): DataLine<TData> | null { @@ -184,15 +201,25 @@ export class DataHub<TKey, TData> { return this.subscriptionLineMap.get(keyString) ?? null; } - getLineOrCreateWithSetup(key: TKey): DataLine<TData> { + getLineOrCreate(key: TKey): DataLine<TData> { const keyString = this.keyToString(key); return this.subscriptionLineMap.get(keyString) ?? this.createLine(key); } - getLineOrCreateWithoutSetup(key: TKey): DataLine<TData> { + getLineOrCreateWithoutInitSync(key: TKey): DataLine<TData> { const keyString = this.keyToString(key); return ( - this.subscriptionLineMap.get(keyString) ?? this.createLine(key, false) + this.subscriptionLineMap.get(keyString) ?? this.createLine(key, true) ); } + + optionalInitLineWithSyncAction( + key: TKey, + syncAction: (line: DataLine<TData>) => Promise<void> + ): Promise<void> { + const optionalLine = this.getLine(key); + if (optionalLine != null) return Promise.resolve(); + const line = this.createLine(key, true); + return line.syncWithAction(syncAction); + } } |