@@ -1556,6 +1556,54 @@ type RootSubscriptionInfo = {
1556
1556
subscriptionId : SubscriptionId | null ; // null when there's no current server subscription id
1557
1557
} ;
1558
1558
1559
+ /**
1560
+ * @internal
1561
+ */
1562
+ const LogsResult = pick ( {
1563
+ err : TransactionErrorResult ,
1564
+ logs : array ( string ( ) ) ,
1565
+ signature : string ( ) ,
1566
+ } ) ;
1567
+
1568
+ /**
1569
+ * Logs result.
1570
+ *
1571
+ * @typedef {Object } Logs.
1572
+ */
1573
+ export type Logs = {
1574
+ err : TransactionError | null ;
1575
+ logs : string [ ] ;
1576
+ signature : string ;
1577
+ } ;
1578
+
1579
+ /**
1580
+ * Expected JSON RPC response for the "logsNotification" message.
1581
+ */
1582
+ const LogsNotificationResult = pick ( {
1583
+ result : notificationResultAndContext ( LogsResult ) ,
1584
+ subscription : number ( ) ,
1585
+ } ) ;
1586
+
1587
+ /**
1588
+ * Filter for log subscriptions.
1589
+ */
1590
+ export type LogsFilter = PublicKey | 'all' | 'allWithVotes' ;
1591
+
1592
+ /**
1593
+ * Callback function for log notifications.
1594
+ */
1595
+ export type LogsCallback = ( logs : Logs , ctx : Context ) => void ;
1596
+
1597
+ /**
1598
+ * @private
1599
+ */
1600
+ type LogsSubscriptionInfo = {
1601
+ callback : LogsCallback ;
1602
+ filter : LogsFilter ;
1603
+ subscriptionId : SubscriptionId | null ; // null when there's no current server subscription id
1604
+ commitment ?: Commitment ;
1605
+ } ;
1606
+
1559
1607
/**
1560
1608
* Signature result
1561
1609
*
@@ -1669,6 +1717,11 @@ export class Connection {
1669
1717
[ id : number ] : SlotSubscriptionInfo ;
1670
1718
} = { } ;
1671
1719
1720
+ /** @internal */ _logsSubscriptionCounter : number = 0 ;
1721
+ /** @internal */ _logsSubscriptions : {
1722
+ [ id : number ] : LogsSubscriptionInfo ;
1723
+ } = { } ;
1724
+
1672
1725
/**
1673
1726
* Establish a JSON RPC connection
1674
1727
*
@@ -1730,6 +1783,10 @@ export class Connection {
1730
1783
'rootNotification' ,
1731
1784
this . _wsOnRootNotification . bind ( this ) ,
1732
1785
) ;
1786
+ this . _rpcWebSocket . on (
1787
+ 'logsNotification' ,
1788
+ this . _wsOnLogsNotification . bind ( this ) ,
1789
+ ) ;
1733
1790
}
1734
1791
1735
1792
/**
@@ -2991,12 +3048,14 @@ export class Connection {
2991
3048
const slotKeys = Object . keys ( this . _slotSubscriptions ) . map ( Number ) ;
2992
3049
const signatureKeys = Object . keys ( this . _signatureSubscriptions ) . map ( Number ) ;
2993
3050
const rootKeys = Object . keys ( this . _rootSubscriptions ) . map ( Number ) ;
3051
+ const logsKeys = Object . keys ( this . _logsSubscriptions ) . map ( Number ) ;
2994
3052
if (
2995
3053
accountKeys . length === 0 &&
2996
3054
programKeys . length === 0 &&
2997
3055
slotKeys . length === 0 &&
2998
3056
signatureKeys . length === 0 &&
2999
- rootKeys . length === 0
3057
+ rootKeys . length === 0 &&
3058
+ logsKeys . length === 0
3000
3059
) {
3001
3060
if ( this . _rpcWebSocketConnected ) {
3002
3061
this . _rpcWebSocketConnected = false ;
@@ -3053,6 +3112,21 @@ export class Connection {
3053
3112
const sub = this . _rootSubscriptions [ id ] ;
3054
3113
this . _subscribe ( sub , 'rootSubscribe' , [ ] ) ;
3055
3114
}
3115
+
3116
+ for ( let id of logsKeys ) {
3117
+ const sub = this . _logsSubscriptions [ id ] ;
3118
+ let filter ;
3119
+ if ( typeof sub . filter === 'object' ) {
3120
+ filter = { mentions : [ sub . filter . toString ( ) ] } ;
3121
+ } else {
3122
+ filter = sub . filter ;
3123
+ }
3124
+ this . _subscribe (
3125
+ sub ,
3126
+ 'logsSubscribe' ,
3127
+ this . _buildArgs ( [ filter ] , sub . commitment ) ,
3128
+ ) ;
3129
+ }
3056
3130
}
3057
3131
3058
3132
/**
@@ -3169,6 +3243,55 @@ export class Connection {
3169
3243
}
3170
3244
}
3171
3245
3246
+ /**
3247
+ * Registers a callback to be invoked whenever logs are emitted.
3248
+ */
3249
+ onLogs (
3250
+ filter : LogsFilter ,
3251
+ callback : LogsCallback ,
3252
+ commitment ?: Commitment ,
3253
+ ) : number {
3254
+ const id = ++ this . _logsSubscriptionCounter ;
3255
+ this . _logsSubscriptions [ id ] = {
3256
+ filter,
3257
+ callback,
3258
+ commitment,
3259
+ subscriptionId : null ,
3260
+ } ;
3261
+ this . _updateSubscriptions ( ) ;
3262
+ return id ;
3263
+ }
3264
+
3265
+ /**
3266
+ * Deregister a logs callback.
3267
+ *
3268
+ * @param id subscription id to deregister.
3269
+ */
3270
+ async removeOnLogsListener ( id : number ) : Promise < void > {
3271
+ if ( ! this . _logsSubscriptions [ id ] ) {
3272
+ throw new Error ( `Unknown logs id: ${ id } ` ) ;
3273
+ }
3274
+ const subInfo = this . _logsSubscriptions [ id ] ;
3275
+ delete this . _logsSubscriptions [ id ] ;
3276
+ await this . _unsubscribe ( subInfo , 'logsUnsubscribe' ) ;
3277
+ this . _updateSubscriptions ( ) ;
3278
+ }
3279
+
3280
+ /**
3281
+ * @internal
3282
+ */
3283
+ _wsOnLogsNotification ( notification : Object ) {
3284
+ const res = create ( notification , LogsNotificationResult ) ;
3285
+ const keys = Object . keys ( this . _logsSubscriptions ) . map ( Number ) ;
3286
+ for ( let id of keys ) {
3287
+ const sub = this . _logsSubscriptions [ id ] ;
3288
+ if ( sub . subscriptionId === res . subscription ) {
3289
+ sub . callback ( res . result . value , res . result . context ) ;
3290
+ return ;
3291
+ }
3292
+ }
3293
+ }
3294
+
3172
3295
/**
3173
3296
* @internal
3174
3297
*/
0 commit comments