@@ -5,8 +5,9 @@ import { v4 as uuidv4 } from 'uuid';
5
5
6
6
export class CustomizedCadenceBulkAccountLoader extends BulkAccountLoader {
7
7
private customIntervalId : NodeJS . Timeout | null ;
8
+ private currentPollingFrequency : number | null ;
8
9
private accountFrequencies : Map < string , number > ;
9
- private lastPollingTime : Map < string , number > ;
10
+ private lastPollingTimes : Map < string , number > ;
10
11
private defaultPollingFrequency : number ;
11
12
12
13
constructor (
@@ -16,8 +17,9 @@ export class CustomizedCadenceBulkAccountLoader extends BulkAccountLoader {
16
17
) {
17
18
super ( connection , commitment , defaultPollingFrequency ) ;
18
19
this . customIntervalId = null ;
20
+ this . currentPollingFrequency = null ;
19
21
this . accountFrequencies = new Map ( ) ;
20
- this . lastPollingTime = new Map ( ) ;
22
+ this . lastPollingTimes = new Map ( ) ;
21
23
this . defaultPollingFrequency = defaultPollingFrequency ;
22
24
}
23
25
@@ -32,12 +34,12 @@ export class CustomizedCadenceBulkAccountLoader extends BulkAccountLoader {
32
34
} > = [ ] ;
33
35
34
36
for ( const [ key , frequency ] of this . accountFrequencies . entries ( ) ) {
35
- const lastPollTime = this . lastPollingTime . get ( key ) || 0 ;
37
+ const lastPollTime = this . lastPollingTimes . get ( key ) || 0 ;
36
38
if ( currentTime - lastPollTime >= frequency ) {
37
39
const account = this . accountsToLoad . get ( key ) ;
38
40
if ( account ) {
39
41
accountsToLoad . push ( account ) ;
40
- this . lastPollingTime . set ( key , currentTime ) ;
42
+ this . lastPollingTimes . set ( key , currentTime ) ;
41
43
}
42
44
}
43
45
}
@@ -66,23 +68,28 @@ export class CustomizedCadenceBulkAccountLoader extends BulkAccountLoader {
66
68
}
67
69
}
68
70
71
+ /**
72
+ * Updates the polling frequency for an account. This affects all callbacks attached to this account.
73
+ *
74
+ * @param publicKey The public key of the account to set the custom polling frequency for
75
+ * @param newFrequency The new polling frequency in ms
76
+ */
69
77
public setCustomPollingFrequency (
70
78
publicKey : PublicKey ,
71
79
newFrequency : number
72
80
) : void {
73
81
const key = publicKey . toBase58 ( ) ;
74
82
this . accountFrequencies . set ( key , newFrequency ) ;
75
- this . lastPollingTime . set ( key , 0 ) ; // Reset last polling time to ensure immediate load
83
+ this . lastPollingTimes . set ( key , 0 ) ; // Reset last polling time to ensure immediate load
76
84
this . restartPollingIfNeeded ( newFrequency ) ;
77
85
}
78
86
79
87
private restartPollingIfNeeded ( newFrequency : number ) : void {
80
- const currentMinFrequency = Math . min (
81
- ...Array . from ( this . accountFrequencies . values ( ) ) ,
82
- this . defaultPollingFrequency
83
- ) ;
84
-
85
- if ( newFrequency < currentMinFrequency || ! this . customIntervalId ) {
88
+ if (
89
+ ( this . currentPollingFrequency &&
90
+ newFrequency < this . currentPollingFrequency ) ||
91
+ ! this . customIntervalId
92
+ ) {
86
93
this . stopPolling ( ) ;
87
94
this . startPolling ( ) ;
88
95
}
@@ -97,9 +104,10 @@ export class CustomizedCadenceBulkAccountLoader extends BulkAccountLoader {
97
104
* @returns A unique callback ID that can be used to remove this specific callback later
98
105
*
99
106
* The method will:
100
- * 1. Create a new callback mapping for the account
101
- * 2. Set up polling frequency tracking for the account
102
- * 3. Reset last polling time to 0 to ensure immediate data fetch
107
+ * 1. Create a new callback mapping for the account if it doesn't exist already
108
+ * 2. Set up polling frequency tracking for the account if it doesn't exist already. If previous polling frequency is faster than the new one,
109
+ * we will use the previous frequency.
110
+ * 3. Reset last polling time to 0 to ensure data fetch is triggered on the next poll. Note that this does not mean the account will be fetched immediately.
103
111
* 4. Automatically restart polling if this account needs a faster frequency than existing accounts
104
112
*/
105
113
public async addAccount (
@@ -108,28 +116,53 @@ export class CustomizedCadenceBulkAccountLoader extends BulkAccountLoader {
108
116
customPollingFrequency ?: number
109
117
) : Promise < string > {
110
118
const callbackId = uuidv4 ( ) ;
111
- const callbacks = new Map < string , ( buffer : Buffer , slot : number ) => void > ( ) ;
112
- callbacks . set ( callbackId , callback ) ;
113
- const newAccountToLoad = {
114
- publicKey,
115
- callbacks,
116
- } ;
117
- this . accountsToLoad . set ( publicKey . toString ( ) , newAccountToLoad ) ;
119
+ const existingAccountToLoad = this . accountsToLoad . get ( publicKey . toString ( ) ) ;
120
+
121
+ if ( existingAccountToLoad ) {
122
+ existingAccountToLoad . callbacks . set ( callbackId , callback ) ;
123
+ } else {
124
+ const callbacks = new Map <
125
+ string ,
126
+ ( buffer : Buffer , slot : number ) => void
127
+ > ( ) ;
128
+ callbacks . set ( callbackId , callback ) ;
129
+ const newAccountToLoad = {
130
+ publicKey,
131
+ callbacks,
132
+ } ;
133
+ this . accountsToLoad . set ( publicKey . toString ( ) , newAccountToLoad ) ;
134
+ }
118
135
119
136
const key = publicKey . toBase58 ( ) ;
120
- const frequency = customPollingFrequency || this . defaultPollingFrequency ;
121
- this . accountFrequencies . set ( key , frequency ) ;
122
- this . lastPollingTime . set ( key , 0 ) ; // Reset last polling time to ensure immediate load
137
+ const previousFrequency =
138
+ this . accountFrequencies . get ( key ) || this . defaultPollingFrequency ;
139
+ const updatedFrequency =
140
+ customPollingFrequency && customPollingFrequency < previousFrequency
141
+ ? customPollingFrequency
142
+ : previousFrequency ;
143
+
144
+ this . accountFrequencies . set ( key , updatedFrequency ) ;
145
+ this . lastPollingTimes . set ( key , 0 ) ; // Reset last polling time to ensure immediate load
123
146
124
- this . restartPollingIfNeeded ( frequency ) ;
147
+ this . restartPollingIfNeeded ( updatedFrequency ) ;
125
148
126
149
return callbackId ;
127
150
}
128
151
129
- public removeAccount ( publicKey : PublicKey ) : void {
130
- const key = publicKey . toBase58 ( ) ;
131
- this . accountFrequencies . delete ( key ) ;
132
- this . lastPollingTime . delete ( key ) ;
152
+ public removeAccount ( publicKey : PublicKey , callbackId : string ) : void {
153
+ const existingAccountToLoad = this . accountsToLoad . get ( publicKey . toString ( ) ) ;
154
+
155
+ if ( existingAccountToLoad ) {
156
+ existingAccountToLoad . callbacks . delete ( callbackId ) ;
157
+
158
+ if ( existingAccountToLoad . callbacks . size === 0 ) {
159
+ this . bufferAndSlotMap . delete ( publicKey . toString ( ) ) ;
160
+ this . accountsToLoad . delete ( existingAccountToLoad . publicKey . toString ( ) ) ;
161
+ const key = publicKey . toBase58 ( ) ;
162
+ this . accountFrequencies . delete ( key ) ;
163
+ this . lastPollingTimes . delete ( key ) ;
164
+ }
165
+ }
133
166
134
167
if ( this . accountsToLoad . size === 0 ) {
135
168
this . stopPolling ( ) ;
@@ -154,6 +187,8 @@ export class CustomizedCadenceBulkAccountLoader extends BulkAccountLoader {
154
187
this . defaultPollingFrequency
155
188
) ;
156
189
190
+ this . currentPollingFrequency = minFrequency ;
191
+
157
192
this . customIntervalId = setInterval ( ( ) => {
158
193
this . handleAccountLoading ( ) . catch ( ( error ) => {
159
194
console . error ( 'Error in account loading:' , error ) ;
@@ -167,8 +202,9 @@ export class CustomizedCadenceBulkAccountLoader extends BulkAccountLoader {
167
202
if ( this . customIntervalId ) {
168
203
clearInterval ( this . customIntervalId ) ;
169
204
this . customIntervalId = null ;
205
+ this . currentPollingFrequency = null ;
170
206
}
171
- this . lastPollingTime . clear ( ) ;
207
+ this . lastPollingTimes . clear ( ) ;
172
208
}
173
209
174
210
public clearAccountFrequencies ( ) : void {
0 commit comments