forked from ethereum/mist
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathweb3Base.js
More file actions
161 lines (133 loc) · 4.75 KB
/
web3Base.js
File metadata and controls
161 lines (133 loc) · 4.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
const _ = global._;
const Q = require('bluebird');
const oboe = require('oboe');
const SocketBase = require('./base');
const Socket = SocketBase.Socket;
const STATE = SocketBase.STATE;
module.exports = class Web3Socket extends Socket {
constructor(socketMgr, id) {
super(socketMgr, id);
this._sendRequests = {};
this._handleSocketResponse();
}
/**
* Send an RPC call.
* @param {Array|Object} single or array of payloads.
* @param {Object} options Additional options.
* @param {Boolean} [options.fullResult] If set then will return full result
* JSON, not just result value.
* @return {Promise}
*/
send(payload, options) {
return Q.try(() => {
if (!this.isConnected) {
throw new Error('Not connected');
}
const isBatch = _.isArray(payload);
const finalPayload = isBatch
? _.map(payload, p => this._finalizeSinglePayload(p))
: this._finalizeSinglePayload(payload);
/*
For batch requeests we use the id of the first request as the
id to refer to the batch as one. We can do this because the
response will also come back as a batch, in the same order as the
the requests within the batch were sent.
*/
const id = isBatch
? finalPayload[0].id
: finalPayload.id;
this._log.trace(
isBatch ? 'Batch request' : 'Request',
id, finalPayload
);
this._sendRequests[id] = {
options,
/* Preserve the original id of the request so that we can
update the response with it */
origId: (
isBatch ? _.map(payload, p => p.id) : payload.id
),
};
this.write(JSON.stringify(finalPayload));
return new Q((resolve, reject) => {
_.extend(this._sendRequests[id], {
resolve,
reject,
});
});
});
}
/**
* Construct a payload object.
* @param {Object} payload Payload to send.
* @param {String} payload.method Method name.
* @param {Object} [payload.params] Method arguments.
* @return {Object} final payload object
*/
_finalizeSinglePayload(payload) {
if (!payload.method) {
throw new Error('Method required');
}
return {
jsonrpc: '2.0',
id: _.uuid(),
method: payload.method,
params: payload.params || [],
};
}
/**
* Handle responses from Geth.
*/
_handleSocketResponse() {
oboe(this)
.done((result) => {
this._log.trace('JSON response', result);
try {
const isBatch = _.isArray(result);
const firstItem = isBatch ? result[0] : result;
const req = firstItem.id ? this._sendRequests[firstItem.id] : null;
if (req) {
this._log.trace(
isBatch ? 'Batch response' : 'Response',
firstItem.id, result
);
// if we don't want full JSON result, send just the result
if (!_.get(req, 'options.fullResult')) {
if (isBatch) {
result = _.map(result, r => r.result);
} else {
result = result.result;
}
} else {
// restore original ids
if (isBatch) {
req.origId.forEach((id, idx) => {
if (result[idx]) {
result[idx].id = id;
}
});
} else {
result.id = req.origId;
}
}
req.resolve({
isBatch,
result,
});
} else {
// not a response to a request so pass it on as a notification
this.emit('data-notification', result);
}
} catch (err) {
this._log.error('Error handling socket response', err);
}
})
.fail((err) => {
this._log.error('Socket response error', err);
_.each(this._sendRequests, (req) => {
req.reject(err);
});
this._sendRequests = {};
});
}
};