Skip to content

Instantly share code, notes, and snippets.

@frankzhao
Last active June 10, 2018 04:17
Show Gist options
  • Save frankzhao/8492ee02e1343cb1fa471a03f8c3e656 to your computer and use it in GitHub Desktop.
Save frankzhao/8492ee02e1343cb1fa471a03f8c3e656 to your computer and use it in GitHub Desktop.
Example BTC Markets websocket api implementation
#!/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))
@aljp
Copy link

aljp commented Jun 10, 2018

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