From 0a456da9e9cc0cf0244e80a3da5af26debd20841 Mon Sep 17 00:00:00 2001 From: crupest Date: Sun, 2 Aug 2020 18:42:12 +0800 Subject: Implement sync timeline. --- Timeline/ClientApp/src/app/data/timeline.ts | 75 ++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 7 deletions(-) (limited to 'Timeline/ClientApp/src') diff --git a/Timeline/ClientApp/src/app/data/timeline.ts b/Timeline/ClientApp/src/app/data/timeline.ts index d84f7bc4..b30f3a7d 100644 --- a/Timeline/ClientApp/src/app/data/timeline.ts +++ b/Timeline/ClientApp/src/app/data/timeline.ts @@ -94,6 +94,11 @@ export type TimelineInfoState = | TimelineInfoLoadingState | TimelineInfoNonLoadingState; +interface TimelineCache { + timeline: TimelineInfo; + lastUpdated: string; +} + interface PostListInfo { idList: number[]; lastUpdated: string; @@ -101,7 +106,7 @@ interface PostListInfo { export class TimelineService { // timeline storage structure: - // each timeline has a TimelineInfo saved with key created by getTimelineKey + // each timeline has a TimelineCache saved with key created by getTimelineKey private getTimelineKey(timelineName: string): string { return `timeline.${timelineName}`; @@ -110,14 +115,70 @@ export class TimelineService { private getCachedTimeline( timelineName: string ): Promise { - return dataStorage.getItem( - this.getTimelineKey(timelineName) - ); + return dataStorage + .getItem(this.getTimelineKey(timelineName)) + .then((cache) => cache?.timeline ?? null); } - private syncTimeline(timelineName: string): Promise { - // TODO: Implement this. - throw new Error('Not implemented.'); + private async syncTimeline(timelineName: string): Promise { + const cache = await dataStorage.getItem(timelineName); + + const save = (cache: TimelineCache): Promise => + dataStorage.setItem( + this.getTimelineKey(timelineName), + cache + ); + const push = (state: TimelineInfoState): void => { + this._timelineSubscriptionHub.update(timelineName, () => + Promise.resolve(state) + ); + }; + + let result: TimelineInfo; + const now = new Date(); + if (cache == null) { + try { + const res = await getHttpTimelineClient().getTimeline(timelineName); + result = res; + await save({ timeline: result, lastUpdated: now.toISOString() }); + push({ state: 'synced', timeline: result }); + } catch (e) { + if (e instanceof HttpTimelineNotExistError) { + push({ state: 'synced', timeline: null }); + } else { + push({ state: 'offline', timeline: null }); + } + throw e; + } + } else { + try { + const res = await getHttpTimelineClient().getTimeline(timelineName, { + checkUniqueId: cache.timeline.uniqueId, + ifModifiedSince: new Date(cache.lastUpdated), + }); + if (res instanceof NotModified) { + result = cache.timeline; + await save({ timeline: result, lastUpdated: now.toISOString() }); + push({ state: 'synced', timeline: result }); + } else { + result = res; + await save({ timeline: result, lastUpdated: now.toISOString() }); + if (res.uniqueId === cache.timeline.uniqueId) { + push({ state: 'synced', timeline: result }); + } else { + push({ state: 'new', timeline: result }); + } + } + } catch (e) { + if (e instanceof HttpTimelineNotExistError) { + push({ state: 'new', timeline: null }); + } else { + push({ state: 'offline', timeline: cache.timeline }); + } + throw e; + } + } + return result; } private _timelineSubscriptionHub = new SubscriptionHub< -- cgit v1.2.3