class McastParams(object): """ Esta classe armazena e retorna alguns parametros e funcoes comuns ao cliente e servidor multicast. O objetivo principal eh evitar redundancia de codigo """ def __init__(self,port,addr,sbound="",sport=None): self.__port = int(port) self.__addr = addr self.__serverbound = sbound self.__serverport = sport or int(port)-1 self.__log = Log() self.__quit = False def quit(self): """ Mata threads, se existirem """ if self.getThread(): os.kill(self.getThreadPID(),signal.SIGKILL) self.closeSocket() def shouldQuit(self): return self.__quit def closeSocket(self): self.getSocket().close() def getSocket(self): return self.__socket def getPort(self): return self.__port def getAddr(self): return self.__addr def writeLog(self, v, msg): self.__log.log(v,"Mcast:%s"%msg) def getServerBound(self): return self.__serverbound def getServerPort(self): return self.__serverport def setThreadPID(self,pid): self.__threadPID = pid def getThreadPID(self): return self.__threadPID def read(self): while True: try: return self.getSocket().recvfrom(1024) except socket.error, errormsg: self.writeLog(LOGERROR,"read")
def waitrequest(*args): """ Executa funcao "handle" para cada mensagem recebida. Funcao executada em uma thread separada """ obj, handle = args[0], args[1] obj.setThreadPID(os.getpid()) log = Log() while not obj.shouldQuit(): try: handle(obj.read()) except socket.error,errormsg: log.log(LOGERROR,"watrequest:%s"%errormsg) pass time.sleep(0.01)
class GetLatestPriceController(object): """Gets the latest known price for a given symbol""" def __init__(self): self.log = Log(file_handler, self.__class__.__name__) def call(self, symbol): if symbol not in allowed_symbols or not buffer_dict: self.log.debug("Requested symbol %s is not allowed or has no data." % symbol) return json.dumps({"result": None}) last_trade_time = max(buffer_dict) data = buffer_dict.get(last_trade_time) result = {"symbol": data.get("symbol"), "price": data.get("price"), "time": last_trade_time.strftime("%Y-%m-%d %H:%M:%S")} return json.dumps({"result": result})
def __init__(self,port,addr,sbound="",sport=None): self.__port = int(port) self.__addr = addr self.__serverbound = sbound self.__serverport = sport or int(port)-1 self.__log = Log() self.__quit = False
class GetChartDataController(object): """Gets chart data for a given symbol""" def __init__(self): self.log = Log(file_handler, self.__class__.__name__) def call(self, symbol): if symbol not in allowed_symbols or not buffer_dict: self.log.debug("Requested symbol %s is not allowed or has no data." % symbol) return json.dumps({"result": None}) labels = [k.strftime("%H:%M:%S") for k in buffer_dict.keys()] data = [p.get("price") for p in buffer_dict.values()] result = {"symbol": symbol, "labels": labels, "data": data, "min": float(min(data)) - 10, "max": float(max(data)) + 10} return json.dumps({"result": result})
class IndexViewController(object): """Basic index view""" def __init__(self): self.log = Log(file_handler, self.__class__.__name__) def call(self): self.get_socket() return render_template("index.html", channel_href=config.channel_href) def get_socket(self): client = Client(config.api_key, config.api_secret) bm = BinanceSocketManager(client) bm.start_trade_socket("BTCUSDT", self.process_message) return bm.start() def process_message(self, msg): utime = str(msg.get("T"))[:10] ms = str(msg.get("T"))[-3:] dt = datetime.fromtimestamp(int(utime)).replace(microsecond=int(ms) * 1000) symbol = msg.get("s") price = "%.2f" % float(msg.get("p")) buffer_dict.update({dt: {"symbol": symbol, "price": price}}) delete_keys = [] for k in buffer_dict.keys(): if (dt - k).seconds > config.timeframe or (datetime.now() - k).seconds > config.timeframe: delete_keys.append(k) if delete_keys: for k in delete_keys: del buffer_dict[k] self.log.info("Deleted keys: %s" % delete_keys) prices = [p.get("price") for p in buffer_dict.values()] if prices: max_price = max(prices) min_price = min(prices[prices.index(max_price):]) drop_percent = (float(max_price) - float(min_price)) / float(max_price) if (drop_percent > config.percent_threshhold and drop_percent not in registered_drops.get("drops", []) and datetime.now() - dt).seconds < 5): self.send_notification(symbol, max_price, min_price, "{:.2%}".format(drop_percent)) PriceLog.create(symbol=symbol, max_price=max_price, min_price=min_price, drop_percent=round(drop_percent * 100, 2)) registered_drops.get("drops", []).append(drop_percent)
class ClearRegisteredDropsController(object): """Clears registered drops list""" def __init__(self): self.log = Log(file_handler, self.__class__.__name__) def call(self): now = datetime.now() delete_keys = [] for k in buffer_dict.keys(): if (now - k).seconds > config.timeframe: delete_keys.append(k) if delete_keys: for k in delete_keys: del buffer_dict[k] self.log.info("Deleted keys: %s" % delete_keys) if (now - registered_drops.get("last_clear_time")).seconds > config.timeframe + 2: self.log.info("Clearing registered drops %s" % registered_drops) registered_drops.get("drops", []).clear() registered_drops["last_clear_time"] = now return "Drops cleared." return "Drops clearing skipped."
def __init__(self, serverID, mcastPort, mcastAddr, serverFile): Thread.__init__(self) McastServiceServer.__init__(self,mcastPort,mcastAddr) self.__serverDict = self.readServerFile(serverFile) self.__server = int(serverID) self.__requestList = [] self.__timeoutList = [] self.__log = Log("server%d.log"%self.__server) self.writeLog(LOGCONTROL,"Iniciando...") self.getServer().setAlive() # Sinaliza quando a thread tera que ser fechada self.__quit = False
def __init__(self): self.log = Log(file_handler, self.__class__.__name__)
# -*- coding:utf-8 -*- import os import logging import config from flask import Flask from misc import Log app = Flask(__name__) if not os.path.exists("logs"): os.mkdir("logs") file_handler = logging.FileHandler(config.log_config.get("filename")) file_handler.setLevel(config.log_config.get("level")) file_handler.setFormatter(config.log_config.get("format")) log = Log(file_handler, "Binance") log.info("Binance service started.") import views
class OnlineCalcServer(McastServiceServer,Thread): def __init__(self, serverID, mcastPort, mcastAddr, serverFile): Thread.__init__(self) McastServiceServer.__init__(self,mcastPort,mcastAddr) self.__serverDict = self.readServerFile(serverFile) self.__server = int(serverID) self.__requestList = [] self.__timeoutList = [] self.__log = Log("server%d.log"%self.__server) self.writeLog(LOGCONTROL,"Iniciando...") self.getServer().setAlive() # Sinaliza quando a thread tera que ser fechada self.__quit = False def run(self): """ Este metodo recebe as mensagens e endereca para o metodo correto """ # Criando timeout para o heartbeat self.__createTimeout(self.sendHeartBeat,TOUT_HEARTBEAT) # Criando timeout para o atualizar status dos servidores self.__createTimeout(self.updateHeartBeat,TOUT_DEAD) while not self.__quit: (data,(ip,port)) = self.getRequest() Thread(target=self.parserRequest,args=(data,ip,port)).start() def parserRequest(self, data, ip, port): """ Recebe uma requisicao e faz o parser executando os metodos necessarios. """ # Expressoes regulares de possiveis mensagens reID = "(?P<id>[0-9]+)" rePORT = "(?P<port>[0-9]{4,5})" reREQCONF = "(?P<request>.*)" reREQ = "(?P<request>[0-9()\.\+\-\/\*]*)" reALIVE = re.compile("^%s:ALIVE$" % reID) reCONFIRM = re.compile("%s:CONFIRM:%s$" % (reID,reREQCONF)) reREQUEST = re.compile("^%s:%s$"%(rePORT,reREQ)) reQUIT = re.compile("^%s:QUIT$"% reID) if reALIVE.match(data): data = reALIVE.search(data) sid = int(data.group("id")) self.heartBeatReceived(sid) elif reCONFIRM.match(data): data = reCONFIRM.search(data) serverID = data.group("id") request = Request(data.group("request")) self.requestSentby(serverID,request) elif reREQUEST.match(data): data = reREQUEST.search(data) port = data.group("port") data = "%s:%s:%s" %(ip,port,data.group("request")) request = Request(data) self.addRequest(request) self.sendReply(request) elif reQUIT.match(data): data = reQUIT.search(data) serverID = int(data.group("id")) self.serverQuiting(serverID) else: msg = "Request invalido (%s,%d):%s"%(ip,port,data) self.writeLog(LOGWARNING,msg) def __createTimeout(self,method,tout): tout = Timeout(method,tout) tout.start() self.addTimeout(tout) def serverQuiting(self, serverID): """ Quando um servidor vai sair seta ele como morto """ if self.getServer() != self.getServerDict()[serverID]: msg = "Servidor %d desconectou"%( serverID ) self.writeLog(LOGCONTROL,msg) self.missingHeartBeat(serverID) def readServerFile(self,serverFile): """ Le um arquivo contendo os servidores que serao utilizados e retorna um dicionario {id:Server} """ serverList = {} for line in open(serverFile): # Se a linha nao eh um comentario nem vazia if not re.match("^(#|$)",line): sid,shostname,sport = line.split() serverList[int(sid)] = Server(sid,shostname,sport) return serverList def writeLog(self,verbose,msg): """ Escreve uma mensagem no log """ msg = "Server-%d %s"%( self.getServer().getID(),msg ) self.__log.log(verbose,msg) def addTimeout(self,obj): self.__timeoutList.append(obj) def addRequest(self, request): """ Adiciona uma nova requisicao a lista e a trata """ self.writeLog(LOGMESSAGE,"Request:%s"%request) self.__requestList.append(request) def removeRequest(self, request): """ Remove request da lista """ if request in self.__requestList: self.__requestList.remove(request) def requestSentby(self, serverID, request): """ Confirmacao de que o servidor serverID respondeu a requisicao request, que deve ser removida da lista """ if int(serverID) != self.getServer().getID(): msg = "Servidor %s Respondeu %s"%(serverID,request) else: msg = "Respondi %s"%(request) self.writeLog(LOGMESSAGE,msg) self.removeRequest(request) def heartBeatReceived(self,serverID): """ Marca servidor serverID como vivo """ if serverID != self.getServer().getID(): self.writeLog(LOGCONTROL,"HeartBeatReceived:%d"%serverID) self.getServerDict()[int(serverID)].setAlive() def updateHeartBeat(self): """ Verifica se algum servidor nao responde a mais de TOUT_DEAD segundos """ for server in self.getServerDict().values(): if server != self.getServer(): if time.time() - server.getLastContact() > TOUT_DEAD: self.missingHeartBeat(server.getID()) def missingHeartBeat(self,serverID): """ Marca servidor serverID como morto """ self.writeLog(LOGCONTROL,"MissingHeartBeat:%d"%serverID) self.getServerDict()[int(serverID)].setNotAlive() def sendHeartBeat(self): """ Envia mensagem ao multicast informando que esta vivo """ self.getMcast().send("%d:ALIVE"%self.getServer().getID()) def whoAnswers(self): """ Retorna o menor servidor ativo """ for idx in sorted(self.getServerDict().keys()): server = self.getServerDict()[idx] if server.imalive(): return self.getServerDict()[idx] def sendReply(self,request,force=False): """ Computa request e (se sou o servidor com menor ID vivo) envia resposta para o cliente, ao mesmo tempo que comunica os outros servidores do grupo multicast que a requisicao request foi respondida. """ willAnswer = self.whoAnswers() if force or willAnswer == self.getServer(): reply = "Server%d "%(self.getServer().getID()) reply += str((self.getServer().getAddr()))+": " try: reply += str(eval(request.getRequest())) except (SyntaxError,TypeError),error: reply += "ERRO: "+str(error) except ZeroDivisionError: reply = "ERRO: Ocorreu uma divisao por zero." self.writeLog(LOGCONTROL,"Respondendo %s = %s"%(request,reply)) host,port = request.getIP(),request.getPort() McastServiceServer.sendReply(self,host,port,reply) self.sendReplyConfirm(request)