diff --git a/keyserver/src/scripts/biggest-farcaster-channels.js b/keyserver/src/scripts/biggest-farcaster-channels.js new file mode 100644 --- /dev/null +++ b/keyserver/src/scripts/biggest-farcaster-channels.js @@ -0,0 +1,25 @@ +// @flow + +import invariant from 'invariant'; + +import type { NeynarChannel } from 'lib/types/farcaster-types.js'; + +import { main } from './utils.js'; +import { neynarClient } from '../utils/fc-cache.js'; + +async function fetchAllFarcasterChannelsAndPrintSortedByFollowerCount() { + invariant(neynarClient, 'neynarClient should be defined'); + const allChannels = await neynarClient.getAllChannels(); + allChannels.sort( + (channelA: NeynarChannel, channelB: NeynarChannel) => + channelB.follower_count - channelA.follower_count, + ); + const simplifiedChannelInfo = allChannels.map(({ id, follower_count }) => ({ + id, + follower_count, + })); + simplifiedChannelInfo.splice(1000); + console.log(JSON.stringify(simplifiedChannelInfo, undefined, ' ')); +} + +main([fetchAllFarcasterChannelsAndPrintSortedByFollowerCount]); diff --git a/keyserver/src/scripts/utils.js b/keyserver/src/scripts/utils.js --- a/keyserver/src/scripts/utils.js +++ b/keyserver/src/scripts/utils.js @@ -3,6 +3,7 @@ import { endPool } from '../database/database.js'; import { endFirebase, endAPNs } from '../push/providers.js'; import { publisher } from '../socket/redis.js'; +import { initFCCache } from '../utils/fc-cache.js'; import { prefetchAllURLFacts } from '../utils/urls.js'; function endScript() { @@ -15,6 +16,7 @@ function main(functions: $ReadOnlyArray<() => Promise>) { void (async () => { await prefetchAllURLFacts(); + await initFCCache(); try { for (const f of functions) { await f(); diff --git a/keyserver/src/utils/fc-cache.js b/keyserver/src/utils/fc-cache.js --- a/keyserver/src/utils/fc-cache.js +++ b/keyserver/src/utils/fc-cache.js @@ -12,6 +12,7 @@ type NeynarConfig = { +key: string }; let getFCNames: ?GetFCNames; +let neynarClient: ?NeynarClient; async function initFCCache() { const neynarSecret = await getCommConfig({ folder: 'secrets', @@ -21,10 +22,10 @@ if (!neynarKey) { return; } - const neynarClient = new NeynarClient(neynarKey); + neynarClient = new NeynarClient(neynarKey); const fcCache = new FCCache(neynarClient); getFCNames = (users: $ReadOnlyArray): Promise => baseGetFCNames(fcCache, users); } -export { initFCCache, getFCNames }; +export { initFCCache, getFCNames, neynarClient }; diff --git a/lib/types/farcaster-types.js b/lib/types/farcaster-types.js --- a/lib/types/farcaster-types.js +++ b/lib/types/farcaster-types.js @@ -31,5 +31,6 @@ export type NeynarChannel = { +id: string, +name: string, + +follower_count: number, ... }; diff --git a/lib/utils/neynar-client.js b/lib/utils/neynar-client.js --- a/lib/utils/neynar-client.js +++ b/lib/utils/neynar-client.js @@ -18,7 +18,7 @@ }, }; -type FetchFollowedFarcasterChannelsResponse = { +type FetchFarcasterChannelsResponse = { +channels: $ReadOnlyArray, +next: { +cursor: ?string, @@ -53,6 +53,7 @@ const fetchFollowerLimit = 150; const fetchFollowedChannelsLimit = 100; +const fetchChannelsLimit = 50; class NeynarClient { apiKey: string; @@ -129,8 +130,7 @@ }, }); - const json: FetchFollowedFarcasterChannelsResponse = - await response.json(); + const json: FetchFarcasterChannelsResponse = await response.json(); const { channels, next } = json; @@ -229,6 +229,48 @@ } while (fidsLeft.length > 0); return results; } + + async getAllChannels(): Promise> { + const farcasterChannels = []; + let paginationCursor = null; + + do { + const params: { [string]: string } = { + limit: fetchChannelsLimit.toString(), + ...(paginationCursor ? { cursor: paginationCursor } : null), + }; + + const url = getNeynarURL('2', 'channel/list', params); + + try { + const response = await fetch(url, { + method: 'GET', + headers: { + Accept: 'application/json', + api_key: this.apiKey, + }, + }); + + const json: FetchFarcasterChannelsResponse = await response.json(); + + const { channels, next } = json; + + channels.forEach(channel => { + farcasterChannels.push(channel); + }); + + paginationCursor = next.cursor; + } catch (error) { + console.log( + 'Failed to fetch all Farcaster channels:', + getMessageForException(error) ?? 'unknown', + ); + throw error; + } + } while (paginationCursor); + + return farcasterChannels; + } } export { NeynarClient };