diff options
Diffstat (limited to 'src/state/models/cache')
-rw-r--r-- | src/state/models/cache/my-follows.ts | 99 |
1 files changed, 67 insertions, 32 deletions
diff --git a/src/state/models/cache/my-follows.ts b/src/state/models/cache/my-follows.ts index 10f88c4a9..14dc9895d 100644 --- a/src/state/models/cache/my-follows.ts +++ b/src/state/models/cache/my-follows.ts @@ -1,7 +1,14 @@ import {makeAutoObservable} from 'mobx' -import {AppBskyActorDefs} from '@atproto/api' +import { + AppBskyActorDefs, + AppBskyGraphGetFollows as GetFollows, + moderateProfile, +} from '@atproto/api' import {RootStoreModel} from '../root-store' +const MAX_SYNC_PAGES = 10 +const SYNC_TTL = 60e3 * 10 // 10 minutes + type Profile = AppBskyActorDefs.ProfileViewBasic | AppBskyActorDefs.ProfileView export enum FollowState { @@ -10,6 +17,14 @@ export enum FollowState { Unknown, } +export interface FollowInfo { + did: string + followRecordUri: string | undefined + handle: string + displayName: string | undefined + avatar: string | undefined +} + /** * This model is used to maintain a synced local cache of the user's * follows. It should be periodically refreshed and updated any time @@ -17,9 +32,8 @@ export enum FollowState { */ export class MyFollowsCache { // data - followDidToRecordMap: Record<string, string | boolean> = {} + byDid: Record<string, FollowInfo> = {} lastSync = 0 - myDid?: string constructor(public rootStore: RootStoreModel) { makeAutoObservable( @@ -35,16 +49,45 @@ export class MyFollowsCache { // = clear() { - this.followDidToRecordMap = {} - this.lastSync = 0 - this.myDid = undefined + this.byDid = {} + } + + /** + * Syncs a subset of the user's follows + * for performance reasons, caps out at 1000 follows + */ + async syncIfNeeded() { + if (this.lastSync > Date.now() - SYNC_TTL) { + return + } + + let cursor + for (let i = 0; i < MAX_SYNC_PAGES; i++) { + const res: GetFollows.Response = await this.rootStore.agent.getFollows({ + actor: this.rootStore.me.did, + cursor, + limit: 100, + }) + res.data.follows = res.data.follows.filter( + profile => + !moderateProfile(profile, this.rootStore.preferences.moderationOpts) + .account.filter, + ) + this.hydrateMany(res.data.follows) + if (!res.data.cursor) { + break + } + cursor = res.data.cursor + } + + this.lastSync = Date.now() } getFollowState(did: string): FollowState { - if (typeof this.followDidToRecordMap[did] === 'undefined') { + if (typeof this.byDid[did] === 'undefined') { return FollowState.Unknown } - if (typeof this.followDidToRecordMap[did] === 'string') { + if (typeof this.byDid[did].followRecordUri === 'string') { return FollowState.Following } return FollowState.NotFollowing @@ -53,49 +96,41 @@ export class MyFollowsCache { async fetchFollowState(did: string): Promise<FollowState> { // TODO: can we get a more efficient method for this? getProfile fetches more data than we need -prf const res = await this.rootStore.agent.getProfile({actor: did}) - if (res.data.viewer?.following) { - this.addFollow(did, res.data.viewer.following) - } else { - this.removeFollow(did) - } + this.hydrate(did, res.data) return this.getFollowState(did) } getFollowUri(did: string): string { - const v = this.followDidToRecordMap[did] + const v = this.byDid[did] if (typeof v === 'string') { return v } throw new Error('Not a followed user') } - addFollow(did: string, recordUri: string) { - this.followDidToRecordMap[did] = recordUri + addFollow(did: string, info: FollowInfo) { + this.byDid[did] = info } removeFollow(did: string) { - this.followDidToRecordMap[did] = false + if (this.byDid[did]) { + this.byDid[did].followRecordUri = undefined + } } - /** - * Use this to incrementally update the cache as views provide information - */ - hydrate(did: string, recordUri: string | undefined) { - if (recordUri) { - this.followDidToRecordMap[did] = recordUri - } else { - this.followDidToRecordMap[did] = false + hydrate(did: string, profile: Profile) { + this.byDid[did] = { + did, + followRecordUri: profile.viewer?.following, + handle: profile.handle, + displayName: profile.displayName, + avatar: profile.avatar, } } - /** - * Use this to incrementally update the cache as views provide information - */ - hydrateProfiles(profiles: Profile[]) { + hydrateMany(profiles: Profile[]) { for (const profile of profiles) { - if (profile.viewer) { - this.hydrate(profile.did, profile.viewer.following) - } + this.hydrate(profile.did, profile) } } } |