|
|
@ -609,63 +609,6 @@ Storage.prototype.storeActiveAddresses = function(walletId, addresses, cb) { |
|
|
|
}, cb); |
|
|
|
}; |
|
|
|
|
|
|
|
// -------- --------------------------- Total
|
|
|
|
// > Time >
|
|
|
|
// ^to <= ^from
|
|
|
|
// ^fwdIndex => ^end
|
|
|
|
|
|
|
|
Storage.prototype.getTxHistoryCache = function(walletId, from, to, cb) { |
|
|
|
var self = this; |
|
|
|
$.checkArgument(from >= 0); |
|
|
|
$.checkArgument(from <= to); |
|
|
|
|
|
|
|
self.db.collection(collections.CACHE).findOne({ |
|
|
|
walletId: walletId, |
|
|
|
type: 'historyCacheStatus', |
|
|
|
key: null |
|
|
|
}, function(err, result) { |
|
|
|
if (err) return cb(err); |
|
|
|
if (!result) return cb(); |
|
|
|
if (!result.isUpdated) return cb(); |
|
|
|
|
|
|
|
// Reverse indexes
|
|
|
|
var fwdIndex = result.totalItems - to; |
|
|
|
|
|
|
|
if (fwdIndex < 0) { |
|
|
|
fwdIndex = 0; |
|
|
|
} |
|
|
|
|
|
|
|
var end = result.totalItems - from; |
|
|
|
|
|
|
|
// nothing to return
|
|
|
|
if (end <=0) |
|
|
|
return cb(null, []); |
|
|
|
|
|
|
|
|
|
|
|
// Cache is OK.
|
|
|
|
self.db.collection(collections.CACHE).findOne({ |
|
|
|
walletId: walletId, |
|
|
|
type: 'historyCache', |
|
|
|
key: null |
|
|
|
}, function(err, result) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
if (!result || result.history.length < end) |
|
|
|
return cb(); |
|
|
|
|
|
|
|
var ret = result.history.slice(fwdIndex, end); |
|
|
|
|
|
|
|
if (_.any(ret, function(i) { |
|
|
|
return !i; |
|
|
|
})) { |
|
|
|
// some items are not yet defined.
|
|
|
|
return cb(); |
|
|
|
} |
|
|
|
return cb(null, ret.reverse()); |
|
|
|
}); |
|
|
|
}) |
|
|
|
}; |
|
|
|
|
|
|
|
Storage.prototype.softResetAllTxHistoryCache = function(cb) { |
|
|
|
this.db.collection(collections.CACHE).update({ |
|
|
|
type: 'historyCacheStatus', |
|
|
@ -696,10 +639,9 @@ Storage.prototype.clearTxHistoryCache = function(walletId, cb) { |
|
|
|
var self = this; |
|
|
|
self.db.collection(collections.CACHE).remove({ |
|
|
|
walletId: walletId, |
|
|
|
type: 'historyCache', |
|
|
|
key: null |
|
|
|
type: 'historyCache' |
|
|
|
}, { |
|
|
|
w: 1 |
|
|
|
multi: 1 |
|
|
|
}, function(err) { |
|
|
|
self.db.collection(collections.CACHE).remove({ |
|
|
|
walletId: walletId, |
|
|
@ -711,75 +653,191 @@ Storage.prototype.clearTxHistoryCache = function(walletId, cb) { |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
// items should be in CHRONOLOGICAL order
|
|
|
|
// firstPosition, is the
|
|
|
|
Storage.prototype.storeTxHistoryCache = function(walletId, totalItems, firstPosition, items, cb) { |
|
|
|
$.shouldBeNumber(firstPosition); |
|
|
|
$.checkArgument(firstPosition >= 0); |
|
|
|
$.shouldBeNumber(totalItems); |
|
|
|
$.checkArgument(totalItems >= 0); |
|
|
|
var bucketKey = function(bucket, size) { |
|
|
|
return bucket + ':' + size; |
|
|
|
}; |
|
|
|
|
|
|
|
var BUCKET_SIZE = 100; |
|
|
|
|
|
|
|
Storage.prototype._doGetTxHistoryCacheBucket = function(walletId, fwdIndex, cb) { |
|
|
|
var self = this; |
|
|
|
|
|
|
|
var bucket = Math.floor(fwdIndex / BUCKET_SIZE); |
|
|
|
var bucketStart = bucket * BUCKET_SIZE; |
|
|
|
|
|
|
|
self.db.collection(collections.CACHE).findOne({ |
|
|
|
walletId: walletId, |
|
|
|
type: 'historyCache', |
|
|
|
key: bucketKey(bucket, BUCKET_SIZE), |
|
|
|
}, function(err, res1) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
var h1 = res1 ? res1.history || [] : []; |
|
|
|
|
|
|
|
if (h1.length < BUCKET_SIZE) |
|
|
|
h1[BUCKET_SIZE-1] = null; |
|
|
|
|
|
|
|
self.db.collection(collections.CACHE).findOne({ |
|
|
|
walletId: walletId, |
|
|
|
type: 'historyCache', |
|
|
|
key: bucketKey(bucket + 1, BUCKET_SIZE), |
|
|
|
}, function(err, res2) { |
|
|
|
if (err) return cb(err); |
|
|
|
var h2 = res2 ? res2.history || [] : []; |
|
|
|
|
|
|
|
if (h2.length < BUCKET_SIZE) |
|
|
|
h2[BUCKET_SIZE-1] = null; |
|
|
|
var h = (new Array(bucketStart)).concat(h1).concat(h2); |
|
|
|
return cb(null, h, bucket); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Storage.prototype.getTxHistoryCache = function(walletId, from, to, cb) { |
|
|
|
var self = this; |
|
|
|
$.checkArgument(from >= 0); |
|
|
|
$.checkArgument(from <= to); |
|
|
|
|
|
|
|
self.db.collection(collections.CACHE).findOne({ |
|
|
|
walletId: walletId, |
|
|
|
type: 'historyCacheStatus', |
|
|
|
key: null |
|
|
|
}, function(err, result) { |
|
|
|
if (err) return cb(err); |
|
|
|
if (!result) return cb(); |
|
|
|
if (!result.isUpdated) return cb(); |
|
|
|
|
|
|
|
// Reverse indexes
|
|
|
|
var fwdIndex = result.totalItems - to; |
|
|
|
|
|
|
|
result = result || {}; |
|
|
|
var h = result.history || []; |
|
|
|
if (fwdIndex < 0) { |
|
|
|
fwdIndex = 0; |
|
|
|
} |
|
|
|
var end = result.totalItems - from; |
|
|
|
|
|
|
|
//create a sparce array, from the input
|
|
|
|
_.each(items, function(i) { |
|
|
|
h[firstPosition++] = i; |
|
|
|
// nothing to return
|
|
|
|
if (end <= 0) |
|
|
|
return cb(null, []); |
|
|
|
|
|
|
|
self._doGetTxHistoryCacheBucket(walletId, fwdIndex, function(err, h) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
if (!h) //|| result.history.length < end)
|
|
|
|
return cb(); |
|
|
|
|
|
|
|
var res = h.slice(fwdIndex, end); |
|
|
|
|
|
|
|
if (_.any(res, function(i) { |
|
|
|
return !i; |
|
|
|
})) { |
|
|
|
// some items are not yet defined.
|
|
|
|
return cb(); |
|
|
|
} |
|
|
|
return cb(null, res.reverse()); |
|
|
|
}); |
|
|
|
}) |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
Storage.prototype._doSaveTxHistoryCache = function(walletId, fwdIndex, items, cb) { |
|
|
|
$.checkArgument(items.length < BUCKET_SIZE); |
|
|
|
|
|
|
|
var self = this; |
|
|
|
var bucket = Math.floor(fwdIndex / BUCKET_SIZE); |
|
|
|
var bucketStart = bucket * BUCKET_SIZE; |
|
|
|
|
|
|
|
self._doGetTxHistoryCacheBucket(walletId, fwdIndex, function(err, h, bucket) { |
|
|
|
|
|
|
|
// Add new items
|
|
|
|
_.each(items, function(i) { |
|
|
|
h[fwdIndex++] = i; |
|
|
|
}); |
|
|
|
|
|
|
|
// TODO: check txid uniqness?
|
|
|
|
var toSave = h.slice(bucketStart, bucketStart + BUCKET_SIZE); |
|
|
|
self.db.collection(collections.CACHE).update({ |
|
|
|
walletId: walletId, |
|
|
|
type: 'historyCache', |
|
|
|
key: null |
|
|
|
key: bucketKey(bucket, BUCKET_SIZE), |
|
|
|
}, { |
|
|
|
walletId: walletId, |
|
|
|
type: 'historyCache', |
|
|
|
key: null, |
|
|
|
history: h |
|
|
|
key: bucketKey(bucket, BUCKET_SIZE), |
|
|
|
history: toSave, |
|
|
|
}, { |
|
|
|
w: 1, |
|
|
|
upsert: true, |
|
|
|
}, function(err) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
var cacheIsComplete = !!h[0]; |
|
|
|
var now = Date.now(); |
|
|
|
bucket++; |
|
|
|
bucketStart += BUCKET_SIZE; |
|
|
|
|
|
|
|
toSave = h.slice(bucketStart, bucketStart + BUCKET_SIZE); |
|
|
|
self.db.collection(collections.CACHE).update({ |
|
|
|
walletId: walletId, |
|
|
|
type: 'historyCacheStatus', |
|
|
|
key: null |
|
|
|
type: 'historyCache', |
|
|
|
key: bucketKey(bucket, BUCKET_SIZE), |
|
|
|
}, { |
|
|
|
walletId: walletId, |
|
|
|
type: 'historyCacheStatus', |
|
|
|
key: null, |
|
|
|
totalItems: totalItems, |
|
|
|
updatedOn: now, |
|
|
|
isComplete: cacheIsComplete, |
|
|
|
isUpdated: true, |
|
|
|
type: 'historyCache', |
|
|
|
key: bucketKey(bucket, BUCKET_SIZE), |
|
|
|
history: toSave, |
|
|
|
}, { |
|
|
|
w: 1, |
|
|
|
upsert: true, |
|
|
|
}, cb); |
|
|
|
|
|
|
|
}); |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// items should be in reverse CHRONOLOGICAL order
|
|
|
|
// firstPosition, is the
|
|
|
|
Storage.prototype.storeTxHistoryCache = function(walletId, totalItems, to, items, cb) { |
|
|
|
$.shouldBeNumber(to); |
|
|
|
$.checkArgument(to >= 0); |
|
|
|
$.shouldBeNumber(totalItems); |
|
|
|
$.checkArgument(totalItems >= 0); |
|
|
|
|
|
|
|
|
|
|
|
var fwdIndex = totalItems - to; |
|
|
|
if (fwdIndex < 0) fwdIndex = 0; |
|
|
|
|
|
|
|
var self = this; |
|
|
|
|
|
|
|
self._doSaveTxHistoryCache(walletId, fwdIndex, items.reverse(), function(err) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
var now = Date.now(); |
|
|
|
self.db.collection(collections.CACHE).update({ |
|
|
|
walletId: walletId, |
|
|
|
type: 'historyCacheStatus', |
|
|
|
key: null |
|
|
|
}, { |
|
|
|
walletId: walletId, |
|
|
|
type: 'historyCacheStatus', |
|
|
|
key: null, |
|
|
|
totalItems: totalItems, |
|
|
|
updatedOn: now, |
|
|
|
isUpdated: true, |
|
|
|
}, { |
|
|
|
w: 1, |
|
|
|
upsert: true, |
|
|
|
}, cb); |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Storage.prototype.fetchActiveAddresses = function(walletId, cb) { |
|
|
|
var self = this; |
|
|
|
|
|
|
|