Last active
June 10, 2018 04:17
-
-
Save frankzhao/8492ee02e1343cb1fa471a03f8c3e656 to your computer and use it in GitHub Desktop.
Example BTC Markets websocket api implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
""" | |
btcmarkets.py | |
usage: python btcmarkets.py 'socket.btcmarkets.net' 443 | |
Example BTC Markets websocket api implementation based on | |
https://github.com/BTCMarkets/API/wiki/websocket | |
BTC Markets uses a Socket.IO server. This uses an initial https connection | |
that is then upgraded to wss (RFC6455). For the Socket.IO protocol, see | |
(https://github.com/socketio/engine.io-protocol). | |
This script connects to the websocket endpoint and returns ticker | |
information as it is received from the server. | |
Created by Frank Zhao (https://github.com/frankzhao) | |
""" | |
import websockets | |
import sys | |
import logging | |
import asyncio | |
import json | |
from six.moves.urllib.parse import urlencode | |
logging.basicConfig(level=logging.INFO) | |
logger = logging.getLogger('btcmarkets') | |
async def connect(server, port): | |
logger.info("Connecting to: %s:%d" % (server, port)) | |
query_params = { | |
'EIO': 3, | |
'transport': 'websocket' | |
} | |
wss_url = 'wss://' + server + ':' + str(port) + '/socket.io/?' + urlencode(query_params) | |
async with websockets.connect(wss_url) as websocket: # type: websockets.client.WebSocketClientProtocol | |
json_decoder = json.JSONDecoder() | |
response = await websocket.recv() | |
response = json_decoder.decode(response[1:]) # type: dict | |
sid = response.get('sid') | |
ping_timeout = response.get('pingTimeout') | |
logger.debug("< Received session ID: {}".format(sid)) | |
packet = await websocket.recv() | |
try: | |
assert packet == '40' | |
except AssertionError: | |
logging.error("Connection failed! Server response: %s", packet) | |
websocket.timeout = int(ping_timeout) | |
await websocket.ping() | |
await websocket.send('42' + '[\"join\", \"Ticker-BTCMarkets-BTC-AUD\"]') # mock socket.emit() | |
try: | |
while True: | |
packet = await websocket.recv() | |
logger.info(packet) # this is the ticker info | |
await websocket.pong() | |
except KeyboardInterrupt: | |
websocket.close() | |
if __name__ == '__main__': | |
if len(sys.argv) != 3: | |
sys.stderr.write('usage: python btcmarkets.py <server> <port>\n') | |
sys.exit(1) | |
server = sys.argv[1] | |
port = int(sys.argv[2]) | |
asyncio.get_event_loop().run_until_complete(connect(server, port)) |
Hey, so I tacked this problem a couple of weeks ago, my result is here:
https://gist.github.com/aljp/cb7a85e4f3f1352bbf66165150961892
It could probably be a bit more robust (i.e. checking the connection response), however it does deal with sending the heartbeat according to the pingInterval, and also recovers the websocket connection when CloudFlare's proxy (or something) kills the connection because it is idle.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@georgysh Yes, I have noticed the same behaviour. I haven't found the solution yet, but the frame received appears to be a Connection Close frame: