diff options
| author | crupest <crupest@outlook.com> | 2020-08-02 18:42:12 +0800 | 
|---|---|---|
| committer | crupest <crupest@outlook.com> | 2020-08-02 18:42:12 +0800 | 
| commit | 0a456da9e9cc0cf0244e80a3da5af26debd20841 (patch) | |
| tree | 794fc1c3e4c4791e091d785db0f45ae12c774677 /Timeline/ClientApp/src/app/data/timeline.ts | |
| parent | 9014a5b52e9810eb71bc88b3645b0e716a8576ca (diff) | |
| download | timeline-0a456da9e9cc0cf0244e80a3da5af26debd20841.tar.gz timeline-0a456da9e9cc0cf0244e80a3da5af26debd20841.tar.bz2 timeline-0a456da9e9cc0cf0244e80a3da5af26debd20841.zip  | |
Implement sync timeline.
Diffstat (limited to 'Timeline/ClientApp/src/app/data/timeline.ts')
| -rw-r--r-- | Timeline/ClientApp/src/app/data/timeline.ts | 75 | 
1 files changed, 68 insertions, 7 deletions
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<TimelineInfo | null> {
 -    return dataStorage.getItem<TimelineInfo | null>(
 -      this.getTimelineKey(timelineName)
 -    );
 +    return dataStorage
 +      .getItem<TimelineCache | null>(this.getTimelineKey(timelineName))
 +      .then((cache) => cache?.timeline ?? null);
    }
 -  private syncTimeline(timelineName: string): Promise<TimelineInfo> {
 -    // TODO: Implement this.
 -    throw new Error('Not implemented.');
 +  private async syncTimeline(timelineName: string): Promise<TimelineInfo> {
 +    const cache = await dataStorage.getItem<TimelineCache | null>(timelineName);
 +
 +    const save = (cache: TimelineCache): Promise<TimelineCache> =>
 +      dataStorage.setItem<TimelineCache>(
 +        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<
  | 
