def __init__(self, application, request, **kwargs): super(WebSocketHandler, self).__init__(application, request, **kwargs) self.remote_ip = request.headers.get( 'X-Forwarded-For', request.headers.get( 'X-Real-Ip', request.remote_ip)) application.log('INFO', 'CONNECTION_OPEN', self.remote_ip ) self.trade_client = None self.user_response = None self.last_message_datetime = [datetime.now()] self.open_orders = {} self.md_subscriptions = {} self.sec_status_subscriptions = {} self.honey_pot_connection = False if self.application.is_tor_node( self.remote_ip ): self.honey_pot_connection = True application.log('INFO', 'BLOCKED_TOR_NODE', self.remote_ip ) return self.trade_client = TradeClient( self.application.zmq_context, self.application.trade_in_socket, self.application.options.trade_pub)
def __init__(self, application, request, **kwargs): super(WebSocketHandler, self).__init__(application, request, **kwargs) self.remote_ip = request.headers.get( 'X-Forwarded-For', request.headers.get('X-Real-Ip', request.remote_ip)) application.log('INFO', 'CONNECTION_OPEN', self.remote_ip) self.trade_client = TradeClient(self.application.zmq_context, self.application.trade_in_socket, self.application.options.trade_pub) self.md_subscriptions = {} self.sec_status_subscriptions = {} self.user_response = None self.last_order_datetime = datetime.now() self.open_orders = {}
def __init__(self, application, request, **kwargs): super(WebSocketHandler, self).__init__(application, request, **kwargs) self.remote_ip = request.headers.get( 'X-Forwarded-For', request.headers.get( 'X-Real-Ip', request.remote_ip)) application.log('INFO', 'CONNECTION_OPEN', self.remote_ip ) self.trade_client = TradeClient( self.application.zmq_context, self.application.trade_in_socket, self.application.options.trade_pub) self.md_subscriptions = {} self.sec_status_subscriptions = {} self.user_response = None
class WebSocketHandler(websocket.WebSocketHandler): def __init__(self, application, request, **kwargs): super(WebSocketHandler, self).__init__(application, request, **kwargs) self.remote_ip = request.headers.get( 'X-Forwarded-For', request.headers.get( 'X-Real-Ip', request.remote_ip)) application.log('INFO', 'CONNECTION_OPEN', self.remote_ip ) self.trade_client = TradeClient( self.application.zmq_context, self.application.trade_in_socket, self.application.options.trade_pub) self.md_subscriptions = {} self.sec_status_subscriptions = {} self.user_response = None def on_trade_publish(self, message): self.write_message(str(message[1])) def check_origin(self, origin): self.application.log('INFO', 'ORIGIN', origin) return self.application.is_origin_allowed(origin) def open(self): try: self.trade_client.connect() self.trade_client.on_trade_publish = self.on_trade_publish self.application.register_connection(self) except TradeClientException as e: self.write_message( '{"MsgType":"ERROR", "Description":"Error establishing connection with trade", "Detail": "' + str(e) + '"}') self.trade_client.close() self.close() def write_message(self, message, binary=False): self.application.log('OUT', self.trade_client.connection_id, message ) super(WebSocketHandler, self).write_message(message, binary) def close(self): self.application.log('DEBUG', self.remote_ip, 'WebSocketHandler.close() invoked' ) super(WebSocketHandler, self).close() def on_message(self, raw_message): if not self.trade_client.isConnected(): return try: req_msg = JsonMessage(raw_message) except InvalidMessageException as e: self.write_message( '{"MsgType":"ERROR", "Description":"Invalid message", "Detail": "' + str(e) + '"}') self.application.unregister_connection(self) self.trade_client.close() self.close() return if req_msg.isUserRequest(): if req_msg.has('Password'): raw_message = raw_message.replace(req_msg.get('Password'), '*') if req_msg.has('NewPassword'): raw_message = raw_message.replace(req_msg.get('NewPassword'), '*') self.application.log('IN', self.trade_client.connection_id ,raw_message ) else: self.application.log('IN', self.trade_client.connection_id, raw_message ) if req_msg.isTestRequest() or req_msg.isHeartbeat(): dt = datetime.datetime.now() response_msg = { 'MsgType' : '0', 'TestReqID' : req_msg.get('TestReqID'), 'ServerTimestamp' : int(mktime(dt.timetuple()) + dt.microsecond/1000.0 ) } sendTime = req_msg.get('SendTime') if sendTime: response_msg['SendTime'] = sendTime self.write_message(str(json.dumps(response_msg, cls=JsonEncoder))) return if req_msg.isTradeHistoryRequest(): # Trade History request self.on_trade_history_request(req_msg) return if req_msg.isMarketDataRequest(): # Market Data Request self.on_market_data_request(req_msg) if not self.trade_client.isConnected(): self.application.log('DEBUG', self.trade_client.connection_id, 'not self.trade_client.isConnected()' ) self.application.unregister_connection(self) self.trade_client.close() self.close() return if req_msg.isSecurityStatusRequest(): self.on_security_status_request(req_msg) return if req_msg.isDepositRequest(): if not req_msg.get('DepositMethodID') and not req_msg.get('DepositID'): currency = req_msg.get('Currency') secret = uuid.uuid4().hex callback_url = self.application.options.callback_url + secret hot_wallet = self.get_broker_wallet('hot', currency) cold_wallet = self.get_broker_wallet('cold', currency) if not hot_wallet and not cold_wallet: return if not hot_wallet and cold_wallet: dest_wallet = cold_wallet elif hot_wallet and not cold_wallet: dest_wallet = hot_wallet else: # 62.5% of all deposits go to the cold wallet, and 37.5% go to the hot wallet dest_wallet = hot_wallet if secret[0] in ('0','1','2','3','4','5','6','7','8','9'): dest_wallet = cold_wallet if not dest_wallet: return parameters = urllib.urlencode({ 'method': 'create', 'address': dest_wallet, 'callback': callback_url, 'currency': currency }) try: url_payment_processor = self.application.options.url_payment_processor + '?' + parameters self.application.log('DEBUG', self.trade_client.connection_id, "invoking..." + url_payment_processor ) response = urllib2.urlopen(url_payment_processor) data = json.load(response) self.application.log('DEBUG', self.trade_client.connection_id, str(data) ) req_msg.set('InputAddress', data['input_address']) req_msg.set('Destination', data['destination']) req_msg.set('Secret', secret) except urllib2.HTTPError as e: out_message = json.dumps({ 'MsgType': 'ERROR', 'ReqID': req_msg.get('DepositReqID'), 'Description': 'Blockchain.info is not available at this moment, please try again within few minutes', 'Detail': str(e) }) self.write_message(out_message) return except Exception as e: out_message = json.dumps({ 'MsgType': 'ERROR', 'ReqID': req_msg.get('DepositReqID'), 'Description': 'Error retrieving a new deposit address from Blockchain.info. Please, try again', 'Detail': str(e) }) self.write_message(out_message) return try: resp_message = self.trade_client.sendMessage(req_msg) if resp_message: self.write_message(resp_message.raw_message) if resp_message and resp_message.isUserResponse(): self.user_response = resp_message if not self.trade_client.isConnected(): self.application.log('DEBUG', self.trade_client.connection_id, 'not self.trade_client.isConnected()' ) self.application.unregister_connection(self) self.trade_client.close() self.close() except TradeClientException as e: exception_message = { 'MsgType': 'ERROR', 'Description': 'Invalid message', 'Detail': str(e) } self.write_message(json.dumps(exception_message)) self.application.unregister_connection(self) self.trade_client.close() self.close() def is_user_logged(self): if not self.user_response: return False return self.user_response.get('UserStatus') == 1 def is_broker(self): if not self.is_user_logged(): return False return self.user_response.get('IsBroker') == 1 def get_broker_wallet(self, type, currency): if not self.user_response: return broker = self.user_response.get('Broker') if not broker: return if 'CryptoCurrencies' not in broker: return broker_crypto_currencies = broker['CryptoCurrencies'] for crypto_currency in broker_crypto_currencies: if crypto_currency['CurrencyCode'] == currency: for wallet in crypto_currency['Wallets']: if wallet['type'] == type: return wallet['address'] def on_close(self): self.application.log('DEBUG', self.trade_client.connection_id, 'WebSocketHandler.on_close' ) self.application.unregister_connection(self) self.trade_client.close() def on_trade_history_request(self, msg): since = msg.get('Since') page = msg.get('Page', 0) page_size = msg.get('PageSize', 100) filter = msg.get('Filter') offset = page * page_size if self.is_broker(): columns = [ 'TradeID' , 'Market', 'Side', 'Price', 'Size', 'Buyer' , 'Seller', 'Created', 'BuyerUsername' ,'SellerUsername' ] else: columns = [ 'TradeID' , 'Market', 'Side', 'Price', 'Size', 'Buyer' , 'Seller', 'Created' ] trade_list = generate_trade_history(self.application.db_session, page_size, offset, show_username=self.is_broker(), since=since) response_msg = { 'MsgType' : 'U33', # TradeHistoryResponse 'TradeHistoryReqID' : msg.get('TradeHistoryReqID'), 'Page' : page, 'PageSize' : page_size, 'Columns' : columns, 'TradeHistoryGrp' : trade_list } if since: response_msg['Since'] = since self.write_message(str(json.dumps(response_msg, cls=JsonEncoder))) def on_security_status_request(self, msg): # Generate a FullRefresh req_id = msg.get('SecurityStatusReqID') # Disable previous Snapshot + Update Request if int(msg.get('SubscriptionRequestType')) == 2: if req_id in self.sec_status_subscriptions: del self.sec_status_subscriptions[req_id] return instruments = msg.get('Instruments') if int(msg.get('SubscriptionRequestType')) == 1: # Snapshot + Updates if req_id not in self.sec_status_subscriptions: self.sec_status_subscriptions[req_id] = [] for instrument in instruments: ss = generate_security_status( instrument, req_id) self.write_message(str(json.dumps(ss, cls=JsonEncoder))) # Snapshot + Updates if int(msg.get('SubscriptionRequestType')) == 1: self.sec_status_subscriptions[req_id].append( SecurityStatusPublisher( req_id, instrument, self.on_send_json_msg_to_user)) def on_market_data_request(self, msg): # Generate a FullRefresh req_id = msg.get('MDReqID') # Disable previous Snapshot + Update Request if int(msg.get('SubscriptionRequestType')) == 2: if req_id in self.md_subscriptions: del self.md_subscriptions[req_id] return market_depth = msg.get('MarketDepth') instruments = msg.get('Instruments') entries = msg.get('MDEntryTypes') if int(msg.get('SubscriptionRequestType')) == 1: # Snapshot + Updates if req_id not in self.md_subscriptions: self.md_subscriptions[req_id] = [] for instrument in instruments: md = generate_md_full_refresh( instrument, market_depth, entries, req_id, self.is_broker()) self.write_message(str(json.dumps(md, cls=JsonEncoder))) # Snapshot + Updates if int(msg.get('SubscriptionRequestType')) == 1: self.md_subscriptions[req_id].append( MarketDataPublisher( req_id, market_depth, entries, instrument, self.on_send_json_msg_to_user, self.is_broker())) def on_send_json_msg_to_user(self, sender, json_msg): s = json.dumps(json_msg, cls=JsonEncoder) self.write_message(s)
def __init__(self, opt, instance_name): self.options = opt self.instance_name = instance_name handlers = [ (r'/', WebSocketHandler), (r'/get_deposit(.*)', DepositHandler), (r'/_webhook/verification_form', VerificationWebHookHandler), (r'/_webhook/deposit_receipt', DepositReceiptWebHookHandler), (r'/process_deposit(.*)', ProcessDepositHandler), (r'/api/(?P<version>[^\/]+)/(?P<symbol>[^\/]+)/(?P<resource>[^\/]+)', RestApiHandler) ] settings = dict( cookie_secret='cookie_secret' ) tornado.web.Application.__init__(self, handlers, **settings) self.allowed_origins = json.loads(self.options.allowed_origins) self.allow_all_origins = self.allowed_origins[0] == '*' input_log_file_handler = logging.handlers.TimedRotatingFileHandler( os.path.expanduser(self.options.gateway_log), when='MIDNIGHT') formatter = logging.Formatter('%(asctime)s - %(message)s') input_log_file_handler.setFormatter(formatter) self.replay_logger = logging.getLogger(self.instance_name) self.replay_logger.setLevel(logging.INFO) self.replay_logger.addHandler(input_log_file_handler) ch = logging.StreamHandler(sys.stdout) ch.setLevel(logging.DEBUG) ch.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')) self.replay_logger.addHandler(ch) self.replay_logger.info('START') self.log_start_data() from models import Base, db_bootstrap db_engine = self.options.sqlalchemy_engine + ':///' +\ os.path.expanduser(self.options.sqlalchemy_connection_string) engine = create_engine( db_engine, echo=self.options.db_echo) Base.metadata.create_all(engine) self.db_session = scoped_session(sessionmaker(bind=engine)) db_bootstrap(self.db_session) self.zmq_context = zmq.Context() self.trade_in_socket = self.zmq_context.socket(zmq.REQ) self.trade_in_socket.connect(self.options.trade_in) self.application_trade_client = TradeClient( self.zmq_context, self.trade_in_socket) self.application_trade_client.connect() self.security_list = self.application_trade_client.getSecurityList() self.md_subscriber = {} for instrument in self.security_list.get('Instruments'): symbol = instrument['Symbol'] self.md_subscriber[symbol] = MarketDataSubscriber.get(symbol, self) self.md_subscriber[symbol].subscribe( self.zmq_context, self.options.trade_pub, self.application_trade_client) last_trade_id = Trade.get_last_trade_id(self.db_session) trade_list = self.application_trade_client.getLastTrades(last_trade_id) for trade in trade_list: msg = dict() msg['id'] = trade[0] msg['symbol'] = trade[1] msg['side'] = trade[2] msg['price'] = trade[3] msg['size'] = trade[4] msg['buyer_id'] = trade[5] msg['seller_id'] = trade[6] msg['buyer_username'] = trade[7] msg['seller_username'] = trade[8] msg['created'] = trade[9] msg['trade_date'] = trade[9][:10] msg['trade_time'] = trade[9][11:] msg['order_id'] = trade[10] msg['counter_order_id'] = trade[11] Trade.create( self.db_session, msg) all_trades = Trade.get_all_trades(self.db_session) for t in all_trades: trade_info = dict() trade_info['price'] = t.price trade_info['size'] = t.size trade_info['trade_date'] = t.created.strftime('%Y-%m-%d') trade_info['trade_time'] = t.created.strftime('%H:%M:%S') self.md_subscriber[ t.symbol ].inst_status.push_trade(trade_info) for symbol, subscriber in self.md_subscriber.iteritems(): subscriber.ready() self.connections = {} self.heart_beat_timer = tornado.ioloop.PeriodicCallback( self.send_heartbeat_to_trade, 30000) self.heart_beat_timer.start()
class WebSocketGatewayApplication(tornado.web.Application): def __init__(self, opt, instance_name): self.options = opt self.instance_name = instance_name handlers = [ (r'/', WebSocketHandler), (r'/get_deposit(.*)', DepositHandler), (r'/_webhook/verification_form', VerificationWebHookHandler), (r'/_webhook/deposit_receipt', DepositReceiptWebHookHandler), (r'/process_deposit(.*)', ProcessDepositHandler), (r'/api/(?P<version>[^\/]+)/(?P<symbol>[^\/]+)/(?P<resource>[^\/]+)', RestApiHandler) ] settings = dict( cookie_secret='cookie_secret' ) tornado.web.Application.__init__(self, handlers, **settings) self.allowed_origins = json.loads(self.options.allowed_origins) self.allow_all_origins = self.allowed_origins[0] == '*' input_log_file_handler = logging.handlers.TimedRotatingFileHandler( os.path.expanduser(self.options.gateway_log), when='MIDNIGHT') formatter = logging.Formatter('%(asctime)s - %(message)s') input_log_file_handler.setFormatter(formatter) self.replay_logger = logging.getLogger(self.instance_name) self.replay_logger.setLevel(logging.INFO) self.replay_logger.addHandler(input_log_file_handler) ch = logging.StreamHandler(sys.stdout) ch.setLevel(logging.DEBUG) ch.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')) self.replay_logger.addHandler(ch) self.replay_logger.info('START') self.log_start_data() from models import Base, db_bootstrap db_engine = self.options.sqlalchemy_engine + ':///' +\ os.path.expanduser(self.options.sqlalchemy_connection_string) engine = create_engine( db_engine, echo=self.options.db_echo) Base.metadata.create_all(engine) self.db_session = scoped_session(sessionmaker(bind=engine)) db_bootstrap(self.db_session) self.zmq_context = zmq.Context() self.trade_in_socket = self.zmq_context.socket(zmq.REQ) self.trade_in_socket.connect(self.options.trade_in) self.application_trade_client = TradeClient( self.zmq_context, self.trade_in_socket) self.application_trade_client.connect() self.security_list = self.application_trade_client.getSecurityList() self.md_subscriber = {} for instrument in self.security_list.get('Instruments'): symbol = instrument['Symbol'] self.md_subscriber[symbol] = MarketDataSubscriber.get(symbol, self) self.md_subscriber[symbol].subscribe( self.zmq_context, self.options.trade_pub, self.application_trade_client) last_trade_id = Trade.get_last_trade_id(self.db_session) trade_list = self.application_trade_client.getLastTrades(last_trade_id) for trade in trade_list: msg = dict() msg['id'] = trade[0] msg['symbol'] = trade[1] msg['side'] = trade[2] msg['price'] = trade[3] msg['size'] = trade[4] msg['buyer_id'] = trade[5] msg['seller_id'] = trade[6] msg['buyer_username'] = trade[7] msg['seller_username'] = trade[8] msg['created'] = trade[9] msg['trade_date'] = trade[9][:10] msg['trade_time'] = trade[9][11:] msg['order_id'] = trade[10] msg['counter_order_id'] = trade[11] Trade.create( self.db_session, msg) all_trades = Trade.get_all_trades(self.db_session) for t in all_trades: trade_info = dict() trade_info['price'] = t.price trade_info['size'] = t.size trade_info['trade_date'] = t.created.strftime('%Y-%m-%d') trade_info['trade_time'] = t.created.strftime('%H:%M:%S') self.md_subscriber[ t.symbol ].inst_status.push_trade(trade_info) for symbol, subscriber in self.md_subscriber.iteritems(): subscriber.ready() self.connections = {} self.heart_beat_timer = tornado.ioloop.PeriodicCallback( self.send_heartbeat_to_trade, 30000) self.heart_beat_timer.start() def format_currency(self, currency_code, value, is_value_in_satoshis=True): currencies = self.security_list.get('Currencies') for currency_obj in currencies: if currency_obj['Code'] == currency_code: if is_value_in_satoshis: return currency_obj['FormatPython'].format(value/1e8) else: return currency_obj['FormatPython'].format(value) return value def is_origin_allowed(self, origin): if self.allow_all_origins: return True if origin in self.allowed_origins: return True return False def log_start_data(self): self.log('PARAM','BEGIN') self.log('PARAM','callback_url' ,self.options.callback_url) self.log('PARAM','port' ,self.options.port) self.log('PARAM','trade_in' ,self.options.trade_in) self.log('PARAM','trade_pub' ,self.options.trade_pub) self.log('PARAM','url_payment_processor' ,self.options.url_payment_processor) self.log('PARAM','session_timeout_limit' ,self.options.session_timeout_limit) self.log('PARAM','db_echo' ,self.options.db_echo) self.log('PARAM','sqlalchemy_engine' ,self.options.sqlalchemy_engine) self.log('PARAM','sqlalchemy_connection_string' ,self.options.sqlalchemy_connection_string) self.log('PARAM','allowed_origins' ,self.options.allowed_origins) self.log('PARAM','END') def log(self, command, key, value=None): log_msg = command + ',' + key if value: try: log_msg += ',' + value except Exception,e : try: log_msg += ',' + str(value) except Exception,e : try: log_msg += ',' + unicode(value) except Exception,e : log_msg += ', [object]'
class WebSocketHandler(websocket.WebSocketHandler): def __init__(self, application, request, **kwargs): super(WebSocketHandler, self).__init__(application, request, **kwargs) self.remote_ip = request.headers.get( 'X-Forwarded-For', request.headers.get('X-Real-Ip', request.remote_ip)) application.log('INFO', 'CONNECTION_OPEN', self.remote_ip) self.trade_client = None self.user_response = None self.last_message_datetime = [datetime.now()] self.open_orders = {} self.md_subscriptions = {} self.sec_status_subscriptions = {} self.honey_pot_connection = False if self.application.is_tor_node(self.remote_ip): self.honey_pot_connection = True application.log('INFO', 'BLOCKED_TOR_NODE', self.remote_ip) return self.trade_client = TradeClient(self.application.zmq_context, self.application.trade_in_socket, self.application.options.trade_pub) def process_execution_report(self): pass def on_close(self): self.application.log('INFO', 'CONNECTION_CLOSE', self.remote_ip) for req_id, md_publisher_list in self.md_subscriptions.items(): for md_publisher in md_publisher_list: md_publisher.cleanup() self.md_subscriptions[req_id] = [] self.md_subscriptions = {} for req_id, sec_status_publisher_list in self.sec_status_subscriptions.items( ): for sec_status_publisher in sec_status_publisher_list: sec_status_publisher.cleanup() self.sec_status_subscriptions[req_id] = [] self.sec_status_subscriptions = {} self.application.unregister_connection(self) if self.trade_client: self.trade_client.close() self.trade_client = None def on_trade_publish(self, message): self.write_message(str(message[1])) def check_origin(self, origin): self.application.log('INFO', 'ORIGIN', origin) return self.application.is_origin_allowed(origin) def open(self): self.set_nodelay(True) try: if self.trade_client: self.trade_client.connect() self.trade_client.on_trade_publish = self.on_trade_publish self.application.register_connection(self) except TradeClientException as e: self.write_message( '{"MsgType":"ERROR", "Description":"Error establishing connection with trade", "Detail": "' + str(e) + '"}') if self.trade_client: self.trade_client.close() self.close() def write_message(self, message, binary=False): super(WebSocketHandler, self).write_message(message, binary) def close(self, code=None, reason=None): self.application.log('DEBUG', self.remote_ip, 'WebSocketHandler.close() invoked') super(WebSocketHandler, self).close() def on_message(self, raw_message): if self.honey_pot_connection: self.application.log('INFO', "HONEY_POT", raw_message) if self.trade_client is None or not self.trade_client.isConnected(): return self.last_message_datetime.append(datetime.now()) message_time_last_second = self.last_message_datetime[-1] - timedelta( seconds=1) for x in xrange(0, len(self.last_message_datetime)): if self.last_message_datetime[x] > message_time_last_second: self.last_message_datetime = self.last_message_datetime[x:] break if len(self.last_message_datetime ) > 15: # higher than 15 messages per second self.application.log( "ERROR", "TOO_MANY_MESSAGES", "Exceed 15 messages per second. [ip=" + self.remote_ip + ",'" + raw_message + "']") self.write_message( '{"MsgType":"ERROR", "Description":"Too many messages per second", "Detail": "16 messages in the last second"}' ) self.application.unregister_connection(self) self.trade_client.close() self.close() return try: req_msg = JsonMessage(raw_message) except InvalidMessageException as e: self.write_message( '{"MsgType":"ERROR", "Description":"Invalid message", "Detail": "' + str(e) + '"}') self.application.unregister_connection(self) self.trade_client.close() self.close() return req_msg.set('RemoteIP', self.remote_ip) if req_msg.isUserRequest(): if req_msg.has('Password'): raw_message = raw_message.replace(req_msg.get('Password'), '*') if req_msg.has('NewPassword'): raw_message = raw_message.replace(req_msg.get('NewPassword'), '*') self.application.log('IN', self.trade_client.connection_id, raw_message) if req_msg.isTestRequest() or req_msg.isHeartbeat(): dt = datetime.now() response_msg = { 'MsgType': '0', 'TestReqID': req_msg.get('TestReqID'), 'ServerTimestamp': int(mktime(dt.timetuple()) + dt.microsecond / 1000.0) } sendTime = req_msg.get('SendTime') if sendTime: response_msg['SendTime'] = sendTime self.write_message(str(json.dumps(response_msg, cls=JsonEncoder))) return if req_msg.isTradeHistoryRequest(): # Trade History request self.on_trade_history_request(req_msg) return if req_msg.isMarketDataRequest(): # Market Data Request self.on_market_data_request(req_msg) if not self.trade_client.isConnected(): self.application.log('DEBUG', self.trade_client.connection_id, 'not self.trade_client.isConnected()') self.application.unregister_connection(self) self.trade_client.close() self.close() return if req_msg.isSecurityStatusRequest(): self.on_security_status_request(req_msg) return if req_msg.isDepositRequest(): if not req_msg.get('DepositMethodID') and not req_msg.get( 'DepositID'): currency = req_msg.get('Currency') secret = uuid.uuid4().hex callback_url = self.application.options.callback_url + secret hot_wallet = self.get_broker_wallet('hot', currency) cold_wallet = self.get_broker_wallet('cold', currency) if not hot_wallet and not cold_wallet: return if not hot_wallet and cold_wallet: dest_wallet = cold_wallet elif hot_wallet and not cold_wallet: dest_wallet = hot_wallet else: # 62.5% of all deposits go to the cold wallet, and 37.5% go to the hot wallet dest_wallet = hot_wallet if secret[0] in ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'): dest_wallet = cold_wallet if not dest_wallet: return parameters = urllib.urlencode({ 'method': 'create', 'address': dest_wallet, 'callback': callback_url, 'currency': currency }) try: url_payment_processor = self.application.options.url_payment_processor + '?' + parameters self.application.log('DEBUG', self.trade_client.connection_id, "invoking..." + url_payment_processor) response = urllib2.urlopen(url_payment_processor) data = json.load(response) self.application.log('DEBUG', self.trade_client.connection_id, str(data)) req_msg.set('InputAddress', data['input_address']) req_msg.set('Destination', data['destination']) req_msg.set('Secret', secret) except urllib2.HTTPError as e: out_message = json.dumps({ 'MsgType': 'ERROR', 'ReqID': req_msg.get('DepositReqID'), 'Description': 'Blockchain.info is not available at this moment, please try again within few minutes', 'Detail': str(e) }) self.write_message(out_message) return except Exception as e: out_message = json.dumps({ 'MsgType': 'ERROR', 'ReqID': req_msg.get('DepositReqID'), 'Description': 'Error retrieving a new deposit address from Blockchain.info. Please, try again', 'Detail': str(e) }) self.write_message(out_message) return try: resp_message = self.trade_client.sendMessage(req_msg) if resp_message: self.write_message(resp_message.raw_message) if resp_message and resp_message.isUserResponse(): self.user_response = resp_message if self.is_user_logged(): self.application.log('LOGIN_OK', self.trade_client.connection_id, raw_message) #TODO: Request open order list #self.trade_client. else: self.application.log('LOGIN_FAILED', self.trade_client.connection_id, raw_message) if not self.trade_client.isConnected(): self.application.log('DEBUG', self.trade_client.connection_id, 'not self.trade_client.isConnected()') self.application.unregister_connection(self) self.trade_client.close() self.close() except TradeClientException as e: exception_message = { 'MsgType': 'ERROR', 'Description': 'Invalid message', 'Detail': str(e) } self.write_message(json.dumps(exception_message)) self.application.unregister_connection(self) self.trade_client.close() self.close() def is_user_logged(self): if not self.user_response: return False return self.user_response.get('UserStatus') == 1 def is_broker(self): if not self.is_user_logged(): return False return self.user_response.get('IsBroker') == 1 def get_broker_wallet(self, type, currency): if not self.user_response: return broker = self.user_response.get('Broker') if not broker: return if 'CryptoCurrencies' not in broker: return broker_crypto_currencies = broker['CryptoCurrencies'] for crypto_currency in broker_crypto_currencies: if crypto_currency['CurrencyCode'] == currency: for wallet in crypto_currency['Wallets']: if wallet['type'] == type: return wallet['address'] def on_trade_history_request(self, msg): since = msg.get('Since') page = msg.get('Page', 0) page_size = msg.get('PageSize', 100) filter = msg.get('Filter') offset = page * page_size if self.is_broker(): columns = [ 'TradeID', 'Market', 'Side', 'Price', 'Size', 'Buyer', 'Seller', 'Created', 'BuyerUsername', 'SellerUsername' ] else: columns = [ 'TradeID', 'Market', 'Side', 'Price', 'Size', 'Buyer', 'Seller', 'Created' ] trade_list = generate_trade_history(self.application.db_session, page_size, offset, show_username=self.is_broker(), since=since) response_msg = { 'MsgType': 'U33', # TradeHistoryResponse 'TradeHistoryReqID': msg.get('TradeHistoryReqID'), 'Page': page, 'PageSize': page_size, 'Columns': columns, 'TradeHistoryGrp': trade_list } if since: response_msg['Since'] = since self.write_message(str(json.dumps(response_msg, cls=JsonEncoder))) def on_security_status_request(self, msg): # Generate a FullRefresh req_id = msg.get('SecurityStatusReqID') # Disable previous Snapshot + Update Request if int(msg.get('SubscriptionRequestType')) == 2: if req_id in self.sec_status_subscriptions: for sec_status_publisher in self.sec_status_subscriptions[ req_id]: sec_status_publisher.cleanup() self.sec_status_subscriptions[req_id] = [] del self.sec_status_subscriptions[req_id] return instruments = msg.get('Instruments') if int(msg.get('SubscriptionRequestType')) == 1: # Snapshot + Updates if req_id not in self.sec_status_subscriptions: self.sec_status_subscriptions[req_id] = [] for instrument in instruments: ss = generate_security_status(instrument, req_id) self.write_message(str(json.dumps(ss, cls=JsonEncoder))) # Snapshot + Updates if int(msg.get('SubscriptionRequestType')) == 1: self.sec_status_subscriptions[req_id].append( SecurityStatusPublisher(req_id, instrument, self.on_send_json_msg_to_user)) def on_market_data_request(self, msg): # Generate a FullRefresh req_id = msg.get('MDReqID') # Disable previous Snapshot + Update Request if int(msg.get('SubscriptionRequestType')) == 2: if req_id in self.md_subscriptions: for md_publisher in self.md_subscriptions[req_id]: md_publisher.cleanup() self.md_subscriptions[req_id] = [] del self.md_subscriptions[req_id] return market_depth = msg.get('MarketDepth') instruments = msg.get('Instruments') entries = msg.get('MDEntryTypes') if int(msg.get('SubscriptionRequestType')) == 1: # Snapshot + Updates if req_id not in self.md_subscriptions: self.md_subscriptions[req_id] = [] for instrument in instruments: md = generate_md_full_refresh(instrument, market_depth, entries, req_id, self.is_broker()) self.write_message(str(json.dumps(md, cls=JsonEncoder))) # Snapshot + Updates if int(msg.get('SubscriptionRequestType')) == 1: self.md_subscriptions[req_id].append( MarketDataPublisher(req_id, market_depth, entries, instrument, self.on_send_json_msg_to_user, self.is_broker())) def on_send_json_msg_to_user(self, sender, json_msg): s = json.dumps(json_msg, cls=JsonEncoder) self.write_message(s)
def __init__(self, opt, instance_name): self.options = opt self.instance_name = instance_name handlers = [ (r'/', WebSocketHandler), (r'/get_deposit(.*)', DepositHandler), (r'/_webhook/verification_form', VerificationWebHookHandler), (r'/_webhook/deposit_receipt', DepositReceiptWebHookHandler), (r'/process_deposit(.*)', ProcessDepositHandler), (r'/api/(?P<version>[^\/]+)/(?P<symbol>[^\/]+)/(?P<resource>[^\/]+)', RestApiHandler) ] settings = dict(cookie_secret='cookie_secret') tornado.web.Application.__init__(self, handlers, **settings) self.allowed_origins = json.loads(self.options.allowed_origins) self.allow_all_origins = self.allowed_origins[0] == '*' input_log_file_handler = logging.handlers.TimedRotatingFileHandler( os.path.expanduser(self.options.gateway_log), when='MIDNIGHT') formatter = logging.Formatter('%(asctime)s - %(message)s') input_log_file_handler.setFormatter(formatter) self.replay_logger = logging.getLogger(self.instance_name) self.replay_logger.setLevel(logging.INFO) self.replay_logger.addHandler(input_log_file_handler) ch = logging.StreamHandler(sys.stdout) ch.setLevel(logging.DEBUG) ch.setFormatter( logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s')) self.replay_logger.addHandler(ch) self.replay_logger.info('START') self.log_start_data() self.update_tor_nodes() from models import Base, db_bootstrap db_engine = self.options.sqlalchemy_engine + ':///' +\ os.path.expanduser(self.options.sqlalchemy_connection_string) engine = create_engine(db_engine, echo=self.options.db_echo) Base.metadata.create_all(engine) self.db_session = scoped_session(sessionmaker(bind=engine)) db_bootstrap(self.db_session) self.zmq_context = zmq.Context() self.trade_in_socket = self.zmq_context.socket(zmq.REQ) self.trade_in_socket.connect(self.options.trade_in) self.application_trade_client = TradeClient(self.zmq_context, self.trade_in_socket) self.application_trade_client.connect() self.security_list = self.application_trade_client.getSecurityList() self.md_subscriber = {} for instrument in self.security_list.get('Instruments'): symbol = instrument['Symbol'] self.md_subscriber[symbol] = MarketDataSubscriber.get(symbol, self) self.md_subscriber[symbol].subscribe(self.zmq_context, self.options.trade_pub, self.application_trade_client) last_trade_id = Trade.get_last_trade_id(self.db_session) trade_list = self.application_trade_client.getLastTrades(last_trade_id) for trade in trade_list: msg = dict() msg['id'] = trade[0] msg['symbol'] = trade[1] msg['side'] = trade[2] msg['price'] = trade[3] msg['size'] = trade[4] msg['buyer_id'] = trade[5] msg['seller_id'] = trade[6] msg['buyer_username'] = trade[7] msg['seller_username'] = trade[8] msg['created'] = trade[9] msg['trade_date'] = trade[9][:10] msg['trade_time'] = trade[9][11:] msg['order_id'] = trade[10] msg['counter_order_id'] = trade[11] Trade.create(self.db_session, msg) all_trades = Trade.get_all_trades(self.db_session) for t in all_trades: trade_info = dict() trade_info['price'] = t.price trade_info['size'] = t.size trade_info['trade_date'] = t.created.strftime('%Y-%m-%d') trade_info['trade_time'] = t.created.strftime('%H:%M:%S') self.md_subscriber[t.symbol].inst_status.push_trade(trade_info) for symbol, subscriber in self.md_subscriber.iteritems(): subscriber.ready() self.connections = {} self.heart_beat_timer = tornado.ioloop.PeriodicCallback( self.send_heartbeat_to_trade, 30000) self.heart_beat_timer.start() self.update_tor_nodes_timer = tornado.ioloop.PeriodicCallback( self.update_tor_nodes, 3600000) self.update_tor_nodes_timer.start()
class WebSocketGatewayApplication(tornado.web.Application): def __init__(self, opt, instance_name): self.options = opt self.instance_name = instance_name handlers = [ (r'/', WebSocketHandler), (r'/get_deposit(.*)', DepositHandler), (r'/_webhook/verification_form', VerificationWebHookHandler), (r'/_webhook/deposit_receipt', DepositReceiptWebHookHandler), (r'/process_deposit(.*)', ProcessDepositHandler), (r'/api/(?P<version>[^\/]+)/(?P<symbol>[^\/]+)/(?P<resource>[^\/]+)', RestApiHandler) ] settings = dict(cookie_secret='cookie_secret') tornado.web.Application.__init__(self, handlers, **settings) self.allowed_origins = json.loads(self.options.allowed_origins) self.allow_all_origins = self.allowed_origins[0] == '*' input_log_file_handler = logging.handlers.TimedRotatingFileHandler( os.path.expanduser(self.options.gateway_log), when='MIDNIGHT') formatter = logging.Formatter('%(asctime)s - %(message)s') input_log_file_handler.setFormatter(formatter) self.replay_logger = logging.getLogger(self.instance_name) self.replay_logger.setLevel(logging.INFO) self.replay_logger.addHandler(input_log_file_handler) ch = logging.StreamHandler(sys.stdout) ch.setLevel(logging.DEBUG) ch.setFormatter( logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s')) self.replay_logger.addHandler(ch) self.replay_logger.info('START') self.log_start_data() self.update_tor_nodes() from models import Base, db_bootstrap db_engine = self.options.sqlalchemy_engine + ':///' +\ os.path.expanduser(self.options.sqlalchemy_connection_string) engine = create_engine(db_engine, echo=self.options.db_echo) Base.metadata.create_all(engine) self.db_session = scoped_session(sessionmaker(bind=engine)) db_bootstrap(self.db_session) self.zmq_context = zmq.Context() self.trade_in_socket = self.zmq_context.socket(zmq.REQ) self.trade_in_socket.connect(self.options.trade_in) self.application_trade_client = TradeClient(self.zmq_context, self.trade_in_socket) self.application_trade_client.connect() self.security_list = self.application_trade_client.getSecurityList() self.md_subscriber = {} for instrument in self.security_list.get('Instruments'): symbol = instrument['Symbol'] self.md_subscriber[symbol] = MarketDataSubscriber.get(symbol, self) self.md_subscriber[symbol].subscribe(self.zmq_context, self.options.trade_pub, self.application_trade_client) last_trade_id = Trade.get_last_trade_id(self.db_session) trade_list = self.application_trade_client.getLastTrades(last_trade_id) for trade in trade_list: msg = dict() msg['id'] = trade[0] msg['symbol'] = trade[1] msg['side'] = trade[2] msg['price'] = trade[3] msg['size'] = trade[4] msg['buyer_id'] = trade[5] msg['seller_id'] = trade[6] msg['buyer_username'] = trade[7] msg['seller_username'] = trade[8] msg['created'] = trade[9] msg['trade_date'] = trade[9][:10] msg['trade_time'] = trade[9][11:] msg['order_id'] = trade[10] msg['counter_order_id'] = trade[11] Trade.create(self.db_session, msg) all_trades = Trade.get_all_trades(self.db_session) for t in all_trades: trade_info = dict() trade_info['price'] = t.price trade_info['size'] = t.size trade_info['trade_date'] = t.created.strftime('%Y-%m-%d') trade_info['trade_time'] = t.created.strftime('%H:%M:%S') self.md_subscriber[t.symbol].inst_status.push_trade(trade_info) for symbol, subscriber in self.md_subscriber.iteritems(): subscriber.ready() self.connections = {} self.heart_beat_timer = tornado.ioloop.PeriodicCallback( self.send_heartbeat_to_trade, 30000) self.heart_beat_timer.start() self.update_tor_nodes_timer = tornado.ioloop.PeriodicCallback( self.update_tor_nodes, 3600000) self.update_tor_nodes_timer.start() def format_currency(self, currency_code, value, is_value_in_satoshis=True): currencies = self.security_list.get('Currencies') for currency_obj in currencies: if currency_obj['Code'] == currency_code: if is_value_in_satoshis: return currency_obj['FormatPython'].format(value / 1e8) else: return currency_obj['FormatPython'].format(value) return value def is_origin_allowed(self, origin): if self.allow_all_origins: return True if origin in self.allowed_origins: return True return False def is_tor_node(self, ip): self.log('DEBUG', 'TOR_CHECK', ip) return ip in self.tor_ip_list_ def log_start_data(self): self.log('PARAM', 'BEGIN') self.log('PARAM', 'callback_url', self.options.callback_url) self.log('PARAM', 'port', self.options.port) self.log('PARAM', 'trade_in', self.options.trade_in) self.log('PARAM', 'trade_pub', self.options.trade_pub) self.log('PARAM', 'url_payment_processor', self.options.url_payment_processor) self.log('PARAM', 'session_timeout_limit', self.options.session_timeout_limit) self.log('PARAM', 'db_echo', self.options.db_echo) self.log('PARAM', 'sqlalchemy_engine', self.options.sqlalchemy_engine) self.log('PARAM', 'sqlalchemy_connection_string', self.options.sqlalchemy_connection_string) self.log('PARAM', 'allowed_origins', self.options.allowed_origins) self.log('PARAM', 'END') def log(self, command, key, value=None): log_msg = command + ',' + key if value: try: log_msg += ',' + value except Exception, e: try: log_msg += ',' + str(value) except Exception, e: try: log_msg += ',' + unicode(value) except Exception, e: log_msg += ', [object]'
def run_application(options, instance_name): input_log_file_handler = logging.handlers.TimedRotatingFileHandler( os.path.expanduser(options.mailer_log), when='MIDNIGHT') input_log_file_handler.setFormatter(logging.Formatter(u"%(asctime)s - %(message)s")) app_logger = logging.getLogger(instance_name) app_logger.setLevel(logging.INFO) app_logger.addHandler(input_log_file_handler) ch = logging.StreamHandler(sys.stdout) ch.setLevel(logging.DEBUG) ch.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')) app_logger.addHandler(ch) app_logger.info('START') def log(command, key, value=None): log_msg = u'%s, %s, %s' %(command, key, value if value else None) app_logger.info(unicode(log_msg)) log('PARAM', 'BEGIN') log('PARAM', 'trade_in', options.trade_in) log('PARAM', 'trade_pub', options.trade_pub) log('PARAM', 'app_log', options.app_log) log('PARAM', 'maxmind_license_key', options.maxmind_license_key) log('PARAM', 'END') context = zmq.Context() socket = context.socket(zmq.SUB) socket.connect(options.trade_pub) socket.setsockopt(zmq.SUBSCRIBE, "^FRAUDER$") trade_in_socket = context.socket(zmq.REQ) trade_in_socket.connect(options.trade_in) application_trade_client = TradeClient( context, trade_in_socket) application_trade_client.connect() login_response = application_trade_client.sendJSON( MessageBuilder.login( 8999999, options.frauder_username, options.frauder_password)) if login_response.get('UserStatus') != 1: raise RuntimeError("Invalid user id") brokers = {} broker_list, broker_list_columns = application_trade_client.getBrokerList(['1']) for b in broker_list: brokers[b[0]] = { "params": b } while True: try: raw_email_message = socket.recv() log('IN', 'TRADE_IN_PUB', raw_email_message) msg = JsonMessage(raw_email_message) if not msg.isAccessLog(): continue try: broker_id = msg.get('BrokerID') except Exception as ex: traceback.print_exc() log('ERROR', 'EXCEPTION', str(ex)) time.sleep(1) except KeyboardInterrupt: app_logger.info('END') break except Exception as ex: time.sleep(1)
def run_application(options, instance_name): input_log_file_handler = logging.handlers.TimedRotatingFileHandler( os.path.expanduser(options.mailer_log), when='MIDNIGHT') input_log_file_handler.setFormatter(logging.Formatter(u"%(asctime)s - %(message)s")) mail_logger = logging.getLogger(instance_name) mail_logger.setLevel(logging.INFO) mail_logger.addHandler(input_log_file_handler) ch = logging.StreamHandler(sys.stdout) ch.setLevel(logging.DEBUG) ch.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')) mail_logger.addHandler(ch) mail_logger.info('START') def log(command, key, value=None): log_msg = u'%s, %s, %s' %(command, key, value if value else None) mail_logger.info(unicode(log_msg)) log('PARAM', 'BEGIN') log('PARAM', 'trade_in', options.trade_in) log('PARAM', 'trade_pub', options.trade_pub) log('PARAM', 'mailer_log', options.mailer_log) log('PARAM', 'mailchimp_apikey', options.mailchimp_apikey) log('PARAM', 'mandrill_apikey', options.mandrill_apikey) log('PARAM', 'mailer_username', options.mailer_username) log('PARAM', 'mailchimp_newsletter_list_id', options.mailchimp_newsletter_list_id) log('PARAM', 'END') context = zmq.Context() socket = context.socket(zmq.SUB) socket.connect(options.trade_pub) socket.setsockopt(zmq.SUBSCRIBE, "^EMAIL$") trade_in_socket = context.socket(zmq.REQ) trade_in_socket.connect(options.trade_in) application_trade_client = TradeClient( context, trade_in_socket) application_trade_client.connect() login_response = application_trade_client.sendJSON( MessageBuilder.login( 8999999, options.mailer_username, options.mailer_password)) if login_response.get('UserStatus') != 1: raise RuntimeError("Invalid user id") brokers = {} broker_list, broker_list_columns = application_trade_client.getBrokerList(['1']) for b in broker_list: brokers[b[0]] = { "params": b } broker_mandrill_column_index = None try: broker_mandrill_column_index = broker_list_columns.index('MandrillApiKey') except ValueError: pass for broker_id, broker_data in brokers.iteritems(): if broker_mandrill_column_index and broker_data['params'][ broker_mandrill_column_index ]: broker_data['MandrillApiKey'] = broker_data['params'][ broker_mandrill_column_index ] else: broker_data['MandrillApiKey'] = options.mandrill_apikey for broker_id, broker_data in brokers.iteritems(): print broker_id, broker_data['MandrillApiKey'] # [u'BrokerID', u'ShortName', u'BusinessName', u'Address', u'City', u'State', # u'ZipCode', u'Country', u'PhoneNumber1', u'PhoneNumber2', u'Skype', u'Currencies', # u'TosUrl', u'FeeStructure', u'TransactionFeeBuy', u'TransactionFeeSell', u'Status', # u'ranking', u'Email', u'CountryCode', u'CryptoCurrencies', u'WithdrawStructure', # u'SupportURL', u'SignupLabel', u'AcceptCustomersFrom', u'IsBrokerHub'] mailchimp_api = mailchimp.Mailchimp(options.mailchimp_apikey) try: mailchimp_api.helper.ping() except mailchimp.Error: raise RuntimeError("Invalid MailChimp API key") mandrill_api = mandrill.Mandrill(options.mandrill_apikey) try: mandrill_api.users.ping() except mandrill.Error: raise RuntimeError("Invalid Mandrill API key") while True: try: raw_email_message = socket.recv() log('IN', 'TRADE_IN_PUB', raw_email_message) msg = JsonMessage(raw_email_message) if not msg.isEmail(): log('ERROR', 'EXCEPTION', 'Received message is not an email message') continue try: broker_id = msg.get('BrokerID') sender = brokers[broker_id]['params'][broker_list_columns.index('MailerFromName')] + \ '<' + brokers[broker_id]['params'][broker_list_columns.index('MailerFromEmail')] + '>' body = "" msg_to = msg.get('To') subject = msg.get('Subject') language = msg.get('Language') content_type = 'plain' if msg.has('Template') and msg.get('Template'): params = {} if msg.has('Params') and msg.get('Params'): params = json.loads(msg.get('Params')) template_name = msg.get('Template') if template_name == 'welcome': # user signup .... let's register him on mailchimp newsletter try: mailchimp_api.lists.subscribe( id = brokers[broker_id]['params'][broker_list_columns.index('MailchimpListID')], email = {'email': params['email'] }, merge_vars = {'EMAIL' : params['email'], 'FNAME': params['username'] } ) except mailchimp.ListAlreadySubscribedError: log('ERROR', 'EXCEPTION', params['email'] + ' mailchimp.ListAlreadySubscribedError' ) except mailchimp.Error, e: log('ERROR', 'EXCEPTION', str(e)) template_content = [] for k,v in params.iteritems(): template_content.append( { 'name': k, 'content': v } ) for broker_column_key in broker_list_columns: broker_column_value = brokers[broker_id]['params'][broker_list_columns.index(broker_column_key)] template_content.append( { 'name': 'broker_' + convertCamelCase2Underscore(broker_column_key), 'content': broker_column_value } ) message = { 'from_email': brokers[broker_id]['params'][broker_list_columns.index('MailerFromEmail')], 'from_name': brokers[broker_id]['params'][broker_list_columns.index('MailerFromName')], 'to': [{'email': msg_to, 'name': params['username'],'type': 'to' }], 'metadata': {'website': 'www.blinktrade.com'}, 'global_merge_vars': template_content } result = mandrill_api.messages.send_template( template_name= (template_name + '-' + language.replace('_','-') ).lower(), template_content=template_content, message=message) log('INFO', 'SUCCESS', str(result)) continue elif msg.has('RawData') and msg.get('RawData'): body = msg.get('RawData') log('DEBUG', 'EMAIL', u'{"Sender":"%s","To":"%s","Subject":"%s", "Body":"%s" }' % (sender, msg_to, subject, body)) send_email(sender, msg_to, subject, body, content_type) log('IN', 'SENT', "") log('INFO', 'SUCCESS', msg.get('EmailThreadID')) except Exception as ex: traceback.print_exc() log('ERROR', 'EXCEPTION', str(ex)) time.sleep(1) except KeyboardInterrupt: mail_logger.info('END') break
def run_application(options, instance_name): input_log_file_handler = logging.handlers.TimedRotatingFileHandler( os.path.expanduser(options.mailer_log), when='MIDNIGHT') input_log_file_handler.setFormatter( logging.Formatter(u"%(asctime)s - %(message)s")) mail_logger = logging.getLogger(instance_name) mail_logger.setLevel(logging.INFO) mail_logger.addHandler(input_log_file_handler) ch = logging.StreamHandler(sys.stdout) ch.setLevel(logging.DEBUG) ch.setFormatter( logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s')) mail_logger.addHandler(ch) mail_logger.info('START') def log(command, key, value=None): log_msg = u'%s, %s, %s' % (command, key, value if value else None) mail_logger.info(unicode(log_msg)) log('PARAM', 'BEGIN') log('PARAM', 'trade_in', options.trade_in) log('PARAM', 'trade_pub', options.trade_pub) log('PARAM', 'mailer_log', options.mailer_log) log('PARAM', 'mailchimp_apikey', options.mailchimp_apikey) log('PARAM', 'mandrill_apikey', options.mandrill_apikey) log('PARAM', 'mailer_username', options.mailer_username) log('PARAM', 'mailchimp_newsletter_list_id', options.mailchimp_newsletter_list_id) log('PARAM', 'END') context = zmq.Context() socket = context.socket(zmq.SUB) socket.connect(options.trade_pub) socket.setsockopt(zmq.SUBSCRIBE, "^EMAIL$") trade_in_socket = context.socket(zmq.REQ) trade_in_socket.connect(options.trade_in) application_trade_client = TradeClient(context, trade_in_socket) application_trade_client.connect() login_response = application_trade_client.sendJSON( MessageBuilder.login(8999999, options.mailer_username, options.mailer_password)) if login_response.get('UserStatus') != 1: raise RuntimeError("Invalid user id") brokers = {} broker_list, broker_list_columns = application_trade_client.getBrokerList( ['1']) for b in broker_list: brokers[b[0]] = {"params": b} broker_mandrill_column_index = None try: broker_mandrill_column_index = broker_list_columns.index( 'MandrillApiKey') except ValueError: pass for broker_id, broker_data in brokers.iteritems(): if broker_mandrill_column_index and broker_data['params'][ broker_mandrill_column_index]: broker_data['MandrillApiKey'] = broker_data['params'][ broker_mandrill_column_index] else: broker_data['MandrillApiKey'] = options.mandrill_apikey for broker_id, broker_data in brokers.iteritems(): print broker_id, broker_data['MandrillApiKey'] # [u'BrokerID', u'ShortName', u'BusinessName', u'Address', u'City', u'State', # u'ZipCode', u'Country', u'PhoneNumber1', u'PhoneNumber2', u'Skype', u'Currencies', # u'TosUrl', u'FeeStructure', u'TransactionFeeBuy', u'TransactionFeeSell', u'Status', # u'ranking', u'Email', u'CountryCode', u'CryptoCurrencies', u'WithdrawStructure', # u'SupportURL', u'SignupLabel', u'AcceptCustomersFrom', u'IsBrokerHub'] mailchimp_api = mailchimp.Mailchimp(options.mailchimp_apikey) try: mailchimp_api.helper.ping() except mailchimp.Error: raise RuntimeError("Invalid MailChimp API key") mandrill_api = mandrill.Mandrill(options.mandrill_apikey) try: mandrill_api.users.ping() except mandrill.Error: raise RuntimeError("Invalid Mandrill API key") while True: try: raw_email_message = socket.recv() log('IN', 'TRADE_IN_PUB', raw_email_message) msg = JsonMessage(raw_email_message) if not msg.isEmail(): log('ERROR', 'EXCEPTION', 'Received message is not an email message') continue try: broker_id = msg.get('BrokerID') sender = brokers[broker_id]['params'][broker_list_columns.index('MailerFromName')] + \ '<' + brokers[broker_id]['params'][broker_list_columns.index('MailerFromEmail')] + '>' body = "" msg_to = msg.get('To') subject = msg.get('Subject') language = msg.get('Language') content_type = 'plain' if msg.has('Template') and msg.get('Template'): params = {} if msg.has('Params') and msg.get('Params'): params = json.loads(msg.get('Params')) template_name = msg.get('Template') if template_name == 'welcome': # user signup .... let's register him on mailchimp newsletter try: mailchimp_api.lists.subscribe( id=brokers[broker_id]['params'] [broker_list_columns.index('MailchimpListID')], email={'email': params['email']}, merge_vars={ 'EMAIL': params['email'], 'FNAME': params['username'] }) except mailchimp.ListAlreadySubscribedError: log( 'ERROR', 'EXCEPTION', params['email'] + ' mailchimp.ListAlreadySubscribedError') except mailchimp.Error, e: log('ERROR', 'EXCEPTION', str(e)) template_content = [] for k, v in params.iteritems(): template_content.append({'name': k, 'content': v}) for broker_column_key in broker_list_columns: broker_column_value = brokers[broker_id]['params'][ broker_list_columns.index(broker_column_key)] template_content.append({ 'name': 'broker_' + convertCamelCase2Underscore(broker_column_key), 'content': broker_column_value }) message = { 'from_email': brokers[broker_id]['params'][broker_list_columns.index( 'MailerFromEmail')], 'from_name': brokers[broker_id]['params'][broker_list_columns.index( 'MailerFromName')], 'to': [{ 'email': msg_to, 'name': params['username'], 'type': 'to' }], 'metadata': { 'website': 'www.blinktrade.com' }, 'global_merge_vars': template_content } result = mandrill_api.messages.send_template( template_name=(template_name + '-' + language.replace('_', '-')).lower(), template_content=template_content, message=message) log('INFO', 'SUCCESS', str(result)) continue elif msg.has('RawData') and msg.get('RawData'): body = msg.get('RawData') log( 'DEBUG', 'EMAIL', u'{"Sender":"%s","To":"%s","Subject":"%s", "Body":"%s" }' % (sender, msg_to, subject, body)) send_email(sender, msg_to, subject, body, content_type) log('IN', 'SENT', "") log('INFO', 'SUCCESS', msg.get('EmailThreadID')) except Exception as ex: traceback.print_exc() log('ERROR', 'EXCEPTION', str(ex)) time.sleep(1) except KeyboardInterrupt: mail_logger.info('END') break