Page MenuHomePhabricator

D13976.diff
No OneTemporary

D13976.diff

diff --git a/keyserver/src/updaters/thread-updaters.js b/keyserver/src/updaters/thread-updaters.js
--- a/keyserver/src/updaters/thread-updaters.js
+++ b/keyserver/src/updaters/thread-updaters.js
@@ -67,7 +67,7 @@
verifyUserOrCookieIDs,
} from '../fetchers/user-fetchers.js';
import type { Viewer } from '../session/viewer.js';
-import { neynarClient, fcCache } from '../utils/fc-cache.js';
+import { fcCache } from '../utils/fc-cache.js';
import { findUserIdentities } from '../utils/identity-utils.js';
import { redisCache } from '../utils/redis-cache.js';
import RelationshipChangeset from '../utils/relationship-changeset.js';
@@ -990,7 +990,7 @@
ignorePromiseRejections(
(async () => {
const followedChannels =
- await neynarClient?.fetchFollowedFarcasterChannels(farcasterID);
+ await fcCache?.getFollowedFarcasterChannelsForFID(farcasterID);
if (followedChannels) {
await Promise.allSettled(
followedChannels.map(followedChannel =>
diff --git a/lib/components/base-auto-join-community-handler.react.js b/lib/components/base-auto-join-community-handler.react.js
--- a/lib/components/base-auto-join-community-handler.react.js
+++ b/lib/components/base-auto-join-community-handler.react.js
@@ -63,7 +63,7 @@
const fid = useCurrentUserFID();
- const neynarClient = React.useContext(NeynarClientContext)?.client;
+ const fcCache = React.useContext(NeynarClientContext)?.fcCache;
const identityClientContext = React.useContext(IdentityClientContext);
invariant(identityClientContext, 'IdentityClientContext should be set');
@@ -87,7 +87,7 @@
}
prevCanQueryRef.current = canQuery;
- if (!canQuery || !isActive || !fid || !neynarClient) {
+ if (!canQuery || !isActive || !fid || !fcCache) {
return;
}
@@ -100,13 +100,17 @@
})();
const followedFarcasterChannelsPromise =
- neynarClient.fetchFollowedFarcasterChannels(fid);
+ fcCache.getFollowedFarcasterChannelsForFID(fid);
const [authMetadata, followedFarcasterChannels] = await Promise.all([
authMetadataPromise,
followedFarcasterChannelsPromise,
]);
+ if (!followedFarcasterChannels) {
+ return;
+ }
+
const headers = authMetadata
? createDefaultHTTPRequestHeaders(authMetadata)
: {};
@@ -178,7 +182,7 @@
threadInfos,
fid,
isActive,
- neynarClient,
+ fcCache,
getAuthMetadata,
keyserverInfos,
canQuery,
diff --git a/lib/utils/fc-cache.js b/lib/utils/fc-cache.js
--- a/lib/utils/fc-cache.js
+++ b/lib/utils/fc-cache.js
@@ -25,6 +25,14 @@
+farcasterChannel: ?NeynarChannel | Promise<?NeynarChannel>,
};
+type FollowedFarcasterChannelsQueryCacheEntry = {
+ +fid: string,
+ +expirationTime: number,
+ +followedFarcasterChannels:
+ | ?$ReadOnlyArray<NeynarChannel>
+ | Promise<?$ReadOnlyArray<NeynarChannel>>,
+};
+
class FCCache {
client: NeynarClient;
@@ -36,6 +44,12 @@
farcasterChannelQueryCache: Map<string, FarcasterChannelQueryCacheEntry> =
new Map();
+ // Maps from FIDs to a cache entry for the Farcaster user's followed channels
+ followedFarcasterChannelsQueryCache: Map<
+ string,
+ FollowedFarcasterChannelsQueryCacheEntry,
+ > = new Map();
+
constructor(client: NeynarClient) {
this.client = client;
}
@@ -236,6 +250,83 @@
return farcasterChannel;
}
+
+ getFollowedFarcasterChannelsForFID(
+ fid: string,
+ ): Promise<?$ReadOnlyArray<NeynarChannel>> {
+ const cachedChannelEntry =
+ this.getCachedFollowedFarcasterChannelsEntryForFID(fid);
+
+ if (cachedChannelEntry) {
+ return Promise.resolve(cachedChannelEntry.followedFarcasterChannels);
+ }
+
+ const fetchFollowedFarcasterChannelsPromise = (async () => {
+ let followedFarcasterChannels;
+ try {
+ followedFarcasterChannels = await Promise.race([
+ this.client.fetchFollowedFarcasterChannels(fid),
+ throwOnTimeout(`followed channels for ${fid}`),
+ ]);
+ } catch (e) {
+ console.log(e);
+ return null;
+ }
+
+ this.followedFarcasterChannelsQueryCache.set(fid, {
+ fid,
+ expirationTime: Date.now() + cacheTimeout,
+ followedFarcasterChannels,
+ });
+
+ return followedFarcasterChannels;
+ })();
+
+ this.followedFarcasterChannelsQueryCache.set(fid, {
+ fid,
+ expirationTime: Date.now() + queryTimeout * 2,
+ followedFarcasterChannels: fetchFollowedFarcasterChannelsPromise,
+ });
+
+ return fetchFollowedFarcasterChannelsPromise;
+ }
+
+ getCachedFollowedFarcasterChannelsEntryForFID(
+ fid: string,
+ ): ?FollowedFarcasterChannelsQueryCacheEntry {
+ const cacheResult = this.followedFarcasterChannelsQueryCache.get(fid);
+ if (!cacheResult) {
+ return undefined;
+ }
+
+ const { expirationTime } = cacheResult;
+ if (expirationTime <= Date.now()) {
+ this.followedFarcasterChannelsQueryCache.delete(fid);
+ return undefined;
+ }
+
+ return cacheResult;
+ }
+
+ getCachedFollowedFarcasterChannelsForFID(
+ fid: string,
+ ): ?$ReadOnlyArray<NeynarChannel> {
+ const cacheResult = this.getCachedFollowedFarcasterChannelsEntryForFID(fid);
+ if (!cacheResult) {
+ return undefined;
+ }
+
+ const { followedFarcasterChannels } = cacheResult;
+ if (
+ typeof followedFarcasterChannels !== 'object' ||
+ followedFarcasterChannels instanceof Promise ||
+ !followedFarcasterChannels
+ ) {
+ return undefined;
+ }
+
+ return followedFarcasterChannels;
+ }
}
export { FCCache };
diff --git a/native/community-settings/tag-farcaster-channel/tag-channel-button.react.js b/native/community-settings/tag-farcaster-channel/tag-channel-button.react.js
--- a/native/community-settings/tag-farcaster-channel/tag-channel-button.react.js
+++ b/native/community-settings/tag-farcaster-channel/tag-channel-button.react.js
@@ -41,17 +41,22 @@
const neynarClientContext = React.useContext(NeynarClientContext);
invariant(neynarClientContext, 'NeynarClientContext is missing');
- const { client } = neynarClientContext;
+ const { fcCache } = neynarClientContext;
React.useEffect(() => {
void (async () => {
- const channels = await client.fetchFollowedFarcasterChannels(fid);
+ const channels = await fcCache.getFollowedFarcasterChannelsForFID(fid);
+ if (!channels) {
+ return;
+ }
- const sortedChannels = channels.sort((a, b) => a.id.localeCompare(b.id));
+ const sortedChannels = [...channels].sort((a, b) =>
+ a.id.localeCompare(b.id),
+ );
setChannelOptions(sortedChannels);
})();
- }, [client, fid]);
+ }, [fcCache, fid]);
const activeTheme = useSelector(state => state.globalThemeInfo.activeTheme);
diff --git a/web/tag-farcaster-channel/create-farcaster-channel-tag-modal.react.js b/web/tag-farcaster-channel/create-farcaster-channel-tag-modal.react.js
--- a/web/tag-farcaster-channel/create-farcaster-channel-tag-modal.react.js
+++ b/web/tag-farcaster-channel/create-farcaster-channel-tag-modal.react.js
@@ -33,7 +33,7 @@
const neynarClientContext = React.useContext(NeynarClientContext);
invariant(neynarClientContext, 'NeynarClientContext is missing');
- const { client, fcCache } = neynarClientContext;
+ const { fcCache } = neynarClientContext;
const [channelOptions, setChannelOptions] = React.useState<
$ReadOnlyArray<DropdownOption>,
@@ -44,9 +44,12 @@
React.useEffect(() => {
void (async () => {
- const channels = await client.fetchFollowedFarcasterChannels(fid);
+ const channels = await fcCache.getFollowedFarcasterChannelsForFID(fid);
+ if (!channels) {
+ return;
+ }
- const sortedChannels = channels
+ const sortedChannels = [...channels]
.sort((a, b) => a.id.localeCompare(b.id))
.map(channel => ({
id: channel.id,
@@ -57,7 +60,7 @@
setChannelOptions(options);
})();
- }, [client, fid]);
+ }, [fcCache, fid]);
const onChangeSelectedOption = React.useCallback((option: string) => {
setError(null);

File Metadata

Mime Type
text/plain
Expires
Thu, Nov 21, 8:16 AM (4 h, 56 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2555288
Default Alt Text
D13976.diff (8 KB)

Event Timeline