1+ import { unstable_cache } from "next/cache" ;
2+ import { cache } from 'react' ;
13import superjson from "superjson" ;
2- import { z } from ' zod' ;
4+ import { z } from " zod" ;
35
6+ // Your imports
47import { Cluster , clients , priceFeedsSchema } from "../services/pyth" ;
58
6- export const getPublishersForFeed = async (
7- cluster : Cluster ,
8- ) => {
9- "use cache" ;
10- const start = performance . now ( ) ;
11- const data = await clients [ cluster ] . getData ( ) ;
9+ const getDataCached = cache ( async ( cluster : Cluster ) => {
10+ return clients [ cluster ] . getData ( ) ;
11+ } ) ;
12+ const MAX_CACHE_SIZE_STRING = 2 * 1024 * 1024 ;
13+
14+ const getPublishersForFeed = unstable_cache ( async ( cluster : Cluster , chunk ?: number ) => {
15+ const data = await getDataCached ( cluster ) ;
1216 const result : Record < string , string [ ] > = { } ;
1317 for ( const key of data . productPrice . keys ( ) ) {
1418 const price = data . productPrice . get ( key ) ;
1519 result [ key ] = price ?. priceComponents . map ( ( { publisher } ) => publisher . toBase58 ( ) ) ?? [ ] ;
1620 }
17- const end = performance . now ( ) ;
18- // eslint-disable-next-line no-console, @typescript-eslint/restrict-template-expressions
19- console . log ( `getPublishersForFeed: ${ end - start } ms` ) ;
20- return result ;
21- } ;
21+ const stringifiedResult = superjson . stringify ( result ) ;
2222
23- const getFeeds = async ( cluster : Cluster ) => {
24- "use cache" ;
25- const start = performance . now ( ) ;
26- const data = await clients [ cluster ] . getData ( ) ;
27-
28- const result = superjson . stringify ( priceFeedsSchema . parse ( data . symbols . filter (
29- ( symbol ) =>
30- data . productFromSymbol . get ( symbol ) ?. display_symbol !== undefined ,
31- ) . map ( ( symbol ) => ( {
32- symbol,
33- product : data . productFromSymbol . get ( symbol ) ,
34- price : {
35- ...data . productPrice . get ( symbol ) ,
36- priceComponents : data . productPrice . get ( symbol ) ?. priceComponents . map ( ( { publisher } ) => ( {
37- publisher : publisher . toBase58 ( ) ,
38- } ) ) ?? [ ] ,
39- } ,
40- } ) ) ) )
41- const end = performance . now ( ) ;
42- // eslint-disable-next-line no-console, @typescript-eslint/restrict-template-expressions
43- console . log ( `getFeeds: ${ end - start } ms` ) ;
44- return result ;
45- }
23+ const chunksNumber = Math . ceil ( stringifiedResult . length / MAX_CACHE_SIZE_STRING ) ;
24+ const chunks = [ ] ;
25+ for ( let i = 0 ; i < chunksNumber ; i ++ ) {
26+ chunks . push ( stringifiedResult . slice ( i * MAX_CACHE_SIZE_STRING , ( i + 1 ) * MAX_CACHE_SIZE_STRING ) ) ;
27+ }
28+ return {
29+ chunk : chunks [ chunk ?? 0 ] ,
30+ chunksNumber,
31+ } ;
32+ } , [ ] , { revalidate : false } ) ;
4633
47- export const getFeedsForPublisherCached = async (
48- cluster : Cluster ,
49- publisher : string ,
50- ) => {
51- const start = performance . now ( ) ;
52- const rawFeeds = await getFeeds ( cluster ) ;
53- const feeds = superjson . parse < z . infer < typeof priceFeedsSchema > > ( rawFeeds ) ;
54- const end = performance . now ( ) ;
55- // eslint-disable-next-line no-console, @typescript-eslint/restrict-template-expressions
56- console . log ( `getFeedsForPublisherCached: ${ end - start } ms` ) ;
57- return priceFeedsSchema . parse ( feeds . filter ( ( { price } ) =>
58- price . priceComponents . some (
59- ( component ) => component . publisher . toString ( ) === publisher ,
60- ) ,
61- ) ) ;
62- } ;
34+ const _getFeeds = unstable_cache ( async ( cluster : Cluster , chunk ?: number ) => {
35+ // eslint-disable-next-line no-console
36+ console . log ( 'getFeeds' , cluster , chunk ) ;
37+ const data = await getDataCached ( cluster ) ;
38+ const parsedData = priceFeedsSchema . parse (
39+ data . symbols
40+ . filter (
41+ ( symbol ) =>
42+ data . productFromSymbol . get ( symbol ) ?. display_symbol !== undefined
43+ )
44+ . map ( ( symbol ) => ( {
45+ symbol,
46+ product : data . productFromSymbol . get ( symbol ) ,
47+ price : {
48+ ...data . productPrice . get ( symbol ) ,
49+ priceComponents :
50+ data . productPrice
51+ . get ( symbol )
52+ ?. priceComponents . map ( ( { publisher } ) => ( {
53+ publisher : publisher . toBase58 ( ) ,
54+ } ) ) ?? [ ] ,
55+ } ,
56+ } ) )
57+ )
58+ const result = superjson . stringify (
59+ parsedData
60+ ) ;
61+ const chunksNumber = Math . ceil ( result . length / MAX_CACHE_SIZE_STRING ) ;
62+ const chunks = [ ] ;
63+ for ( let i = 0 ; i < chunksNumber ; i ++ ) {
64+ chunks . push ( result . slice ( i * MAX_CACHE_SIZE_STRING , ( i + 1 ) * MAX_CACHE_SIZE_STRING ) ) ;
65+ }
66+ return {
67+ chunk : chunks [ chunk ?? 0 ] ,
68+ chunksNumber,
69+ } ;
70+ } , [ ] , { revalidate : false } ) ;
6371
6472export const getFeedsCached = async ( cluster : Cluster ) => {
65- "use cache" ;
6673 const start = performance . now ( ) ;
67- const rawFeeds = await getFeeds ( cluster ) ;
74+ const { chunk, chunksNumber } = await _getFeeds ( cluster ) ; // uses cache
75+ const rawResults = await Promise . all ( Array . from ( { length : chunksNumber - 1 } , ( _ , i ) => _getFeeds ( cluster , i + 1 ) ) ) ;
76+ const rawJson = [ chunk , ...rawResults . map ( ( { chunk } ) => chunk ) ] . join ( '' ) ;
77+ const data = superjson . parse < z . infer < typeof priceFeedsSchema > > ( rawJson ) ;
6878 const end = performance . now ( ) ;
6979 // eslint-disable-next-line no-console, @typescript-eslint/restrict-template-expressions
7080 console . log ( `getFeedsCached: ${ end - start } ms` ) ;
71- return superjson . parse < z . infer < typeof priceFeedsSchema > > ( rawFeeds ) ;
81+ return data ;
7282} ;
7383
7484export const getPublishersForFeedCached = async ( cluster : Cluster , symbol : string ) => {
7585 const start = performance . now ( ) ;
76- const data = await getPublishersForFeed ( cluster ) ;
86+ const { chunk, chunksNumber } = await getPublishersForFeed ( cluster ) ; // uses cache
87+ const rawResults = await Promise . all ( Array . from ( { length : chunksNumber - 1 } , ( _ , i ) => getPublishersForFeed ( cluster , i + 1 ) ) ) ;
88+ const rawJson = [ chunk , ...rawResults . map ( ( { chunk } ) => chunk ) ] . join ( '' ) ;
89+ const data = superjson . parse < Record < string , string [ ] > > ( rawJson ) ;
7790 const end = performance . now ( ) ;
7891 // eslint-disable-next-line no-console, @typescript-eslint/restrict-template-expressions
7992 console . log ( `getPublishersForFeedCached: ${ end - start } ms` ) ;
8093 return data [ symbol ] ;
81- } ;
94+ } ;
95+
96+ export const getFeedsForPublisherCached = async (
97+ cluster : Cluster ,
98+ publisher : string
99+ ) => {
100+ const start = performance . now ( ) ;
101+ const data = await getFeedsCached ( cluster ) ; // uses cache
102+ const end = performance . now ( ) ;
103+ // eslint-disable-next-line no-console, @typescript-eslint/restrict-template-expressions
104+ console . log ( `getFeedsForPublisherCached: ${ end - start } ms.` ) ;
105+ return priceFeedsSchema . parse (
106+ data . filter ( ( { price } ) =>
107+ price . priceComponents . some (
108+ ( component ) => component . publisher . toString ( ) === publisher
109+ )
110+ )
111+ ) ;
112+ } ;
0 commit comments