@blackglory/geyser-js 0.9.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@blackglory/geyser-js",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
4
  "description": "",
5
5
  "keywords": [],
6
6
  "files": [
7
- "lib"
7
+ "lib",
8
+ "src"
8
9
  ],
9
10
  "type": "module",
10
11
  "main": "lib/index.js",
@@ -0,0 +1,34 @@
1
+ import { JSONObject } from 'justypes'
2
+ import { CustomError } from '@blackglory/errors'
3
+
4
+ export const expectedVersion = '^0.5.0'
5
+
6
+ export interface IRateLimiterConfig extends JSONObject {
7
+ duration: number | null
8
+ limit: number | null
9
+ }
10
+
11
+ export interface IAPI {
12
+ getAllRateLimiterIds(): string[]
13
+
14
+ getRateLimiter(rateLimiterId: string): IRateLimiterConfig | null
15
+ setRateLimiter(rateLimiterId: string, config: IRateLimiterConfig): null
16
+ removeRateLimiter(rateLimiterId: string): null
17
+
18
+ /**
19
+ * 重置速率限制器的状态.
20
+ *
21
+ * @throws {RateLimiterNotFound}
22
+ */
23
+ resetRateLimiter(rateLimiterId: string): null
24
+
25
+ /**
26
+ * @throws {RateLimiterNotFound}
27
+ */
28
+ acquireToken(rateLimiterId: string): null
29
+ }
30
+
31
+ /**
32
+ * 速率限制器在未经配置的情况下, 相当于不存在.
33
+ */
34
+ export class RateLimiterNotFound extends CustomError {}
@@ -0,0 +1,99 @@
1
+ import { createRPCClient } from '@utils/rpc-client.js'
2
+ import { ClientProxy } from 'delight-rpc'
3
+ import { timeoutSignal, withAbortSignal } from 'extra-abort'
4
+ import { IAPI, IRateLimiterConfig } from './contract.js'
5
+ export { IRateLimiterConfig, RateLimiterNotFound } from './contract.js'
6
+
7
+ export interface IGeyserClientOptions {
8
+ server: string
9
+ timeout?: number
10
+ retryIntervalForReconnection?: number
11
+ }
12
+
13
+ export class GeyserClient {
14
+ static async create(options: IGeyserClientOptions): Promise<GeyserClient> {
15
+ const { client, close } = await createRPCClient(
16
+ options.server
17
+ , options.retryIntervalForReconnection
18
+ )
19
+ return new GeyserClient(client, close, options.timeout)
20
+ }
21
+
22
+ private constructor(
23
+ private client: ClientProxy<IAPI>
24
+ , private closeClients: () => Promise<void>
25
+ , private timeout?: number
26
+ ) {}
27
+
28
+ async close(): Promise<void> {
29
+ await this.closeClients()
30
+ }
31
+
32
+ async getAllRateLimiterIds(timeout?: number): Promise<string[]> {
33
+ return await this.withTimeout(
34
+ () => this.client.getAllRateLimiterIds()
35
+ , timeout ?? this.timeout
36
+ )
37
+ }
38
+
39
+ async getRateLimiter(
40
+ rateLimiterId: string
41
+ , timeout?: number
42
+ ): Promise<IRateLimiterConfig | null> {
43
+ return await this.withTimeout(
44
+ () => this.client.getRateLimiter(rateLimiterId)
45
+ , timeout ?? this.timeout
46
+ )
47
+ }
48
+
49
+ async setRateLimiter(
50
+ rateLimiterId: string
51
+ , config: IRateLimiterConfig
52
+ , timeout?: number
53
+ ): Promise<void> {
54
+ await this.withTimeout(
55
+ () => this.client.setRateLimiter(rateLimiterId, config)
56
+ , timeout ?? this.timeout
57
+ )
58
+ }
59
+
60
+ async removeRateLimiter(rateLimiterId: string, timeout?: number): Promise<void> {
61
+ await this.withTimeout(
62
+ () => this.client.removeRateLimiter(rateLimiterId)
63
+ , timeout ?? this.timeout
64
+ )
65
+ }
66
+
67
+ /**
68
+ * 重置速率限制器的状态.
69
+ *
70
+ * @throws {RateLimiterNotFound}
71
+ */
72
+ async resetRateLimiter(rateLimiterId: string, timeout?: number): Promise<void> {
73
+ await this.withTimeout(
74
+ () => this.client.removeRateLimiter(rateLimiterId)
75
+ , timeout ?? this.timeout
76
+ )
77
+ }
78
+
79
+ /**
80
+ * @throws {RateLimiterNotFound}
81
+ */
82
+ async acquireToken(rateLimiterId: string, timeout?: number): Promise<void> {
83
+ await this.withTimeout(
84
+ () => this.client.acquireToken(rateLimiterId)
85
+ , timeout ?? this.timeout
86
+ )
87
+ }
88
+
89
+ private async withTimeout<T>(
90
+ fn: () => PromiseLike<T>
91
+ , timeout: number | undefined = this.timeout
92
+ ): Promise<T> {
93
+ if (timeout) {
94
+ return await withAbortSignal(timeoutSignal(timeout), fn)
95
+ } else {
96
+ return await fn()
97
+ }
98
+ }
99
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './geyser-client.js'
@@ -0,0 +1,27 @@
1
+ import { IAPI, expectedVersion } from '@src/contract.js'
2
+ import { ClientProxy } from 'delight-rpc'
3
+ import { createClient } from '@delight-rpc/extra-native-websocket'
4
+ import { ExtraNativeWebSocket, autoReconnect } from 'extra-native-websocket'
5
+
6
+ export async function createRPCClient(
7
+ url: string
8
+ , retryIntervalForReconnection?: number
9
+ ): Promise<{
10
+ client: ClientProxy<IAPI>
11
+ close: () => Promise<void>
12
+ }> {
13
+ const ws = new ExtraNativeWebSocket(() => new WebSocket(url))
14
+ const cancelAutoReconnect = autoReconnect(ws, retryIntervalForReconnection)
15
+ await ws.connect()
16
+
17
+ const [client, closeClient] = createClient<IAPI>(ws, { expectedVersion })
18
+
19
+ return {
20
+ client
21
+ , close: async () => {
22
+ closeClient()
23
+ cancelAutoReconnect()
24
+ await ws.close()
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,28 @@
1
+ import { IAPI, expectedVersion } from '@src/contract.js'
2
+ import { ClientProxy } from 'delight-rpc'
3
+ import { createClient } from '@delight-rpc/extra-websocket'
4
+ import { WebSocket } from 'ws'
5
+ import { ExtraWebSocket, autoReconnect } from 'extra-websocket'
6
+
7
+ export async function createRPCClient(
8
+ url: string
9
+ , retryIntervalForReconnection?: number
10
+ ): Promise<{
11
+ client: ClientProxy<IAPI>
12
+ close: () => Promise<void>
13
+ }> {
14
+ const ws = new ExtraWebSocket(() => new WebSocket(url))
15
+ const cancelAutoReconnect = autoReconnect(ws, retryIntervalForReconnection)
16
+ await ws.connect()
17
+
18
+ const [client, closeClient] = createClient<IAPI>(ws, { expectedVersion })
19
+
20
+ return {
21
+ client
22
+ , close: async () => {
23
+ closeClient()
24
+ cancelAutoReconnect()
25
+ await ws.close()
26
+ }
27
+ }
28
+ }