Merge pull request #1 from ranchimall/api-improvements
API Improvements
This commit is contained in:
commit
285ccb1471
161
lib/addresses.js
161
lib/addresses.js
@ -22,12 +22,19 @@ AddressController.prototype.show = function(req, res) {
|
|||||||
noTxList: parseInt(req.query.noTxList)
|
noTxList: parseInt(req.query.noTxList)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
self.common.bindStopFlagOnClose(res, options);
|
||||||
|
|
||||||
|
/*DEPRECATED
|
||||||
if (req.query.from && req.query.to) {
|
if (req.query.from && req.query.to) {
|
||||||
options.from = parseInt(req.query.from);
|
options.from = parseInt(req.query.from);
|
||||||
options.to = parseInt(req.query.to);
|
options.to = parseInt(req.query.to);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
if (req.query.after) {
|
||||||
|
options.after = req.query.after;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._address.getAddressSummary(req.addr, options, function(err, data) {
|
self._address.getAddressSummary(req.addr, options, function(err, data) {
|
||||||
if(err) {
|
if(err) {
|
||||||
return self.common.handleErrors(err, res);
|
return self.common.handleErrors(err, res);
|
||||||
}
|
}
|
||||||
@ -40,25 +47,59 @@ AddressController.prototype.show = function(req, res) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AddressController.prototype.show_ws = function(ws, req) {
|
||||||
|
var self = this;
|
||||||
|
var options = { noTxList: true };
|
||||||
|
|
||||||
|
if (req.query.after) {
|
||||||
|
options.after = req.query.after;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.common.bindStopFlagOnClose(ws, options);
|
||||||
|
|
||||||
|
self._address.getAddressSummary(req.addr, options, function (err, data) {
|
||||||
|
if(err) {
|
||||||
|
return self.common.handleErrors_ws(err, ws);
|
||||||
|
}
|
||||||
|
|
||||||
|
ws.send({data});
|
||||||
|
|
||||||
|
}, function(err, result) {
|
||||||
|
|
||||||
|
if(err) {
|
||||||
|
return self.common.handleErrors_ws(err, ws);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ws.readyState === ws.OPEN){
|
||||||
|
ws.send({result});
|
||||||
|
ws.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
AddressController.prototype.balance = function(req, res) {
|
AddressController.prototype.balance = function(req, res) {
|
||||||
this.addressSummarySubQuery(req, res, 'balanceSat');
|
this.addressSummarySubQuery(req, res, 'balance');
|
||||||
};
|
};
|
||||||
|
|
||||||
AddressController.prototype.totalReceived = function(req, res) {
|
AddressController.prototype.totalReceived = function(req, res) {
|
||||||
this.addressSummarySubQuery(req, res, 'totalReceivedSat');
|
this.addressSummarySubQuery(req, res, 'totalReceived');
|
||||||
};
|
};
|
||||||
|
|
||||||
AddressController.prototype.totalSent = function(req, res) {
|
AddressController.prototype.totalSent = function(req, res) {
|
||||||
this.addressSummarySubQuery(req, res, 'totalSentSat');
|
this.addressSummarySubQuery(req, res, 'totalSent');
|
||||||
};
|
};
|
||||||
|
|
||||||
AddressController.prototype.unconfirmedBalance = function(req, res) {
|
AddressController.prototype.unconfirmedBalance = function(req, res) {
|
||||||
this.addressSummarySubQuery(req, res, 'unconfirmedBalanceSat');
|
this.addressSummarySubQuery(req, res, 'unconfirmedBalance');
|
||||||
};
|
};
|
||||||
|
|
||||||
AddressController.prototype.addressSummarySubQuery = function(req, res, param) {
|
AddressController.prototype.addressSummarySubQuery = function(req, res, param) {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.getAddressSummary(req.addr, {}, function(err, data) {
|
var options = { noTxList: true };
|
||||||
|
self.common.bindStopFlagOnClose(res, options);
|
||||||
|
|
||||||
|
self.getAddressSummary(req.addr, options, function(err, data) {
|
||||||
if(err) {
|
if(err) {
|
||||||
return self.common.handleErrors(err, res);
|
return self.common.handleErrors(err, res);
|
||||||
}
|
}
|
||||||
@ -70,23 +111,23 @@ AddressController.prototype.addressSummarySubQuery = function(req, res, param) {
|
|||||||
AddressController.prototype.getAddressSummary = function(address, options, callback) {
|
AddressController.prototype.getAddressSummary = function(address, options, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
this._address.getAddressSummary(address, options, function(err, summary) {
|
self._address.getAddressSummary(address, options, function(err, summary) {
|
||||||
if(err) {
|
if(err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
var transformed = {
|
var transformed = {
|
||||||
address: self.common.translateOutputAddress(address),
|
address: self.common.translateOutputAddress(address),
|
||||||
balance: Unit.fromSatoshis(summary.balance).toBTC(),
|
balance: summary.balance,
|
||||||
balanceSat: summary.balance,
|
balanceSat: summary.balanceSat,
|
||||||
totalReceived: Unit.fromSatoshis(summary.totalReceived).toBTC(),
|
totalReceived: summary.totalReceived,
|
||||||
totalReceivedSat: summary.totalReceivedSat,
|
totalReceivedSat: summary.totalReceivedSat,
|
||||||
totalSent: Unit.fromSatoshis(summary.totalSent).toBTC(),
|
totalSent: summary.totalSent,
|
||||||
totalSentSat: summary.totalSentSat,
|
totalSentSat: summary.totalSentSat,
|
||||||
unconfirmedBalance: Unit.fromSatoshis(summary.unconfirmedBalance).toBTC(),
|
unconfirmedBalance: summary.unconfirmedBalance,
|
||||||
unconfirmedBalanceSat: summary.unconfirmedBalance,
|
unconfirmedBalanceSat: summary.unconfirmedBalanceSat,
|
||||||
unconfirmedTxApperances: summary.unconfirmedAppearances, // misspelling - ew
|
unconfirmedTxApperances: summary.unconfirmedTxApperances,
|
||||||
txApperances: summary.txApperances, // yuck
|
txApperances: summary.txApperances,
|
||||||
transactions: summary.transactions
|
transactions: summary.transactions
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -114,7 +155,7 @@ AddressController.prototype.checkAddrs = function(req, res, next) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!_.isArray(req.addrs) || _.compact(req.addrs).length < 1) {
|
if(!_.isArray(req.addrs) || _.compact(req.addrs).length < 1) {
|
||||||
return this.common.handleErrors({
|
return self.common.handleErrors({
|
||||||
message: 'Must include address',
|
message: 'Must include address',
|
||||||
code: 1
|
code: 1
|
||||||
}, res);
|
}, res);
|
||||||
@ -125,7 +166,7 @@ AddressController.prototype.checkAddrs = function(req, res, next) {
|
|||||||
req.addr = req.addrs[0];
|
req.addr = req.addrs[0];
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.log('[addresses.js.130]', e); //TODO
|
console.log('[addresses.js.130]', e); //TODO
|
||||||
return this.common.handleErrors({
|
return self.common.handleErrors({
|
||||||
message: 'Invalid address: ' + e,
|
message: 'Invalid address: ' + e,
|
||||||
code: 1
|
code: 1
|
||||||
}, res);
|
}, res);
|
||||||
@ -137,7 +178,7 @@ console.log('[addresses.js.130]', e); //TODO
|
|||||||
AddressController.prototype.utxo = function(req, res) {
|
AddressController.prototype.utxo = function(req, res) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
this._address.getAddressUnspentOutputs(req.addr, {}, function(err, utxos) {
|
self._address.getAddressUnspentOutputs(req.addr, {}, function(err, utxos) {
|
||||||
var results;
|
var results;
|
||||||
if(err) {
|
if(err) {
|
||||||
return self.common.handleErrors(err, res);
|
return self.common.handleErrors(err, res);
|
||||||
@ -245,11 +286,21 @@ AddressController.prototype.multiutxo = function(req, res) {
|
|||||||
AddressController.prototype.multitxs = function(req, res) {
|
AddressController.prototype.multitxs = function(req, res) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
var options = {
|
var options = {};
|
||||||
from: parseInt(req.query.from) || parseInt(req.body.from) || 0
|
|
||||||
};
|
|
||||||
|
|
||||||
options.to = parseInt(req.query.to) || parseInt(req.body.to) || parseInt(options.from) + 10;
|
options.after = req.query.after || req.body.after || undefined;
|
||||||
|
|
||||||
|
//Temporary support
|
||||||
|
if(req.query.from || req.body.from) {
|
||||||
|
options.from = parseInt(req.query.from) || parseInt(req.body.from) || undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Temporary support
|
||||||
|
if(req.query.to || req.body.to) {
|
||||||
|
options.to = parseInt(req.query.to) || parseInt(req.body.to) || undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.common.bindStopFlagOnClose(res, options);
|
||||||
|
|
||||||
self._address.getAddressHistory(req.addrs, options, function(err, result) {
|
self._address.getAddressHistory(req.addrs, options, function(err, result) {
|
||||||
|
|
||||||
@ -265,10 +316,14 @@ AddressController.prototype.multitxs = function(req, res) {
|
|||||||
return self.common.handleErrors(err, res);
|
return self.common.handleErrors(err, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var lastItem = items.find(a => a.confirmations !== 0), //assuming items is recent tx first order
|
||||||
|
lastItem = typeof lastItem === 'object' ? lastItem.txid: undefined
|
||||||
|
|
||||||
var ret = {
|
var ret = {
|
||||||
totalItems: result.totalCount,
|
totalItems: result.totalCount,
|
||||||
from: options.from,
|
lastItem: lastItem,
|
||||||
to: Math.min(options.to, result.totalCount),
|
//from: options.from,
|
||||||
|
//to: Math.min(options.to, result.totalCount),
|
||||||
items: items
|
items: items
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -278,6 +333,64 @@ AddressController.prototype.multitxs = function(req, res) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AddressController.prototype.multitxs_ws = function(ws, req) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
var options = {};
|
||||||
|
|
||||||
|
if (req.query.after) {
|
||||||
|
options.after = req.query.after;
|
||||||
|
}
|
||||||
|
|
||||||
|
options.txNotNeeded = true;
|
||||||
|
|
||||||
|
var transformOptions = self._getTransformOptions(req);
|
||||||
|
|
||||||
|
self.common.bindStopFlagOnClose(ws, options);
|
||||||
|
|
||||||
|
var lastItem = {id: '', height: 0};
|
||||||
|
|
||||||
|
self._address.getAddressHistory(req.addrs, options, function (err, data) {
|
||||||
|
if(err) {
|
||||||
|
return self.common.handleErrors_ws(err, ws, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.txController.transformTransaction(data, transformOptions, function(err, tx){
|
||||||
|
|
||||||
|
if(err) {
|
||||||
|
return self.common.handleErrors_ws(err, ws, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
//finding the last key (useful for `after` option on next request call)
|
||||||
|
if(tx.confirmations)
|
||||||
|
if(lastItem.height < tx.blockheight || (lastItem.height == tx.blockheight && lastItem.id < tx.txid)){
|
||||||
|
lastItem.id = tx.txid;
|
||||||
|
lastItem.height = tx.blockheight;
|
||||||
|
}
|
||||||
|
|
||||||
|
ws.send({data: tx})
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}, function(err, result) {
|
||||||
|
|
||||||
|
if(err) {
|
||||||
|
return self.common.handleErrors_ws(err, ws);
|
||||||
|
}
|
||||||
|
|
||||||
|
var ret = {
|
||||||
|
totalItems: result.totalCount,
|
||||||
|
lastItem: lastItem.id
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ws.readyState === ws.OPEN){
|
||||||
|
ws.send({result: ret});
|
||||||
|
ws.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
AddressController.prototype.transformAddressHistoryForMultiTxs = function(txs, options, callback) {
|
AddressController.prototype.transformAddressHistoryForMultiTxs = function(txs, options, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,17 @@ Common.prototype.notReady = function (err, res, p) {
|
|||||||
res.status(503).send('Server not yet ready. Sync Percentage:' + p);
|
res.status(503).send('Server not yet ready. Sync Percentage:' + p);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Common.prototype.notReady_ws = function (err, ws, p) {
|
||||||
|
if(ws.readyState !== ws.OPEN)
|
||||||
|
return;
|
||||||
|
ws.send({error: {message: 'Server not yet ready. Sync Percentage:' + p, code: 503}});
|
||||||
|
ws.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
Common.prototype.bindStopFlagOnClose = function (res_ws, obj) {
|
||||||
|
res_ws.on("close", () => obj.flag_stop = true);
|
||||||
|
};
|
||||||
|
|
||||||
Common.prototype.handleErrors = function (err, res) {
|
Common.prototype.handleErrors = function (err, res) {
|
||||||
if (err) {
|
if (err) {
|
||||||
if (err.code) {
|
if (err.code) {
|
||||||
@ -29,6 +40,22 @@ Common.prototype.handleErrors = function (err, res) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Common.prototype.handleErrors_ws = function (err, ws, close = true) {
|
||||||
|
if(ws.readyState !== ws.OPEN)
|
||||||
|
return;
|
||||||
|
if (err) {
|
||||||
|
if (err.code)
|
||||||
|
ws.send({error: {message: err.message, code: err.code}});
|
||||||
|
else {
|
||||||
|
this.log.error(err.stack);
|
||||||
|
ws.send({error: {message: err.message, code: 503}});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ws.send({error: {message: 'Not found', code: 404}});
|
||||||
|
}
|
||||||
|
if(close)
|
||||||
|
ws.close();
|
||||||
|
}
|
||||||
|
|
||||||
Common.prototype.translateInputAddresses= function(addresses) {
|
Common.prototype.translateInputAddresses= function(addresses) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|||||||
@ -143,7 +143,7 @@ FlosightAPI.prototype._getRateLimiter = function() {
|
|||||||
return limiter;
|
return limiter;
|
||||||
};
|
};
|
||||||
|
|
||||||
FlosightAPI.prototype.setupRoutes = function(app) {
|
FlosightAPI.prototype.setupRoutes = function(app, express, express_ws) {
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
@ -184,6 +184,9 @@ FlosightAPI.prototype.setupRoutes = function(app) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//Add ws listener to app
|
||||||
|
var expressWS = express_ws(app);
|
||||||
|
|
||||||
//Block routes
|
//Block routes
|
||||||
var blockOptions = {
|
var blockOptions = {
|
||||||
node: this.node,
|
node: this.node,
|
||||||
@ -216,10 +219,12 @@ FlosightAPI.prototype.setupRoutes = function(app) {
|
|||||||
// Address routes
|
// Address routes
|
||||||
var addresses = new AddressController(this.node, this.translateAddresses);
|
var addresses = new AddressController(this.node, this.translateAddresses);
|
||||||
app.get('/addr/:addr', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.show.bind(addresses));
|
app.get('/addr/:addr', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.show.bind(addresses));
|
||||||
|
app.ws('/addr/:addr', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.show_ws.bind(addresses));
|
||||||
app.get('/addr/:addr/utxo', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.utxo.bind(addresses));
|
app.get('/addr/:addr/utxo', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.utxo.bind(addresses));
|
||||||
app.get('/addrs/:addrs/utxo', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.multiutxo.bind(addresses));
|
app.get('/addrs/:addrs/utxo', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.multiutxo.bind(addresses));
|
||||||
app.post('/addrs/utxo', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.multiutxo.bind(addresses));
|
app.post('/addrs/utxo', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.multiutxo.bind(addresses));
|
||||||
app.get('/addrs/:addrs/txs', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.multitxs.bind(addresses));
|
app.get('/addrs/:addrs/txs', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.multitxs.bind(addresses));
|
||||||
|
app.ws('/addrs/:addrs/txs', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.multitxs_ws.bind(addresses));
|
||||||
app.post('/addrs/txs', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.multitxs.bind(addresses));
|
app.post('/addrs/txs', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.multitxs.bind(addresses));
|
||||||
|
|
||||||
// Address property routes
|
// Address property routes
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "flosight-api",
|
"name": "flosight-api",
|
||||||
"description": "A Florincoin blockchain REST and web socket API service for Flocore Node.",
|
"description": "A Florincoin blockchain REST and web socket API service for Flocore Node.",
|
||||||
"version": "5.1.0-beta.75",
|
"version": "5.1.1-beta-rm",
|
||||||
"repository": "git://github.com/oipwg/flosight-api.git",
|
"repository": "git://github.com/ranchimall/flosight-api.git",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/oipwg/flosight-api/issues"
|
"url": "https://github.com/ranchimall/flosight-api/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/oipwg/flosight-api",
|
"homepage": "https://github.com/ranchimall/flosight-api",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"flosight",
|
"flosight",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user