1
1
import { Provider } from '../provider' ;
2
2
import { ConsensusParams , NetworkInfo , Status } from '../types' ;
3
3
import { RPCRequest , RPCResponse } from '../spec/jsonrpc' ;
4
+ import { newRequest } from '../spec/utility' ;
5
+ import { ConsensusEndpoint } from '../endpoints' ;
6
+ import { WebSocket } from 'ws' ;
4
7
5
8
/**
6
9
* Provider based on WS JSON-RPC HTTP requests
@@ -24,8 +27,9 @@ export class WSProvider implements Provider {
24
27
*/
25
28
constructor ( baseURL : string , requestTimeout ?: number ) {
26
29
this . ws = new WebSocket ( baseURL ) ;
30
+
27
31
this . ws . addEventListener ( 'message' , ( event ) => {
28
- const response = JSON . parse ( event . data ) as RPCResponse < any > ;
32
+ const response = JSON . parse ( event . data as string ) as RPCResponse < any > ;
29
33
const request = this . requestMap . get ( response . id ) ;
30
34
if ( request ) {
31
35
this . requestMap . delete ( response . id ) ;
@@ -39,15 +43,28 @@ export class WSProvider implements Provider {
39
43
} ) ;
40
44
}
41
45
46
+ /**
47
+ * Closes the WS connection. Required when done working
48
+ * with the WS provider
49
+ */
50
+ closeConnection ( ) {
51
+ this . ws . close ( ) ;
52
+ }
53
+
42
54
/**
43
55
* Sends a request to the WS connection, and resolves
44
56
* upon receiving the response
45
57
* @param {RPCRequest } request the RPC request
46
58
* @returns {Promise<RPCResponse<any>> } the RPC response
47
59
*/
48
- sendRequest ( request : RPCRequest ) : Promise < RPCResponse < any > > {
60
+ async sendRequest < Result > ( request : RPCRequest ) : Promise < RPCResponse < Result > > {
61
+ // Make sure the connection is open
62
+ if ( this . ws . readyState != WebSocket . OPEN ) {
63
+ await this . waitForOpenConnection ( ) ;
64
+ }
65
+
49
66
// The promise will resolve as soon as the response is received
50
- const promise = new Promise < RPCResponse < any > > ( ( resolve , reject ) => {
67
+ const promise = new Promise < RPCResponse < Result > > ( ( resolve , reject ) => {
51
68
const timeout = setTimeout ( ( ) => {
52
69
this . requestMap . delete ( request . id ) ;
53
70
@@ -62,6 +79,52 @@ export class WSProvider implements Provider {
62
79
return promise ;
63
80
}
64
81
82
+ /**
83
+ * Parses the result from the response
84
+ * @param {RPCResponse<Result> } response the response to be parsed
85
+ * @returns {Result } the result of the response
86
+ */
87
+ parseResponse < Result > ( response : RPCResponse < Result > ) : Result {
88
+ if ( ! response ) {
89
+ throw new Error ( 'invalid response' ) ;
90
+ }
91
+
92
+ if ( response . error ) {
93
+ throw new Error ( response . error ?. message ) ;
94
+ }
95
+
96
+ if ( ! response . result ) {
97
+ throw new Error ( 'invalid response returned' ) ;
98
+ }
99
+
100
+ return response . result ;
101
+ }
102
+
103
+ /**
104
+ * Waits for the WS connection to be established
105
+ * @returns {Promise<null> } resolve / reject indicating success
106
+ */
107
+ waitForOpenConnection = ( ) => {
108
+ return new Promise ( ( resolve , reject ) => {
109
+ const maxNumberOfAttempts = 10 ;
110
+ const intervalTime = 200 ; //ms
111
+
112
+ let currentAttempt = 0 ;
113
+ const interval = setInterval ( ( ) => {
114
+ if ( this . ws . readyState === WebSocket . OPEN ) {
115
+ clearInterval ( interval ) ;
116
+ resolve ( null ) ;
117
+ }
118
+
119
+ currentAttempt ++ ;
120
+ if ( currentAttempt > maxNumberOfAttempts - 1 ) {
121
+ clearInterval ( interval ) ;
122
+ reject ( new Error ( 'Maximum number of attempts exceeded' ) ) ;
123
+ }
124
+ } , intervalTime ) ;
125
+ } ) ;
126
+ } ;
127
+
65
128
estimateGas ( tx : any ) : Promise < number > {
66
129
return Promise . reject ( 'implement me' ) ;
67
130
}
@@ -94,8 +157,12 @@ export class WSProvider implements Provider {
94
157
return Promise . reject ( 'implement me' ) ;
95
158
}
96
159
97
- getNetwork ( ) : Promise < NetworkInfo > {
98
- return Promise . reject ( 'implement me' ) ;
160
+ async getNetwork ( ) : Promise < NetworkInfo > {
161
+ const response = await this . sendRequest < NetworkInfo > (
162
+ newRequest ( ConsensusEndpoint . NET_INFO )
163
+ ) ;
164
+
165
+ return this . parseResponse < NetworkInfo > ( response ) ;
99
166
}
100
167
101
168
getSequence ( address : string , height ?: number ) : Promise < number > {
0 commit comments