2015-06-24 12:56:32 +00:00
|
|
|
/*
|
2015-10-08 07:34:07 +00:00
|
|
|
This file is part of web3.js.
|
2015-06-24 12:56:32 +00:00
|
|
|
|
2015-10-08 07:34:07 +00:00
|
|
|
web3.js is free software: you can redistribute it and/or modify
|
2015-06-24 12:56:32 +00:00
|
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
2015-10-08 07:34:07 +00:00
|
|
|
web3.js is distributed in the hope that it will be useful,
|
2015-06-24 12:56:32 +00:00
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
2015-10-08 07:34:07 +00:00
|
|
|
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
|
2015-06-24 12:56:32 +00:00
|
|
|
*/
|
|
|
|
/** @file ipcprovider.js
|
|
|
|
* @authors:
|
|
|
|
* Fabian Vogelsteller <fabian@ethdev.com>
|
|
|
|
* @date 2015
|
|
|
|
*/
|
|
|
|
|
|
|
|
"use strict";
|
|
|
|
|
|
|
|
var utils = require('../utils/utils');
|
|
|
|
var errors = require('./errors');
|
|
|
|
|
|
|
|
|
|
|
|
var IpcProvider = function (path, net) {
|
|
|
|
var _this = this;
|
|
|
|
this.responseCallbacks = {};
|
|
|
|
this.path = path;
|
|
|
|
|
2015-06-26 14:15:23 +00:00
|
|
|
this.connection = net.connect({path: this.path});
|
2015-06-24 12:56:32 +00:00
|
|
|
|
2015-06-26 14:15:23 +00:00
|
|
|
this.connection.on('error', function(e){
|
2015-06-30 13:14:12 +00:00
|
|
|
console.error('IPC Connection Error', e);
|
2015-06-30 09:43:18 +00:00
|
|
|
_this._timeout();
|
|
|
|
});
|
|
|
|
|
2015-07-02 18:04:27 +00:00
|
|
|
this.connection.on('end', function(){
|
2015-06-30 09:43:18 +00:00
|
|
|
_this._timeout();
|
2015-06-26 14:15:23 +00:00
|
|
|
});
|
2015-06-24 12:56:32 +00:00
|
|
|
|
|
|
|
|
|
|
|
// LISTEN FOR CONNECTION RESPONSES
|
2015-07-02 15:47:35 +00:00
|
|
|
this.connection.on('data', function(data) {
|
2015-07-02 18:04:27 +00:00
|
|
|
/*jshint maxcomplexity: 6 */
|
2015-07-02 15:47:35 +00:00
|
|
|
|
2015-07-20 11:50:36 +00:00
|
|
|
_this._parseResponse(data.toString()).forEach(function(result){
|
2015-07-02 15:47:35 +00:00
|
|
|
|
2015-07-20 11:50:36 +00:00
|
|
|
var id = null;
|
2015-07-02 15:47:35 +00:00
|
|
|
|
|
|
|
// get the id which matches the returned id
|
|
|
|
if(utils.isArray(result)) {
|
|
|
|
result.forEach(function(load){
|
|
|
|
if(_this.responseCallbacks[load.id])
|
|
|
|
id = load.id;
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
id = result.id;
|
|
|
|
}
|
|
|
|
|
|
|
|
// fire the callback
|
|
|
|
if(_this.responseCallbacks[id]) {
|
|
|
|
_this.responseCallbacks[id](null, result);
|
|
|
|
delete _this.responseCallbacks[id];
|
|
|
|
}
|
2015-07-02 18:04:27 +00:00
|
|
|
});
|
2015-06-24 12:56:32 +00:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2015-07-20 11:50:36 +00:00
|
|
|
/**
|
|
|
|
Will parse the response and make an array out of it.
|
|
|
|
|
|
|
|
@method _parseResponse
|
|
|
|
@param {String} data
|
|
|
|
*/
|
|
|
|
IpcProvider.prototype._parseResponse = function(data) {
|
|
|
|
var _this = this,
|
|
|
|
returnValues = [];
|
|
|
|
|
|
|
|
// DE-CHUNKER
|
|
|
|
var dechunkedData = data
|
|
|
|
.replace(/\}\{/g,'}|--|{') // }{
|
|
|
|
.replace(/\}\]\[\{/g,'}]|--|[{') // }][{
|
|
|
|
.replace(/\}\[\{/g,'}|--|[{') // }[{
|
|
|
|
.replace(/\}\]\{/g,'}]|--|{') // }]{
|
|
|
|
.split('|--|');
|
|
|
|
|
|
|
|
dechunkedData.forEach(function(data){
|
|
|
|
|
|
|
|
// prepend the last chunk
|
|
|
|
if(_this.lastChunk)
|
|
|
|
data = _this.lastChunk + data;
|
|
|
|
|
|
|
|
var result = null;
|
|
|
|
|
|
|
|
try {
|
|
|
|
result = JSON.parse(data);
|
|
|
|
|
|
|
|
} catch(e) {
|
|
|
|
|
|
|
|
_this.lastChunk = data;
|
|
|
|
|
|
|
|
// start timeout to cancel all requests
|
|
|
|
clearTimeout(_this.lastChunkTimeout);
|
|
|
|
_this.lastChunkTimeout = setTimeout(function(){
|
|
|
|
_this.timeout();
|
|
|
|
throw errors.InvalidResponse(data);
|
|
|
|
}, 1000 * 15);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// cancel timeout and set chunk to null
|
|
|
|
clearTimeout(_this.lastChunkTimeout);
|
|
|
|
_this.lastChunk = null;
|
|
|
|
|
|
|
|
if(result)
|
|
|
|
returnValues.push(result);
|
|
|
|
});
|
|
|
|
|
|
|
|
return returnValues;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-06-24 12:56:32 +00:00
|
|
|
/**
|
|
|
|
Get the adds a callback to the responseCallbacks object,
|
|
|
|
which will be called if a response matching the response Id will arrive.
|
|
|
|
|
2015-07-20 11:50:36 +00:00
|
|
|
@method _addResponseCallback
|
2015-06-24 12:56:32 +00:00
|
|
|
*/
|
2015-07-20 11:50:36 +00:00
|
|
|
IpcProvider.prototype._addResponseCallback = function(payload, callback) {
|
2015-06-24 12:56:32 +00:00
|
|
|
var id = payload.id || payload[0].id;
|
2015-06-30 09:43:18 +00:00
|
|
|
var method = payload.method || payload[0].method;
|
2015-06-24 12:56:32 +00:00
|
|
|
|
|
|
|
this.responseCallbacks[id] = callback;
|
2015-06-30 09:43:18 +00:00
|
|
|
this.responseCallbacks[id].method = method;
|
2015-06-24 12:56:32 +00:00
|
|
|
};
|
|
|
|
|
2015-06-30 09:43:18 +00:00
|
|
|
/**
|
|
|
|
Timeout all requests when the end/error event is fired
|
2015-06-24 12:56:32 +00:00
|
|
|
|
2015-06-30 09:43:18 +00:00
|
|
|
@method _timeout
|
|
|
|
*/
|
|
|
|
IpcProvider.prototype._timeout = function() {
|
2015-07-01 12:41:37 +00:00
|
|
|
for(var key in this.responseCallbacks) {
|
|
|
|
if(this.responseCallbacks.hasOwnProperty(key)){
|
2015-10-14 21:07:59 +00:00
|
|
|
this.responseCallbacks[key](errors.InvalidConnection('on IPC'));
|
2015-07-02 17:19:32 +00:00
|
|
|
delete this.responseCallbacks[key];
|
2015-06-30 09:43:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
Check if the current connection is still valid.
|
|
|
|
|
|
|
|
@method isConnected
|
|
|
|
*/
|
2015-06-24 12:56:32 +00:00
|
|
|
IpcProvider.prototype.isConnected = function() {
|
2015-07-02 17:19:32 +00:00
|
|
|
var _this = this;
|
|
|
|
|
2015-06-24 12:56:32 +00:00
|
|
|
// try reconnect, when connection is gone
|
2015-07-20 11:50:36 +00:00
|
|
|
if(!_this.connection.writable)
|
|
|
|
_this.connection.connect({path: _this.path});
|
2015-06-24 12:56:32 +00:00
|
|
|
|
2015-06-26 12:35:57 +00:00
|
|
|
return !!this.connection.writable;
|
2015-06-24 12:56:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
IpcProvider.prototype.send = function (payload) {
|
2015-06-24 17:10:36 +00:00
|
|
|
|
|
|
|
if(this.connection.writeSync) {
|
2015-07-09 15:35:29 +00:00
|
|
|
var result;
|
2015-06-24 17:10:36 +00:00
|
|
|
|
|
|
|
// try reconnect, when connection is gone
|
2015-06-26 12:35:57 +00:00
|
|
|
if(!this.connection.writable)
|
2015-06-24 17:10:36 +00:00
|
|
|
this.connection.connect({path: this.path});
|
|
|
|
|
2015-07-09 15:35:29 +00:00
|
|
|
var data = this.connection.writeSync(JSON.stringify(payload));
|
2015-06-24 17:10:36 +00:00
|
|
|
|
|
|
|
try {
|
2015-07-09 15:35:29 +00:00
|
|
|
result = JSON.parse(data);
|
2015-06-24 17:10:36 +00:00
|
|
|
} catch(e) {
|
2015-07-09 15:35:29 +00:00
|
|
|
throw errors.InvalidResponse(data);
|
2015-06-24 17:10:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
throw new Error('You tried to send "'+ payload.method +'" synchronously. Synchronous requests are not supported by the IPC provider.');
|
|
|
|
}
|
2015-06-24 12:56:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
IpcProvider.prototype.sendAsync = function (payload, callback) {
|
|
|
|
// try reconnect, when connection is gone
|
2015-06-26 12:35:57 +00:00
|
|
|
if(!this.connection.writable)
|
2015-06-24 12:56:32 +00:00
|
|
|
this.connection.connect({path: this.path});
|
|
|
|
|
|
|
|
|
|
|
|
this.connection.write(JSON.stringify(payload));
|
2015-07-20 11:50:36 +00:00
|
|
|
this._addResponseCallback(payload, callback);
|
2015-06-24 12:56:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
module.exports = IpcProvider;
|
|
|
|
|