WIP
This commit is contained in:
parent
47dd9c89b6
commit
234dd9ef94
2 changed files with 142 additions and 206 deletions
153
lib/plugins.js
153
lib/plugins.js
|
|
@ -6,7 +6,6 @@ var logger = require('./logger');
|
|||
|
||||
|
||||
var SATOSHI_FACTOR = 1e8;
|
||||
var SESSION_TIMEOUT = 60 * 60 * 1000;
|
||||
var POLLING_RATE = 60 * 1000; // poll each minute
|
||||
|
||||
var RECOMMENDED_FEE = 10000;
|
||||
|
|
@ -34,9 +33,9 @@ var lastRates = {};
|
|||
var balanceInterval = null;
|
||||
var rateInterval = null;
|
||||
var tradeInterval = null;
|
||||
var reapTxInterval = null;
|
||||
|
||||
var tradesQueue = [];
|
||||
var sessions = {};
|
||||
var dispenseStatuses = {};
|
||||
|
||||
|
||||
|
|
@ -188,106 +187,58 @@ exports.logEvent = function event(rawEvent, deviceFingerprint) {
|
|||
db.recordDeviceEvent(deviceFingerprint, rawEvent);
|
||||
};
|
||||
|
||||
|
||||
// Just prompts plugin to send BTC
|
||||
function _sendBitcoins(tx, cb) {
|
||||
logger.debug('executing tx: %j', tx);
|
||||
db.changeTxStatus(tx.txId, 'executing');
|
||||
walletPlugin.sendBitcoins(
|
||||
tx.toAddress,
|
||||
tx.satoshis,
|
||||
cachedConfig.exchanges.settings.transactionFee,
|
||||
|
||||
function(err, txHash) {
|
||||
if (err) {
|
||||
var status = err.name === 'InsufficientFunds' ?
|
||||
'insufficientFunds' :
|
||||
'failed';
|
||||
|
||||
// report insufficient funds error
|
||||
db.changeTxStatus(tx.txId, status, {error: err.message});
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
if (txHash) db.changeTxStatus(tx.txId, 'completed', {hash: txHash});
|
||||
else db.changeTxStatus(tx.txId, 'failed', {error: 'No txHash received'});
|
||||
|
||||
pollBalance();
|
||||
cb(null, txHash);
|
||||
}
|
||||
);
|
||||
function _sendBitcoins(toAddress, satoshis, cb) {
|
||||
var transactionFee = cachedConfig.exchanges.settings.transactionFee;
|
||||
walletPlugin.sendBitcoins(toAddress, satoshis, transactionFee, cb);
|
||||
}
|
||||
|
||||
function executeTx(deviceFingerprint, txId, triggeredByUser, cb) {
|
||||
cb = typeof cb === 'function' ? cb : function() {};
|
||||
function executeTx(deviceFingerprint, tx, cb) {
|
||||
db.addTx(deviceFingerprint, tx, function(err, result) {
|
||||
if (err) return cb(err);
|
||||
if (!result) return cb(null, {statusCode: 204});
|
||||
var satoshisToSend = result.satoshisToSend;
|
||||
var dbTxId = result.id;
|
||||
|
||||
clearSession(deviceFingerprint);
|
||||
return _sendBitcoins(tx.toAddress, satoshisToSend, function(err, txHash) {
|
||||
var fee = null; // Need to fill this out in plugins
|
||||
db.addDigitalTx(dbTxId, err, txHash, fee);
|
||||
|
||||
// 1. get remaining amount to be sent
|
||||
db.getPendingAmount(txId, function(err, tx) {
|
||||
if (err) {
|
||||
logger.error(err);
|
||||
return cb(err);
|
||||
}
|
||||
if (err) return cb(err);
|
||||
|
||||
if (!tx) {
|
||||
logger.info('Nothing to send (%s)', txId);
|
||||
|
||||
// all bills were already sent by a timeout trigger;
|
||||
// now only mark that user's `/send` arrived
|
||||
if (triggeredByUser)
|
||||
db.changeTxStatus(txId, 'completed', {is_completed: true});
|
||||
|
||||
// indicate ACK to machine
|
||||
return cb(null, {
|
||||
statusCode: 204, // No Content
|
||||
txId: txId
|
||||
});
|
||||
}
|
||||
|
||||
// indicate whether this call was initiated by user or timeout
|
||||
if (triggeredByUser)
|
||||
tx.is_completed = true;
|
||||
|
||||
// 2. BEFORE sending insert tx to a db
|
||||
db.insertTx(deviceFingerprint, tx, function(err) {
|
||||
if (err) {
|
||||
// `getPendingAmount` generated new `partial_id`, so this can occur
|
||||
// only when 2nd executeTx gets called before 1st executes it's insert
|
||||
if (err.name === 'UniqueViolation') {
|
||||
// this will calculate again and then send only "pending" coins
|
||||
return executeTx(deviceFingerprint, txId, triggeredByUser, cb);
|
||||
}
|
||||
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
// 3. actual sending (of the same amount, that was just inserted to the db)
|
||||
return _sendBitcoins(tx, function(err, txHash) {
|
||||
pollBalance();
|
||||
// TODO: should we indicate error to the machine here?
|
||||
|
||||
// indicate ACK to machine
|
||||
cb(null, {
|
||||
statusCode: 201, // Created
|
||||
txId: txHash
|
||||
});
|
||||
pollBalance();
|
||||
cb(null, {
|
||||
statusCode: 201, // Created
|
||||
txHash: txHash
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// This is where we record starting trade balance at the beginning
|
||||
// of the user session
|
||||
function reapTx(row) {
|
||||
var deviceFingerprint = row.device_fingerprint;
|
||||
var tx = {
|
||||
txId: row.txid,
|
||||
toAddress: row.to_address,
|
||||
currencyCode: row.currency_code
|
||||
};
|
||||
executeTx(deviceFingerprint, tx, function(err) {
|
||||
if (err) logger.error(err);
|
||||
});
|
||||
}
|
||||
|
||||
function reapTxs() {
|
||||
db.pendingTxs(function(err, results) {
|
||||
var rows = results.rows;
|
||||
var rowCount = rows.length;
|
||||
for (var i = 0; i < rowCount; i++) {
|
||||
var row = rows[i];
|
||||
reapTx(row);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
exports.trade = function trade(rawTrade, deviceFingerprint, cb) {
|
||||
if (!sessions[deviceFingerprint]) {
|
||||
sessions[deviceFingerprint] = {
|
||||
timestamp: Date.now(),
|
||||
reaper: setTimeout(function() {
|
||||
executeTx(deviceFingerprint, rawTrade.txId, false);
|
||||
}, SESSION_TIMEOUT)
|
||||
};
|
||||
}
|
||||
db.addPendingTx(deviceFingerprint, rawTrade);
|
||||
|
||||
// add bill to trader queue (if trader is enabled)
|
||||
if (traderPlugin) {
|
||||
|
|
@ -302,7 +253,7 @@ exports.trade = function trade(rawTrade, deviceFingerprint, cb) {
|
|||
};
|
||||
|
||||
exports.sendBitcoins = function sendBitcoins(deviceFingerprint, rawTx, cb) {
|
||||
executeTx(deviceFingerprint, rawTx.txId, true, cb);
|
||||
executeTx(deviceFingerprint, rawTx, cb);
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -482,13 +433,14 @@ exports.fiatBalance = function fiatBalance() {
|
|||
exports.startPolling = function startPolling() {
|
||||
executeTrades();
|
||||
|
||||
if (!balanceInterval) {
|
||||
if (!balanceInterval)
|
||||
balanceInterval = setInterval(pollBalance, POLLING_RATE);
|
||||
}
|
||||
|
||||
if (!rateInterval) {
|
||||
if (!rateInterval)
|
||||
rateInterval = setInterval(pollRate, POLLING_RATE);
|
||||
}
|
||||
|
||||
if (!reapTxInterval)
|
||||
reapTxInterval = setInterval(reapTxs, POLLING_RATE);
|
||||
|
||||
startTrader();
|
||||
};
|
||||
|
|
@ -580,15 +532,6 @@ exports.getBalance = function getBalance() {
|
|||
return lastBalances.transferBalance;
|
||||
};
|
||||
|
||||
function clearSession(deviceFingerprint) {
|
||||
var session = sessions[deviceFingerprint];
|
||||
if (session) {
|
||||
clearTimeout(session.reaper);
|
||||
delete sessions[deviceFingerprint];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Trader functions
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue