Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3327076
D13976.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
8 KB
Referenced Files
None
Subscribers
None
D13976.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D13976: [lib][keyserver][native][web] Introduce FCCache.getFollowedFarcasterChannelsForFID
Attached
Detach File
Event Timeline
Log In to Comment