1
+ import {
2
+ PollingDriftClientAccountSubscriber
3
+ } from './pollingDriftClientAccountSubscriber' ;
4
+
5
+ import {
6
+ OraclePriceData ,
7
+ OracleInfo
8
+ } from '../oracles/types' ;
9
+
10
+ import { getOracleId } from '../oracles/oracleId' ;
11
+
12
+
13
+ // allowing app UI state to incrementally replace RPC fetched acconut data with data from our infra that is pre-indexed and decoded
14
+ export class ExternalDataDriftClientSubscriber extends PollingDriftClientAccountSubscriber {
15
+ private oracleLastUpdate = new Map < string , number > ( ) ;
16
+ private pollingOracles = new Map < string , boolean > ( ) ;
17
+ private oraclePollIntervalId : NodeJS . Timeout ;
18
+
19
+ constructor ( ...args : ConstructorParameters < typeof PollingDriftClientAccountSubscriber > ) {
20
+ super ( ...args ) ;
21
+
22
+ }
23
+
24
+ /** Override to prevent oracles from being automatically polled later */
25
+ public override updateOraclesToPoll ( ) : boolean {
26
+ return true ;
27
+ }
28
+
29
+ /** Public method to be called externally with fresh oracle data */
30
+ public feedOracle ( oracleInfo : OracleInfo , priceData : OraclePriceData , slot : number ) {
31
+ const oracleId = getOracleId ( oracleInfo . publicKey , oracleInfo . source ) ;
32
+ this . oracles . set ( oracleId , { data : priceData , slot } ) ;
33
+ this . oracleLastUpdate . set ( oracleId , Date . now ( ) ) ;
34
+ if ( this . pollingOracles . has ( oracleId ) || this . accountLoader . accountsToLoad . has ( oracleInfo . publicKey . toBase58 ( ) ) ) {
35
+ const oracleToPoll = this . oraclesToPoll . get ( oracleId ) ;
36
+ if ( oracleToPoll ) {
37
+ this . accountLoader . removeAccount (
38
+ oracleToPoll . publicKey ,
39
+ oracleToPoll . callbackId
40
+ ) ;
41
+ this . pollingOracles . delete ( oracleId ) ;
42
+ }
43
+ }
44
+ }
45
+
46
+ public override async subscribe ( ) : Promise < boolean > {
47
+ await super . subscribe ( ) ;
48
+ this . startOraclePollingWatchdog ( ) ;
49
+ return true ;
50
+ }
51
+
52
+ private startOraclePollingWatchdog ( ) {
53
+ if ( this . oraclePollIntervalId ) {
54
+ clearInterval ( this . oraclePollIntervalId ) ;
55
+ }
56
+ // how do we handle not polling bet markets every 1s from this change?
57
+ this . oraclePollIntervalId = setInterval ( async ( ) => {
58
+ for ( const [ oracleId , lastUpdate ] of this . oracleLastUpdate . entries ( ) ) {
59
+ const oracleToPoll = this . oraclesToPoll . get ( oracleId ) ;
60
+ if ( ! oracleToPoll ) continue ;
61
+ const now = Date . now ( ) ;
62
+ if ( now - lastUpdate > 130_000 && ! this . pollingOracles . has ( oracleId ) ) {
63
+ await this . addOracleToAccountLoader ( oracleToPoll ) ;
64
+ this . pollingOracles . set ( oracleId , true ) ;
65
+ }
66
+ }
67
+ } , 60_000 ) ;
68
+ }
69
+
70
+ public override async unsubscribe ( ) : Promise < void > {
71
+ clearInterval ( this . oraclePollIntervalId ) ;
72
+ await super . unsubscribe ( ) ;
73
+ this . oracleLastUpdate . clear ( ) ;
74
+ this . pollingOracles . clear ( ) ;
75
+ }
76
+ }
0 commit comments