Skip to content

Commit 38e2626

Browse files
author
7kharov
authored
Merge pull request #1 from 7kharov/electrumx-persistence
Add electrum config for server version, ping strategy and reconnection
2 parents d54b794 + 7eaa018 commit 38e2626

File tree

4 files changed

+116
-47
lines changed

4 files changed

+116
-47
lines changed

lib/client.js

Lines changed: 44 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,97 +1,107 @@
11
'use strict'
2+
23
const EventEmitter = require('events').EventEmitter
34
const util = require('./util')
45
const initSocket = require('./init_socket')
56
const connectSocket = require('./connect_socket')
67

7-
class Client{
8-
constructor(port, host, protocol = 'tcp', options = void 0){
8+
class Client {
9+
constructor(port, host, protocol, options) {
910
this.id = 0;
10-
this.port = port
11-
this.host = host
12-
this.callback_message_queue = {}
13-
this.subscribe = new EventEmitter()
14-
this.conn = initSocket(this, protocol, options)
11+
this.port = port;
12+
this.host = host;
13+
this.callback_message_queue = {};
14+
this.subscribe = new EventEmitter();
1515
this.mp = new util.MessageParser((body, n) => {
1616
this.onMessage(body, n)
17-
})
18-
this.status = 0
17+
});
18+
this.initSocketConnection(protocol, options);
1919
}
2020

21-
connect(){
22-
if(this.status) {
23-
return Promise.resolve()
21+
initSocketConnection(protocol = 'tcp', options = void 0) {
22+
this.conn = initSocket(this, protocol, options);
23+
this.status = 0;
24+
}
25+
26+
connect() {
27+
if (this.status === 1) {
28+
return Promise.resolve();
2429
}
25-
this.status = 1
26-
return connectSocket(this.conn, this.port, this.host)
30+
this.status = 1;
31+
return connectSocket(this.conn, this.port, this.host);
2732
}
2833

29-
close(){
30-
if(!this.status) {
31-
return
34+
close() {
35+
if (this.status === 0) {
36+
return ;
3237
}
3338
this.conn.end()
3439
this.conn.destroy()
3540
this.status = 0
3641
}
3742

38-
request(method, params){
39-
if(!this.status) {
43+
request(method, params) {
44+
if (this.status === 0) {
4045
return Promise.reject(new Error('ESOCKET'))
4146
}
4247
return new Promise((resolve, reject) => {
4348
const id = ++this.id;
4449
const content = util.makeRequest(method, params, id);
4550
this.callback_message_queue[id] = util.createPromiseResult(resolve, reject);
4651
this.conn.write(content + '\n');
47-
})
52+
});
4853
}
4954

50-
response(msg){
55+
response(msg) {
5156
const callback = this.callback_message_queue[msg.id]
52-
if(callback){
57+
if (callback) {
5358
delete this.callback_message_queue[msg.id]
54-
if(msg.error){
59+
if (msg.error) {
5560
callback(msg.error)
56-
}else{
61+
} else {
5762
callback(null, msg.result)
5863
}
59-
}else{
64+
} else {
65+
console.log("Can't get callback");
6066
; // can't get callback
6167
}
6268
}
6369

64-
onMessage(body, n){
70+
onMessage(body, n) {
6571
const msg = JSON.parse(body)
66-
if(msg instanceof Array){
72+
if (msg instanceof Array) {
6773
; // don't support batch request
6874
} else {
69-
if(msg.id !== void 0){
75+
if (msg.id !== void 0) {
7076
this.response(msg)
71-
}else{
77+
} else {
7278
this.subscribe.emit(msg.method, msg.params)
7379
}
7480
}
7581
}
7682

77-
onConnect(){
83+
onConnect() {
7884
}
7985

80-
onClose(){
86+
onClose(e) {
87+
this.status = 0;
88+
console.log("OnClose:" + e);
8189
Object.keys(this.callback_message_queue).forEach((key) => {
8290
this.callback_message_queue[key](new Error('close connect'))
8391
delete this.callback_message_queue[key]
8492
})
8593
}
8694

87-
onRecv(chunk){
95+
onRecv(chunk) {
8896
this.mp.run(chunk)
8997
}
9098

91-
onEnd(){
99+
onEnd(e) {
100+
console.log("OnEnd:" + e);
92101
}
93102

94-
onError(e){
103+
onError(e) {
104+
console.log("OnError:" + e);
95105
}
96106

97107
}

lib/connect_socket.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ const connectSocket = (conn, port, host) => {
44
return new Promise((resolve, reject) => {
55
const errorHandler = (e) => reject(e)
66
conn.connect(port, host, () => {
7-
conn.removeListener('error', errorHandler)
8-
resolve()
9-
})
10-
conn.on('error', errorHandler)
7+
conn.removeListener('error', errorHandler);
8+
resolve();
9+
});
10+
conn.on('error', errorHandler);
1111
})
1212
}
1313

lib/electrum_client.js

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,79 @@
1+
'use strict'
2+
13
const Client = require("./client")
2-
class ElectrumClient extends Client{
3-
constructor(port, host, protocol, options){
4-
super(port, host, protocol, options)
4+
5+
class ElectrumClient extends Client {
6+
7+
constructor(port, host, protocol, options) {
8+
super(port, host, protocol, options);
9+
this.timeLastCall = 0;
10+
}
11+
12+
initElectrum(electrumConfig, persistencePolicy = { maxRetry: 1000, callback: null }) {
13+
this.persistencePolicy = persistencePolicy;
14+
this.electrumConfig = electrumConfig;
15+
this.timeLastCall = 0;
16+
return this
17+
.connect()
18+
.then(() => this.server_version(this.electrumConfig.client, this.electrumConfig.version))
19+
;
20+
}
21+
22+
// Override parent
23+
request(method, params) {
24+
this.timeLastCall = new Date().getTime();
25+
const parentPromise = super.request(method, params);
26+
return parentPromise
27+
.then((response) => {
28+
this.keepAlive();
29+
return response;
30+
})
31+
;
532
}
6-
onClose(){
33+
34+
onClose() {
735
super.onClose()
836
const list = [
937
'server.peers.subscribe',
1038
'blockchain.numblocks.subscribe',
1139
'blockchain.headers.subscribe',
1240
'blockchain.address.subscribe'
13-
]
14-
list.forEach(event => this.subscribe.removeAllListeners(event))
41+
];
42+
list.forEach(event => this.subscribe.removeAllListeners(event));
43+
setTimeout(() => {
44+
if (this.persistencePolicy != null && this.persistencePolicy.maxRetry > 0) {
45+
this.reconnect();
46+
this.persistencePolicy.maxRetry -= 1;
47+
} else if (this.persistencePolicy != null && this.persistencePolicy.callback != null) {
48+
this.persistencePolicy.callback();
49+
} else if (this.persistencePolicy == null) {
50+
this.reconnect();
51+
}
52+
}, 10000);
53+
}
54+
55+
// ElectrumX persistancy
56+
keepAlive() {
57+
if (this.timeout != null) {
58+
clearTimeout(this.timeout);
59+
}
60+
this.timeout = setTimeout(() => {
61+
if (this.timeLastCall !== 0 &&
62+
new Date().getTime() > this.timeLastCall + 10000/2) {
63+
this.server_ping();
64+
}
65+
}, 10000);
1566
}
16-
server_version(client_name, protocol_version){
17-
return this.request('server.version', [client_name, protocol_version])
67+
68+
69+
reconnect() {
70+
this.initSocketConnection();
71+
return this.initElectrum(this.electrumConfig);
72+
}
73+
74+
// ElectrumX API
75+
server_version(client_name, protocol_version) {
76+
return this.request('server.version', [client_name, protocol_version]);
1877
}
1978
server_banner(){
2079
return this.request('server.banner', [])

lib/init_socket.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const net = require('net');
44
const TIMEOUT = 10000
55

66
const getSocket = (protocol, options) => {
7-
switch(protocol){
7+
switch (protocol) {
88
case 'tcp':
99
return new net.Socket();
1010
case 'tls':

0 commit comments

Comments
 (0)