diff options
author | Paul Frazee <pfrazee@gmail.com> | 2023-04-24 17:02:58 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-24 17:02:58 -0500 |
commit | 1b356556c91ed07025927d4cb0be90a269396822 (patch) | |
tree | 667b9f39d3f484d2952cb7efc5892d20878a55d7 | |
parent | da8af38dcc23ea33c686714be2ce5f0bf0e65798 (diff) | |
download | voidsky-1b356556c91ed07025927d4cb0be90a269396822.tar.zst |
Performance fixes with new getPosts (#525)
* Update notifications to fetch in a batch using getPosts * Improve search perf with getPosts * Bump @atproto/api@0.2.9 * Just use post uri for key
-rw-r--r-- | package.json | 2 | ||||
-rw-r--r-- | src/state/models/content/post-thread.ts | 58 | ||||
-rw-r--r-- | src/state/models/feeds/notifications.ts | 76 | ||||
-rw-r--r-- | src/state/models/ui/search.ts | 23 | ||||
-rw-r--r-- | src/view/com/search/SearchResults.tsx | 11 | ||||
-rw-r--r-- | yarn.lock | 8 |
6 files changed, 97 insertions, 81 deletions
diff --git a/package.json b/package.json index d6d29f3c9..0df1f464c 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "e2e:run": "detox test --configuration ios.sim.debug --take-screenshots all" }, "dependencies": { - "@atproto/api": "0.2.8", + "@atproto/api": "0.2.9", "@bam.tech/react-native-image-resizer": "^3.0.4", "@braintree/sanitize-url": "^6.0.2", "@expo/webpack-config": "^18.0.1", diff --git a/src/state/models/content/post-thread.ts b/src/state/models/content/post-thread.ts index acc9bffa9..76cab5c61 100644 --- a/src/state/models/content/post-thread.ts +++ b/src/state/models/content/post-thread.ts @@ -11,13 +11,6 @@ import * as apilib from 'lib/api/index' import {cleanError} from 'lib/strings/errors' import {updateDataOptimistically} from 'lib/async/revertible' -function* reactKeyGenerator(): Generator<string> { - let counter = 0 - while (true) { - yield `item-${counter++}` - } -} - export class PostThreadItemModel { // ui state _reactKey: string = '' @@ -55,10 +48,9 @@ export class PostThreadItemModel { constructor( public rootStore: RootStoreModel, - reactKey: string, v: AppBskyFeedDefs.ThreadViewPost, ) { - this._reactKey = reactKey + this._reactKey = `thread-${v.post.uri}` this.post = v.post if (FeedPost.isRecord(this.post.record)) { const valid = FeedPost.validateRecord(this.post.record) @@ -82,7 +74,6 @@ export class PostThreadItemModel { } assignTreeModels( - keyGen: Generator<string>, v: AppBskyFeedDefs.ThreadViewPost, higlightedPostUri: string, includeParent = true, @@ -91,22 +82,12 @@ export class PostThreadItemModel { // parents if (includeParent && v.parent) { if (AppBskyFeedDefs.isThreadViewPost(v.parent)) { - const parentModel = new PostThreadItemModel( - this.rootStore, - keyGen.next().value, - v.parent, - ) + const parentModel = new PostThreadItemModel(this.rootStore, v.parent) parentModel._depth = this._depth - 1 parentModel._showChildReplyLine = true if (v.parent.parent) { parentModel._showParentReplyLine = true //parentModel.uri !== higlightedPostUri - parentModel.assignTreeModels( - keyGen, - v.parent, - higlightedPostUri, - true, - false, - ) + parentModel.assignTreeModels(v.parent, higlightedPostUri, true, false) } this.parent = parentModel } else if (AppBskyFeedDefs.isNotFoundPost(v.parent)) { @@ -118,23 +99,13 @@ export class PostThreadItemModel { const replies = [] for (const item of v.replies) { if (AppBskyFeedDefs.isThreadViewPost(item)) { - const itemModel = new PostThreadItemModel( - this.rootStore, - keyGen.next().value, - item, - ) + const itemModel = new PostThreadItemModel(this.rootStore, item) itemModel._depth = this._depth + 1 itemModel._showParentReplyLine = itemModel.parentUri !== higlightedPostUri if (item.replies?.length) { itemModel._showChildReplyLine = true - itemModel.assignTreeModels( - keyGen, - item, - higlightedPostUri, - false, - true, - ) + itemModel.assignTreeModels(item, higlightedPostUri, false, true) } replies.push(itemModel) } else if (AppBskyFeedDefs.isNotFoundPost(item)) { @@ -241,6 +212,19 @@ export class PostThreadModel { this.params = params } + static fromPostView( + rootStore: RootStoreModel, + postView: AppBskyFeedDefs.PostView, + ) { + const model = new PostThreadModel(rootStore, {uri: postView.uri}) + model.resolvedUri = postView.uri + model.hasLoaded = true + model.thread = new PostThreadItemModel(rootStore, { + post: postView, + }) + return model + } + get hasContent() { return typeof this.thread !== 'undefined' } @@ -360,6 +344,9 @@ export class PostThreadModel { } async _load(isRefreshing = false) { + if (this.hasLoaded && !isRefreshing) { + return + } this._xLoading(isRefreshing) try { const res = await this.rootStore.agent.getPostThread( @@ -374,15 +361,12 @@ export class PostThreadModel { _replaceAll(res: GetPostThread.Response) { sortThread(res.data.thread) - const keyGen = reactKeyGenerator() const thread = new PostThreadItemModel( this.rootStore, - keyGen.next().value, res.data.thread as AppBskyFeedDefs.ThreadViewPost, ) thread._isHighlightedPost = true thread.assignTreeModels( - keyGen, res.data.thread as AppBskyFeedDefs.ThreadViewPost, thread.uri, ) diff --git a/src/state/models/feeds/notifications.ts b/src/state/models/feeds/notifications.ts index e2a18ea04..0bbbe215c 100644 --- a/src/state/models/feeds/notifications.ts +++ b/src/state/models/feeds/notifications.ts @@ -2,6 +2,7 @@ import {makeAutoObservable, runInAction} from 'mobx' import { AppBskyNotificationListNotifications as ListNotifications, AppBskyActorDefs, + AppBskyFeedDefs, AppBskyFeedPost, AppBskyFeedRepost, AppBskyFeedLike, @@ -146,6 +147,14 @@ export class NotificationsFeedItemModel { return false } + get additionaDataUri(): string | undefined { + if (this.isReply || this.isQuote || this.isMention) { + return this.uri + } else if (this.isLike || this.isRepost) { + return this.subjectUri + } + } + get subjectUri(): string { if (this.reasonSubject) { return this.reasonSubject @@ -193,28 +202,11 @@ export class NotificationsFeedItemModel { ) } - async fetchAdditionalData() { - if (!this.needsAdditionalData) { - return - } - let postUri - if (this.isReply || this.isQuote || this.isMention) { - postUri = this.uri - } else if (this.isLike || this.isRepost) { - postUri = this.subjectUri - } - if (postUri) { - this.additionalPost = new PostThreadModel(this.rootStore, { - uri: postUri, - depth: 0, - }) - await this.additionalPost.setup().catch(e => { - this.rootStore.log.error( - 'Failed to load post needed by notification', - e, - ) - }) - } + setAdditionalData(additionalPost: AppBskyFeedDefs.PostView) { + this.additionalPost = PostThreadModel.fromPostView( + this.rootStore, + additionalPost, + ) } } @@ -464,7 +456,13 @@ export class NotificationsFeedModel { 'mostRecent', res.data.notifications[0], ) - await notif.fetchAdditionalData() + const addedUri = notif.additionaDataUri + if (addedUri) { + const postsRes = await this.rootStore.agent.app.bsky.feed.getPosts({ + uris: [addedUri], + }) + notif.setAdditionalData(postsRes.data.posts[0]) + } const filtered = this._filterNotifications([notif]) return filtered[0] } @@ -536,25 +534,39 @@ export class NotificationsFeedModel { async _fetchItemModels( items: ListNotifications.Notification[], ): Promise<NotificationsFeedItemModel[]> { - const promises = [] + // construct item models and track who needs more data const itemModels: NotificationsFeedItemModel[] = [] + const addedPostMap = new Map<string, NotificationsFeedItemModel[]>() for (const item of items) { const itemModel = new NotificationsFeedItemModel( this.rootStore, `item-${_idCounter++}`, item, ) - if (itemModel.needsAdditionalData) { - promises.push(itemModel.fetchAdditionalData()) + const uri = itemModel.additionaDataUri + if (uri) { + const models = addedPostMap.get(uri) || [] + models.push(itemModel) + addedPostMap.set(uri, models) } itemModels.push(itemModel) } - await Promise.all(promises).catch(e => { - this.rootStore.log.error( - 'Uncaught failure during notifications _processNotifications()', - e, - ) - }) + + // fetch additional data + if (addedPostMap.size > 0) { + const postsRes = await this.rootStore.agent.app.bsky.feed.getPosts({ + uris: Array.from(addedPostMap.keys()), + }) + for (const post of postsRes.data.posts) { + const models = addedPostMap.get(post.uri) + if (models?.length) { + for (const model of models) { + model.setAdditionalData(post) + } + } + } + } + return itemModels } diff --git a/src/state/models/ui/search.ts b/src/state/models/ui/search.ts index 330283a0b..4ab9db513 100644 --- a/src/state/models/ui/search.ts +++ b/src/state/models/ui/search.ts @@ -1,13 +1,14 @@ import {makeAutoObservable, runInAction} from 'mobx' import {searchProfiles, searchPosts} from 'lib/api/search' -import {AppBskyActorDefs} from '@atproto/api' +import {PostThreadModel} from '../content/post-thread' +import {AppBskyActorDefs, AppBskyFeedDefs} from '@atproto/api' import {RootStoreModel} from '../root-store' export class SearchUIModel { isPostsLoading = false isProfilesLoading = false query: string = '' - postUris: string[] = [] + posts: PostThreadModel[] = [] profiles: AppBskyActorDefs.ProfileView[] = [] constructor(public rootStore: RootStoreModel) { @@ -15,7 +16,7 @@ export class SearchUIModel { } async fetch(q: string) { - this.postUris = [] + this.posts = [] this.profiles = [] this.query = q if (!q.trim()) { @@ -29,8 +30,22 @@ export class SearchUIModel { searchPosts(q).catch(_e => []), searchProfiles(q).catch(_e => []), ]) + + let posts: AppBskyFeedDefs.PostView[] = [] + if (postsSearch?.length) { + do { + const res = await this.rootStore.agent.app.bsky.feed.getPosts({ + uris: postsSearch + .splice(0, 25) + .map(p => `at://${p.user.did}/${p.tid}`), + }) + posts = posts.concat(res.data.posts) + } while (postsSearch.length) + } runInAction(() => { - this.postUris = postsSearch?.map(p => `at://${p.user.did}/${p.tid}`) || [] + this.posts = posts.map(post => + PostThreadModel.fromPostView(this.rootStore, post), + ) this.isPostsLoading = false }) diff --git a/src/view/com/search/SearchResults.tsx b/src/view/com/search/SearchResults.tsx index 5d6163d4b..3b05f75ea 100644 --- a/src/view/com/search/SearchResults.tsx +++ b/src/view/com/search/SearchResults.tsx @@ -49,7 +49,7 @@ const PostResults = observer(({model}: {model: SearchUIModel}) => { ) } - if (model.postUris.length === 0) { + if (model.posts.length === 0) { return ( <CenteredView> <Text type="xl" style={[styles.empty, pal.text]}> @@ -61,8 +61,13 @@ const PostResults = observer(({model}: {model: SearchUIModel}) => { return ( <ScrollView style={pal.view}> - {model.postUris.map(uri => ( - <Post key={uri} uri={uri} hideError /> + {model.posts.map(post => ( + <Post + key={post.resolvedUri} + uri={post.resolvedUri} + initView={post} + hideError + /> ))} <View style={s.footerSpacer} /> <View style={s.footerSpacer} /> diff --git a/yarn.lock b/yarn.lock index c5d29c2af..fb45b87a0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -30,10 +30,10 @@ tlds "^1.234.0" typed-emitter "^2.1.0" -"@atproto/api@0.2.8": - version "0.2.8" - resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.2.8.tgz#92ed413804ecb43aaa45ec18afc93d6f2b28a689" - integrity sha512-LfPgtf3UNg2W/AxHkJMJrLNT9QAD6bi16Sw5Zt3mgANrDnHWGygA7gRpeNdgVI+kFEhQfrIItemJvWLIB9BJDQ== +"@atproto/api@0.2.9": + version "0.2.9" + resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.2.9.tgz#08e29da66d1a9001d9d3ce427548c1760d805e99" + integrity sha512-r00IqidX2YF3VUEa4MUO2Vxqp3+QhI1cSNcWgzT4LsANapzrwdDTM+rY2Ejp9na3F+unO4SWRW3o434cVmG5gw== dependencies: "@atproto/common-web" "*" "@atproto/uri" "*" |