Skip to content

Instantly share code, notes, and snippets.

@vcealicu
Created September 13, 2016 16:04
Show Gist options
  • Save vcealicu/ff81da5d2d7e599337ade5a2efb57dba to your computer and use it in GitHub Desktop.
Save vcealicu/ff81da5d2d7e599337ade5a2efb57dba to your computer and use it in GitHub Desktop.
angular.module('ccc-app').factory('socketWrapper',['$rootScope','$interval', function socketWrapperFactory($rootScope,$interval) {
//none of the streamer controllers will actually update the intrace so i use this interval function to do the updates....
//i specifically prohibit it from calling scope apply at the end because i am calling it inside... did this to make
//easier to understand what it does.
$interval(function() {$rootScope.$apply();}, 200,0,false);
return io.connect('https://streamer.cryptocompare.com/', {secure: true});
}]);
angular.module('ccc-app').factory('streamerUtilities',['$rootScope','$filter','socketWrapper','subscriptionManager',
function streamerUtilitiesFactory($rootScope,$filter,socketWrapper,subscriptionManager){
// CCC.CURRENT.DISPLAY.FIELDS is decalred in streaming-utilies global.
// CCC.TRADE.DISPLAY.FIELDS is decalred in streaming-utilies global.
var displaySettings = CCC.CURRENT.DISPLAY.FIELDS;
var tradeDisplaySettings = CCC.TRADE.DISPLAY.FIELDS;
var displayCurrency = CCC.STATIC.CURRENCY;
var utilStatic = CCC.STATIC.UTIL;
var isStreaming = true;
var isConnected = false;
var alreadyStopped =false;
var globalPageSubs = {};
var streamerUtilitiesInstance = {};
var cachedMessages = {};
var aggPreLoaded = false;
var monitorPreLoaded = false;
socketWrapper.on('connect', function (data) {
isConnected =true;
$rootScope.$emit("SocketConnected",true);
});
socketWrapper.on('reconnect', function () {
if(!isConnected){
isConnected=true;
$rootScope.$emit("SocketConnected",true);
}else{
}
});
socketWrapper.on('reconnecting', function () {
if(isConnected){
globalPageSubs = {};
isConnected =false;
}
});
socketWrapper.on('m', function (message) {
var messageType = message.substring(0, message.indexOf("~"));
switch(messageType){
case CCC.STATIC.TYPE.TRADE:
streamerUtilitiesInstance.emitCurrentTrade('TradeMessage',message);
break;
case CCC.STATIC.TYPE.CURRENT:
streamerUtilitiesInstance.emitCurrentMessage('CurrentMessage',message);
break;
case CCC.STATIC.TYPE.CURRENTAGG:
streamerUtilitiesInstance.emitCurrentMessage('CurrentAggMessage',message);
break;
case CCC.STATIC.TYPE.ORDERBOOK:
console.log(message);
break;
case CCC.STATIC.TYPE.ORDERBOOKCLEAR:
console.log(message);
break;
case CCC.STATIC.TYPE.LOADCOMPLATE:
if(!isStreaming && !alreadyStopped){
streamerUtilitiesInstance.stopStreaming();
alreadyStopped = true;
}
break;
}
});
streamerUtilitiesInstance.getStreamingStatus = function(){
return isStreaming;
};
streamerUtilitiesInstance.stopStreaming = function (){
var subsToSend = [];
for (var sub in globalPageSubs) {
if (globalPageSubs.hasOwnProperty(sub)) {
subsToSend.push(sub);
}
}
if(subsToSend.length>0){
socketWrapper.emit('SubRemove',{subs:subsToSend} );
isStreaming = false;
return true;
}
return false;
};
streamerUtilitiesInstance.startStreaming = function (){
var subsToSend = [];
if(isStreaming){return false;}
for (var sub in globalPageSubs) {
if (globalPageSubs.hasOwnProperty(sub)) {
subsToSend.push(sub);
}
}
if(subsToSend.length>0){
socketWrapper.emit('SubAdd',{subs:subsToSend} );
isStreaming = true;
return true;
}
return false;
};
streamerUtilitiesInstance.addGlobalPageSubs = function (subs,callback){
var subsToSend = [];
for(var i=0;i<subs.length;i++){
if(globalPageSubs.hasOwnProperty(subs[i])){
globalPageSubs[subs[i]] = globalPageSubs[subs[i]]+1;
if(cachedMessages.hasOwnProperty(subs[i])){
callback(cachedMessages[subs[i]]);
}
}else{
globalPageSubs[subs[i]] = 1;
subsToSend.push(subs[i]);
if(cachedMessages.hasOwnProperty(subs[i])){
callback(cachedMessages[subs[i]]);
}
}
}
if(subsToSend.length>0){
socketWrapper.emit('SubAdd',{subs:subsToSend} );
}
alreadyStopped = false;
};
streamerUtilitiesInstance.removeGlobalPageSubs = function (subs){
var subsToRemove = [];
for(var i=0;i<subs.length;i++){
if(globalPageSubs.hasOwnProperty(subs[i])){
globalPageSubs[subs[i]] = globalPageSubs[subs[i]]-1;
if(globalPageSubs[subs[i]]==0){
subsToRemove.push(subs[i]);
delete globalPageSubs[subs[i]];
}
}
}
if(subsToRemove.length>0){
socketWrapper.emit('SubRemove',{subs:subsToRemove} );
}
};
streamerUtilitiesInstance.initConnection = function(){
return {
connected : isConnected,
loadingData : true,
aggPreLoaded : aggPreLoaded,
monitorPreLoaded : monitorPreLoaded,
subs : [],
data : [],
orderBookData : {},
keyToPosition : {},
totalvolume24hour : 0
};
};
streamerUtilitiesInstance.initProgressBar = function(){
if(isConnected){
return {
current : 2,
message : 'Loading data...',
max : 3
};
}else{
return {
current : 1,
message : 'Connecting...',
max : 3
};
}
};
streamerUtilitiesInstance.initOrdering = function(){
return {
isAscending : false,
sortingField : ''
};
};
streamerUtilitiesInstance.emitCurrentTrade = function(messageType,messageRaw){
var currentTrade = CCC.TRADE.unpack(messageRaw);
var subKey = CCC.TRADE.getKey(currentTrade);
var currentDisplay = {};
for(var property in currentTrade){
if(tradeDisplaySettings[property].Show){
switch(tradeDisplaySettings[property].Filter){
case 'Date':
currentDisplay[property] = $filter('date')(currentTrade[property]*1000, tradeDisplaySettings[property].Format);
break;
case 'Number':
var symbolType = tradeDisplaySettings[property].Symbol;
currentDisplay[property] = utilStatic.convertValueToDisplay(currentDisplay[symbolType],currentTrade[property],$filter('number'));
break;
case 'Text':
currentDisplay[property] = currentTrade[property];
break;
case 'CurrencySymbol':
currentDisplay[property] = displayCurrency.getSymbol(currentTrade[property]);
break;
case 'Market':
currentDisplay[property] = subscriptionManager.getNameForExchange(currentTrade[property]);
break
case 'TradeFlag':
if(parseInt(currentTrade[property],16)&CCC.TRADE.FLAGS.SELL){
currentDisplay[property] ='Sell';
}else if (parseInt(currentTrade[property],16)&CCC.TRADE.FLAGS.BUY){
currentDisplay[property] ='Buy';
}else{
currentDisplay[property] ='Unknown';
}
break;
}
}
}
currentTrade['ARRIVEDON'] = new Date();
currentTrade['highlight'] = true;
currentTrade['DISPLAY'] = currentDisplay;
var messageToEmit ={};
messageToEmit.Raw = messageRaw;
messageToEmit.SubKey = subKey;
messageToEmit.Obj = currentTrade;
$rootScope.$emit(messageType,messageToEmit);
};
streamerUtilitiesInstance.mergeObjects = function(obj1,obj2){
for(var attrname in obj2){ obj1[attrname] = obj2[attrname]; }
return obj1;
}
streamerUtilitiesInstance.copyObject = function(obj1){
var obj2={};
for(var attrname in obj1){ obj1[attrname] = obj2[attrname]; }
return obj2;
}
streamerUtilitiesInstance.decorateCurrent = function(prevMessage,newMessage){
//fields that hard coded and should not be overwritten anywhere!
prevMessage = prevMessage||{};
prevMessage['SUBKEY'] = prevMessage['SUBKEY']||newMessage.SubKey;
prevMessage['DATA'] = newMessage.Obj;
prevMessage['DISPLAY'] = newMessage.Display;
if(prevMessage['VISUAL']){
prevMessage['VISUAL'] = streamerUtilitiesInstance.mergeObjects(prevMessage['VISUAL'],newMessage.Visual);
}else{
prevMessage['VISUAL'] = newMessage.Visual;
}
return prevMessage;
};
streamerUtilitiesInstance.decorateCurrentPorfolioMember = function(prevMessage,newMessage,type,portfolioCurrency){
//fields that hard coded and should not be overwritten anywhere!
var dateNow = new Date();
var animationExpires = dateNow.setMilliseconds(dateNow.getMilliseconds() + 900);
prevMessage.PriceInfo[type].RAW = newMessage.Obj;
prevMessage.PriceInfo[type].DISPLAY = newMessage.Display;
var currentPrice = newMessage.Obj.PRICE;
var currentOpen = newMessage.Obj.OPEN24HOUR;
var lastUpdate = newMessage.Obj.LASTUPDATE;
var displaySymbol = displayCurrency.getSymbol(portfolioCurrency);
var isRealatedToConversion = false;
prevMessage.PriceInfo.PortfolioValues.RAW.LastUpdate = lastUpdate;
switch(type){
case 'Current':
prevMessage.PriceInfo.PortfolioValues.RAW.Price = currentPrice;
prevMessage.PriceInfo.PortfolioValues.RAW.Open24Hour = currentOpen;
break;
case 'Conversion':
if(prevMessage.PriceInfo.BTC.RAW.hasOwnProperty('PRICE')){
currentPrice = currentPrice*prevMessage.PriceInfo.BTC.RAW.PRICE;
prevMessage.PriceInfo.PortfolioValues.RAW.Price = currentPrice;
}
if(prevMessage.PriceInfo.BTC.RAW.hasOwnProperty('OPEN24HOUR')){
currentOpen = currentOpen*prevMessage.PriceInfo.BTC.RAW.OPEN24HOUR;
prevMessage.PriceInfo.PortfolioValues.RAW.Open24Hour = currentOpen;
}
break;
case 'BTC':
if(prevMessage.PriceInfo.Conversion.RAW.hasOwnProperty('PRICE')){
currentPrice = currentPrice*prevMessage.PriceInfo.Conversion.RAW.PRICE;
prevMessage.PriceInfo.PortfolioValues.RAW.Price = currentPrice;
}
if(prevMessage.PriceInfo.Conversion.RAW.hasOwnProperty('OPEN24HOUR')){
currentOpen = currentOpen*prevMessage.PriceInfo.Conversion.RAW.OPEN24HOUR;
prevMessage.PriceInfo.PortfolioValues.RAW.Open24Hour = currentOpen;
}
break;
case 'CurrentBuy':
prevMessage.PriceInfo.PortfolioValues.RAW.BuyConversionPrice = currentPrice;
prevMessage.PriceInfo.PortfolioValues.RAW.BuyConversionOpen24Hour = currentOpen;
isRealatedToConversion=true;
break;
case 'ConversionBuy':
if(prevMessage.PriceInfo.BTCBuy.hasOwnProperty('PRICE')){
currentPrice = currentPrice*prevMessage.PriceInfo.BTCBuy.RAW.PRICE;
prevMessage.PriceInfo.PortfolioValues.RAW.BuyConversionPrice = currentPrice;
isRealatedToConversion=true;
}
if(prevMessage.PriceInfo.BTCBuy.hasOwnProperty('OPEN24HOUR')){
currentOpen = currentOpen*prevMessage.PriceInfo.BTCBuy.RAW.OPEN24HOUR;
prevMessage.PriceInfo.PortfolioValues.RAW.BuyConversionOpen24Hour = currentOpen;
isRealatedToConversion=true;
}
break;
case 'BTCBuy':
if(prevMessage.PriceInfo.ConversionBuy.RAW.hasOwnProperty('PRICE')){
currentPrice = currentPrice*prevMessage.PriceInfo.ConversionBuy.RAW.PRICE;
prevMessage.PriceInfo.PortfolioValues.RAW.BuyConversionPrice = currentPrice;
isRealatedToConversion=true;
}
if(prevMessage.PriceInfo.ConversionBuy.RAW.hasOwnProperty('OPEN24HOUR')){
currentOpen = currentOpen*prevMessage.PriceInfo.ConversionBuy.RAW.OPEN24HOUR;
prevMessage.PriceInfo.PortfolioValues.RAW.BuyConversionOpen24Hour = currentOpen;
isRealatedToConversion=true;
}
break;
}
if(isRealatedToConversion==false){
var newVisual = streamerUtilitiesInstance.copyObject(prevMessage.PriceInfo.Visual);
prevMessage.PriceInfo.Visual = streamerUtilitiesInstance.mergeObjects(newVisual,newMessage.Visual);
}else{
prevMessage.PriceInfo.Visual.CONVERSIONBUY = animationExpires;
}
return prevMessage;
};
streamerUtilitiesInstance.decorateCurrentWithMktCap = function(prevMessage,newMessage,totalCoinsMined){
//fields that hard coded and should not be overwritten anywhere!
prevMessage = prevMessage||{};
prevMessage['SUBKEY'] = prevMessage['SUBKEY']||newMessage.SubKey;
prevMessage['DATA'] = newMessage.Obj;
prevMessage['DISPLAY'] = newMessage.Display;
prevMessage.DATA.MKTCAP = 0;
prevMessage.DISPLAY.MKTCAP = "N/A";
if(totalCoinsMined!=0){
prevMessage.DATA.MKTCAP = prevMessage['DATA'].PRICE*totalCoinsMined;
prevMessage.DISPLAY.MKTCAP = utilStatic.convertValueToDisplay(prevMessage.DISPLAY.TOSYMBOL,prevMessage.DATA.MKTCAP,$filter('number'),'short');
}
if(prevMessage['VISUAL']){
prevMessage['VISUAL'] = streamerUtilitiesInstance.mergeObjects(prevMessage['VISUAL'],newMessage.Visual);
}else{
prevMessage['VISUAL'] = newMessage.Visual;
}
return prevMessage;
};
streamerUtilitiesInstance.decorateMktCap = function(messageInfo,totalCoinsMined){
//fields that hard coded and should not be overwritten anywhere!
var messageToReturn = {};
messageToReturn.DATA={};
messageToReturn.DISPLAY={};
var currentPrice = messageInfo.Obj.PRICE;
var displaySymbol = messageInfo.Display.TOSYMBOL;
messageToReturn.DATA.PRICE = currentPrice;
messageToReturn.DATA.MKTCAP = 0;
messageToReturn.DISPLAY.PRICE = utilStatic.convertValueToDisplay(displaySymbol,currentPrice,$filter('number'));
messageToReturn.DISPLAY.MKTCAP = "Not Available";
if(totalCoinsMined!=0){
messageToReturn.DATA.MKTCAP = currentPrice*totalCoinsMined;
messageToReturn.DISPLAY.MKTCAP = utilStatic.convertValueToDisplay(displaySymbol,messageToReturn.DATA.MKTCAP,$filter('number'),'short');
}
return messageToReturn;
};
streamerUtilitiesInstance.decorateCurrenyMktShare = function(messageInfo,totalVolume){
//fields that hard coded and should not be overwritten anywhere!
var messageToReturn = {};
messageToReturn.DATA={};
messageToReturn.DISPLAY={};
var volumeForm = messageInfo.Obj.VOLUME24HOUR;
var volumeTo = messageInfo.Obj.VOLUME24HOURTO;
var displayToSymbol = messageInfo.Display.TOSYMBOL;
var displayFromSymbol = messageInfo.Display.FROMSYMBOL;
messageToReturn.DATA.VOLUME24HOUR = volumeForm;
messageToReturn.DATA.VOLUME24HOURTO = volumeTo;
messageToReturn.DISPLAY.VOLUME24HOUR = utilStatic.convertValueToDisplay(displayFromSymbol,volumeForm,$filter('number'));
messageToReturn.DISPLAY.VOLUME24HOURTO = utilStatic.convertValueToDisplay(displayToSymbol,volumeTo,$filter('number'));
messageToReturn.DISPLAY.TOSYMBOL = displayToSymbol;
messageToReturn.DISPLAY.FROMSYMBOL = displayFromSymbol;
return messageToReturn;
};
streamerUtilitiesInstance.initMonitorFromServer = function(rawDataArray){
for(var i=0,length=rawDataArray.length;i<length;i++){
streamerUtilitiesInstance.emitCurrentMessage('CurrentMessage',rawDataArray[i]);
}
monitorPreLoaded=true;
};
streamerUtilitiesInstance.initAggFromServer = function(rawDataArray){
for(var i=0,length=rawDataArray.length;i<length;i++){
streamerUtilitiesInstance.emitCurrentMessage('CurrentAggMessage',rawDataArray[i]);
}
aggPreLoaded=true;
};
streamerUtilitiesInstance.emitCurrentMessage = function(messageType,messageRaw){
var lastestMessage= CCC.CURRENT.unpack(messageRaw);
var subKey = CCC.CURRENT.getKey(lastestMessage);
var dateNow = new Date();
var animationExpires = dateNow.setMilliseconds(dateNow.getMilliseconds() + 900);
var currentMessageFull = cachedMessages[subKey] || {};
var currentMessage = currentMessageFull['Obj']||{};
var currentDisplay = currentMessageFull['Display']||{};
var currentVisual = {};
currentDisplay.FROMSYMBOL = displayCurrency.getSymbol(lastestMessage.FROMSYMBOL);
currentDisplay.TOSYMBOL = displayCurrency.getSymbol(lastestMessage.TOSYMBOL);
for(var flag in CCC.CURRENT.FLAGS){
if(parseInt(lastestMessage['FLAGS'],16)&CCC.CURRENT.FLAGS[flag]){
currentVisual[flag] = animationExpires;
}
}
for(var property in lastestMessage){
currentMessage[property] = lastestMessage[property];
if(displaySettings[property].Show){
currentVisual[property] = animationExpires;
switch(displaySettings[property].Filter){
case 'Date':
currentDisplay[property] = $filter('date')(lastestMessage[property]*1000, displaySettings[property].Format);
break;
case 'Number':
var symbolType = displaySettings[property].Symbol;
currentDisplay[property] = utilStatic.convertValueToDisplay(currentDisplay[symbolType],lastestMessage[property],$filter('number'));
break;
case 'String':
currentDisplay[property] = lastestMessage[property];
break;
case 'Market':
currentDisplay[property] = subscriptionManager.getNameForExchange(lastestMessage[property]);
break
}
}
}
var newCHANGE24HOUR = currentMessage.PRICE - currentMessage.OPEN24HOUR;
currentVisual.CHANGE24HOUR = animationExpires;
currentMessage.CHANGE24HOUR = newCHANGE24HOUR;
currentMessage.CHANGEPCT24HOUR = currentMessage.CHANGE24HOUR/currentMessage.OPEN24HOUR*100;
if(Math.abs(currentMessage.CHANGE24HOUR)>10000){
currentDisplay.CHANGE24HOUR = currentDisplay.TOSYMBOL+' '+$filter('number')(currentMessage.CHANGE24HOUR,0);
}else if(Math.abs(currentMessage.CHANGE24HOUR)>1){
currentDisplay.CHANGE24HOUR = currentDisplay.TOSYMBOL+' '+$filter('number')(currentMessage.CHANGE24HOUR,2);
}else{
currentDisplay.CHANGE24HOUR = currentDisplay.TOSYMBOL+' '+currentMessage.CHANGE24HOUR.toPrecision(2);
}
currentDisplay.CHANGEPCT24HOUR = $filter('number')(currentMessage.CHANGEPCT24HOUR,2);
if(currentMessage.CHANGE24HOUR>0){
currentDisplay.CHANGE24HOURUP = animationExpires;
currentDisplay.CHANGE24HOURUNCHANGED = false;
currentDisplay.CHANGE24HOURDOWN = false;
}else if(currentMessage.CHANGE24HOUR<0){
currentDisplay.CHANGE24HOURDOWN = animationExpires;
currentDisplay.CHANGE24HOURUNCHANGED = false;
currentDisplay.CHANGE24HOURUP = false;
}else{
currentDisplay.CHANGE24HOURUNCHANGED = animationExpires;
currentDisplay.CHANGE24HOURDOWN = false;
currentDisplay.CHANGE24HOURUP = false;
}
var messageToEmit ={};
messageToEmit.Raw = messageRaw;
messageToEmit.SubKey = subKey;
messageToEmit.Obj = currentMessage;
messageToEmit.Visual = currentVisual;
messageToEmit.Display = currentDisplay;
cachedMessages[subKey] = messageToEmit;
$rootScope.$emit(messageType,messageToEmit);
};
return streamerUtilitiesInstance;
}]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment