UNPKG

crypto-nodes

Version:

394 lines (269 loc) 8.87 kB
var md5 = require('md5'); var data_cache = {}; var moment = require('moment'); var last_write = { minutes: -1, hours: -1, days: -1, } module.exports = function(RED) { function uuidv4() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); } function upsertData(model, data, callback) { model.update({ _id: data._id }, { $set: data }, { upsert: true }, function(err,msg) { if (err) { console.log(err); } if (msg) { if(callback) { callback(); } } }); } function getLineFormat(type, frequency, data, now) { // TODO:: // Implement input of data type to pass via config var line; switch(type) { default: case 'crypto': line = { _id: getDataCode(type, frequency, data, now), symbol: data.FROMSYMBOL + '/' + data.TOSYMBOL, // TODO: Eliminate //symbol_from: data.FROMSYMBOL, //symbol_to: data.TOSYMBOL, last_price: data.PRICE, exchange: data.EXCHANGE, provider: data.PROVIDER, dir: data.DIR, }; break; } return line; } function getDataModel(config, frequency) { var dataModel; if(config.model_name && app.models[config.model_name]) { return app.models[config.model_name]; } switch(frequency) { default: case 'latest': dataModel = app.models.CryptoDataLatest; break; case 'minute': dataModel = app.models.CryptoDataMinute; break; case 'hour': dataModel = app.models.CryptoDataHour; break; case 'day': dataModel = app.models.CryptoDataDay; break; } return dataModel; } function getDataCode(type, frequency, data, now) { var dataCode = false; switch(type) { default: case 'crypto': switch(frequency) { default: case 'latest': dataCode = data.EXCHANGE + '/' + data.FROMSYMBOL + '/' + data.TOSYMBOL; break; case 'minute': case 'hour': case 'day': if(!now) { now = moment(); } dataCode = now.unix() + '/' + data.EXCHANGE + '/' + data.FROMSYMBOL + '/' + data.TOSYMBOL; } break; } if(!dataCode) { dataCode = uuidv4(); } return md5(dataCode); } function cache_update(model, code, data) { } function cache_dump(config, now, frequency) { //var model = var data = data_cache[frequency]; var write_count = 0; console.log(config); console.log(JSON.stringify(data_cache)); for(var type in data) { var tmp = type.split('/'); var module_name = tmp[0]; var model_name = tmp[1]; var model = getDataModel({ model_name: model_name }, frequency); for(var provider in data[type]) { for(var exchange in data[type][provider]) { for(var symbol in data[type][provider][exchange]) { var line = data[type][provider][exchange][symbol]; line.provider = provider; line.exchange = exchange; line.symbol = symbol; line._id = md5(now.unix() + provider + exchange + symbol); write_count++; upsertData(model, line, function () { //delete data_cache[frequency][type][provider][exchange][symbol]; }); } } } delete data_cache[frequency]; // Handle data retention if(config.model_name == model_name && config.module_name == module_name && config.retainer != 'forever') { var delete_before = 0; switch(config.retainer) { case 'hour': delete_before = moment().subtract(1, "hours"); break; case 'day': delete_before = moment().subtract(1, "days"); break; case 'week': delete_before = moment().subtract(7, "days"); break; case 'month': delete_before = moment().subtract(1, "months"); break; } model.deleteMany({ ts: { $lte: delete_before.unix() } }, function (err) { console.log('DataWriter :: Delete of data before ' + delete_before.format("DD-MM-YYYY hh:mm:ss") + ' completed.'); }); } //console.log(module_name); //console.log(model_name); //console.log(model); //var id = getDataCode(data[symbol].type, frequency, data[symbol], now); } console.log('DataWriter :: Wrote ' + write_count + ' records'); config.node.status({fill: 'green', shape:"dot", text: moment().format("hh:mm:ss") + ' : Wrote ' + write_count + ' records' }); } function system_tick(config) { // console.log('Data dump tick'); var now = moment(); if(last_write.minutes != now.minutes() && config.frequency == 'minute') { if(last_write.minutes == -1) { } else { cache_dump(config, now, 'minute'); } last_write.minutes = now.minutes(); } if(last_write.hours != now.hours() && config.frequency == 'hour') { if(last_write.hours == -1) { } else { cache_dump(config, now, 'hour'); } last_write.hours = now.hours(); } if(last_write.days != now.days() && config.frequency == 'day') { if(last_write.days == -1) { } else { cache_dump(config, now, 'day'); } last_write.days = now.days(); } } function providerDataWriter(config) { RED.nodes.createNode(this,config); config.node = this; setInterval(function () { system_tick(config); }, 1000); // TODO:: Export controls config.debug = true; config.type = 'crypto'; config.setModel = false; var node = this; node.status({fill:"red",shape:"dot", text:"waiting for data"}); node.on('input', function(msg) { var color = 'gray'; if(msg.DIR == 'up') { color = 'green'; } if(msg.DIR == 'down') { color = 'red'; } var dataModel = config.setModel || getDataModel(config, config.frequency); var dataLine = getLineFormat(config.module_name, config.frequency, msg); dataLine.type = config.module_name + '/' + config.model_name; if(config.frequency == 'latest') { // Not needed in data if specific model per type is set delete dataLine.type; upsertData(dataModel, dataLine, function () { /* if(dataLine.exchange == 'CCCAGG' && dataLine.symbol == 'BTC/USD') { console.log('Latest update for CCCAGG ::'); console.log({ ts: new moment().unix(), min: dataLine.last_price, max: dataLine.last_price, val: dataLine.last_price, }); } */ if(config.debug) { var text = (" " + dataLine.exchange).slice(-10) + ' ' + dataLine.symbol + ' ' + dataLine.last_price; node.status({fill: color,shape:"dot", text: text }); } }); } else { if(!data_cache[config.frequency]) { data_cache[config.frequency] = {}; } if(!data_cache[config.frequency][dataLine.type]) { data_cache[config.frequency][dataLine.type] = {}; } if(!data_cache[config.frequency][dataLine.type][dataLine.provider]) { data_cache[config.frequency][dataLine.type][dataLine.provider] = {}; } if(!data_cache[config.frequency][dataLine.type][dataLine.provider][dataLine.exchange]) { data_cache[config.frequency][dataLine.type][dataLine.provider][dataLine.exchange] = {}; } if(!data_cache[config.frequency][dataLine.type][dataLine.provider][dataLine.exchange][dataLine.symbol]) { // Create cache data for symbol data_cache[config.frequency][dataLine.type][dataLine.provider][dataLine.exchange][dataLine.symbol] = { ts: new moment().unix(), min: dataLine.last_price, max: dataLine.last_price, val: dataLine.last_price, } /* if(dataLine.exchange == 'CCCAGG' && dataLine.symbol == 'BTC/USD') { console.log('Cache update for CCCAGG ::'); console.log({ ts: new moment().unix(), min: dataLine.last_price, max: dataLine.last_price, val: dataLine.last_price, }); } */ } else { // Update cache data with min/max values + latest var newLine = data_cache[config.frequency][dataLine.type][dataLine.provider][dataLine.exchange][dataLine.symbol]; newLine.min = Math.min(dataLine.last_price, newLine.min); newLine.max = Math.max(dataLine.last_price, newLine.max); newLine.val = dataLine.last_price; } } }); } RED.nodes.registerType("providerDataWriter",providerDataWriter); RED.httpAdmin.get("/writerConfig", function(req,res) { res.json({ models: Object.keys(global.app.models), modules: Object.keys(global.app.modules) }); }); }