class WebSocket(SSLConnection): def __init__(self, hostname, port, resource): SSLConnection.__init__(self) self.keys = WebSocketKeys() self.header_data = "" self.read_buffer = "" self.out_buffer = '' #synchroneous ssl connection self.connect((hostname, port)) request = WebSocketHandshakeRequest(resource, hostname, port, self.keys.key1, self.keys.key2, self.keys.key3) self.send(HandshakeRequestFormater.format(request)) self.EVENT_HANDSHAKE_COMPLETED = Event() self.EVENT_FRAME = Event() self.EVENT_DISCONNECTED = Event() self.handshake_completed = False def initiate_send(self): num_sent = SSLConnection.send(self, self.out_buffer[:512]) self.out_buffer = self.out_buffer[num_sent:] def handle_write(self): self.initiate_send() def writable(self): return (not self.connected) or len(self.out_buffer) def readable(self): return True def send(self, data): self.out_buffer = self.out_buffer + data def send_message(self, data): log.debug("send_message" + data) self.send('\x00' + data + '\xff') def handle_close(self): log.debug("handle_close2") self.EVENT_DISCONNECTED.fire() self.close() def handle_error(self): traceback.print_exc() def handle_read(self): self.read_buffer += self.recv(81920000) self.process_readbuffer() def process_readbuffer(self): if not self.handshake_completed: try: response, self.read_buffer = HandshakeResponseParser.parse(self.read_buffer) self.handshake_completed = True self.EVENT_HANDSHAKE_COMPLETED.fire() except HandshakeResponseIncomplete: pass if self.handshake_completed and self.read_buffer: frames, self.read_buffer = read_frames(self.read_buffer) for frame in frames: self.EVENT_FRAME.fire(frame=frame)
class MtGoxStreaming(): def __init__(self): self.socket_io = SocketIO("socketio.mtgox.com", "socket.io", "1", "?Currency=USD") self.socket_io.EVENT_CONNECTED_SOCKETIO.subscribe(self.on_connected) self.socket_io.EVENT_DISCONNECTED_SOCKETIO.subscribe(self.on_disconnected) self.socket_io.EVENT_CONNECTED_ENDPOINT.subscribe(self.on_connected_mtgox) self.socket_io.EVENT_JSON_MESSAGE.subscribe(self.on_json_message) self.EVENT_TRADE = Event() self.EVENT_TICKER_USD = Event() self.EVENT_DEPTH_USD = Event() self.socket_io.start() self.trade = "dbf1dee9-4f2e-4a08-8cb7-748919a71b21" #Trades self.ticker = "d5f06780-30a8-4a48-a2f8-7ed181b4a13f" #Ticker USD self.depth = "24e67e0d-1cad-4cc0-9e7a-f8523ef460fe" #Depth USD def on_connected(self, event): self.socket_io.connect("mtgox") def on_disconnected(self, event): log.info("Disconnected") def on_connected_mtgox(self, event): log.info( "Mtgox Connected") self.socket_io.send_json_message("/mtgox", '{"channel":"dbf1dee9-4f2e-4a08-8cb7-748919a71b21", "op":"subscribe"}') self.socket_io.send_json_message("/mtgox", '{"channel":"d5f06780-30a8-4a48-a2f8-7ed181b4a13f", "op":"subscribe"}') self.socket_io.send_json_message("/mtgox", '{"channel":"24e67e0d-1cad-4cc0-9e7a-f8523ef460fe", "op":"subscribe"}') def on_json_message(self, event): message = json.loads(event.data) if 'private' in message: private = message['private'] #ticker, trade, depth if private=='trade': self.EVENT_TRADE.fire(message=message) elif private=='ticker': self.EVENT_TICKER_USD.fire(message=message) elif private=='depth': self.EVENT_DEPTH_USD.fire(message=message) log.debug(event.endpoint + " " + str(message)) def on_subscribed(self, channel, message): channel = message['channel'] if channel==self.trade: channel_name = 'trade' elif channel==self.ticker: channel_name = 'ticker' elif channel==self.depth: channel_name = 'depth' else: channel_name = 'unknown' log.info( "subscribed to channel " + channel_name)
class SocketIO: """ SocketIO implementation ( websocket Transport ) spec : https://github.com/LearnBoost/socket.io-spec """ MSG_DISCONNECTED = "0" MSG_CONNECTED = "1" MSG_HEARTBEAT = "2" MSG_MESSAGE = "3" MSG_JSON_MESSAGE = "4" MSG_EVENT = "5" MSG_ACK = "6" MSG_ERROR = "7" MSG_NOP = "8" CONNECTED, CONNECTING, DISCONNECTED, DISCONNECTING = STATES = range(4) RECONNECT_INTERVAL = 5 #seconds def __init__(self, host, namespace, protocol_version, params): self.host = host # socketio.mtgox.com self.namespace = namespace # socket.io self.protocol_version = protocol_version # 1 self.params = params self.shuttingdown = False self.keep_alive_thread = Thread(target = self.keep_alive) self.keep_alive_thread.daemon = True self.state = SocketIO.DISCONNECTED# self.EVENT_CONNECTED_SOCKETIO = Event() self.EVENT_CONNECTED_ENDPOINT = Event() self.EVENT_JSON_MESSAGE = Event() self.EVENT_DISCONNECTED_SOCKETIO = Event() def start(self): self.keep_alive_thread.start() def connect_socketio(self): data = urllib.urlencode({}) req = urllib2.Request("https://" + self.host + "/" + self.namespace + "/" + self.protocol_version + "/" + self.params, data) response = urllib2.urlopen(req) response_params = response.read().split(':') self.id, heartbeat_interval_str, shutdown_interval_str, supported_transports_str = response_params self.heartbeat_interval = int(heartbeat_interval_str) supported_transports = supported_transports_str.split(',') if not 'websocket' in supported_transports: raise Exception("Websocket tranport not supported") self.websocket = WebSocket(self.host, 443, "/" + self.namespace + "/" + self.protocol_version + "/websocket/" + self.id) self.websocket.EVENT_FRAME.subscribe(self.on_frame) self.websocket.EVENT_DISCONNECTED.subscribe(self.on_disconnected) def on_disconnected(self, event): self.EVENT_DISCONNECTED_SOCKETIO.fire() log.debug("disconnected!") self.state = SocketIO.DISCONNECTED def connect(self, endpoint): self.websocket.send_message('1::/' + endpoint) def on_frame(self, event): msg_type, msg_id, msg_endpoint, msg_data = re.match("([0-9]):([^:]*):([^:]*):?(.*)", event.frame).groups() if msg_type == SocketIO.MSG_CONNECTED: if msg_endpoint == "": self.state = SocketIO.CONNECTED self.EVENT_CONNECTED_SOCKETIO.fire() else: self.EVENT_CONNECTED_ENDPOINT.fire(endpoint=msg_endpoint, data=msg_data) elif msg_type == SocketIO.MSG_JSON_MESSAGE: self.EVENT_JSON_MESSAGE.fire(data=msg_data, endpoint=msg_endpoint) else: log.debug("Unhandled message %s %s" % (msg_type, msg_data)) def stop(self): self.shuttingdown = True self.heartbeat_thread.join(timeout=1) def send_json_message(self, endpoint, message): self.websocket.send_message("4::" + endpoint + ":" + message) def keep_alive(self): next_heartbeat = time.time() try: while not self.shuttingdown: t = time.time() if self.state == SocketIO.DISCONNECTED: try: self.state = SocketIO.CONNECTING self.connect_socketio() except Exception as e: self.state = SocketIO.DISCONNECTED log.debug(traceback.format_exc()) log.warning("Error connecting : " + str(e)) time.sleep(SocketIO.RECONNECT_INTERVAL) if self.state == SocketIO.CONNECTED and t >= next_heartbeat: # Send heartbeat log.debug("Send heartbeat") self.websocket.send_message('2::') next_heartbeat = t + self.heartbeat_interval - 10 time.sleep(1) except: traceback.print_exc()