class Coinbase::Exchange::Websocket

Websocket client for Coinbase Exchange

Public Class Methods

new(options = {}) click to toggle source
# File lib/coinbase/exchange/websocket.rb, line 5
def initialize(options = {})
  @ws_url = options[:ws_url] || "wss://ws-feed.gdax.com"
  @products = options[:product_ids] || ["BTC-USD"]
  @keepalive = options[:keepalive] || false

  @message_cb = ->(_data) { nil }
  @received_cb = ->(_data) { nil }
  @open_cb = ->(_data) { nil }
  @match_cb = ->(_data) { nil }
  @change_cb = ->(_data) { nil }
  @done_cb = ->(_data) { nil }
  @error_cb = ->(_data) { nil }

  @key = options[:key]
  @secret = options[:secret]
  @passphrase = options[:passphrase]
end

Public Instance Methods

change(&block) click to toggle source
# File lib/coinbase/exchange/websocket.rb, line 90
def change(&block)
  @change_cb = block
end
done(&block) click to toggle source
# File lib/coinbase/exchange/websocket.rb, line 94
def done(&block)
  @done_cb = block
end
error(&block) click to toggle source
# File lib/coinbase/exchange/websocket.rb, line 98
def error(&block)
  @error_cb = block
end
match(&block) click to toggle source
# File lib/coinbase/exchange/websocket.rb, line 86
def match(&block)
  @match_cb = block
end
message(&block) click to toggle source

Run this before processing every message

# File lib/coinbase/exchange/websocket.rb, line 74
def message(&block)
  @message_cb = block
end
open(&block) click to toggle source
# File lib/coinbase/exchange/websocket.rb, line 82
def open(&block)
  @open_cb = block
end
ping(options = {}) { |resp| ... } click to toggle source
# File lib/coinbase/exchange/websocket.rb, line 66
def ping(options = {})
  msg = options[:payload] || Time.now.to_s
  @socket.ping(msg) do |resp|
    yield(resp) if block_given?
  end
end
received(&block) click to toggle source
# File lib/coinbase/exchange/websocket.rb, line 78
def received(&block)
  @received_cb = block
end
refresh!() click to toggle source
# File lib/coinbase/exchange/websocket.rb, line 42
def refresh!
  @socket = Faye::WebSocket::Client.new(@ws_url)
  @socket.onopen = method(:ws_opened)
  @socket.onmessage = method(:ws_received)
  @socket.onclose = method(:ws_closed)
  @socket.onerror = method(:ws_error)
end
start!() click to toggle source
# File lib/coinbase/exchange/websocket.rb, line 23
def start!
  if EventMachine.reactor_running?
    @reactor_owner = false
    refresh!
  else
    @reactor_owner = true
    EM.run { refresh! }
  end
end
stop!() click to toggle source
# File lib/coinbase/exchange/websocket.rb, line 33
def stop!
  if @reactor_owner == true
    @socket.onclose = ->(_event) { EM.stop }
  else
    @socket.onclose = ->(_event) { nil }
  end
  @socket.close
end
subscribe!(options = {}) click to toggle source
# File lib/coinbase/exchange/websocket.rb, line 50
def subscribe!(options = {})
  products = options[:product_ids] || @products
  channels = options[:channels] || ["ticker", "user"]
  timestamp = DateTime.now
  payload = {
                type: "subscribe",
                product_ids: products,
                "channels": channels,
                "signature": ws_signature(timestamp: timestamp),
                "key": @key,
                "passphrase": @passphrase,
                "timestamp": timestamp.to_i
            }
  @socket.send(payload.to_json)
end

Private Instance Methods

ws_closed(_event) click to toggle source
# File lib/coinbase/exchange/websocket.rb, line 121
def ws_closed(_event)
  if @keepalive
    refresh!
  else
    EM.stop
  end
end
ws_error(event) click to toggle source
# File lib/coinbase/exchange/websocket.rb, line 129
def ws_error(event)
  fail WebsocketError, event.data
end
ws_opened(_event) click to toggle source
# File lib/coinbase/exchange/websocket.rb, line 104
def ws_opened(_event)
  subscribe!
end
ws_received(event) click to toggle source
# File lib/coinbase/exchange/websocket.rb, line 108
def ws_received(event)
  data = APIObject.new(JSON.parse(event.data))
  @message_cb.call(data)
  case data['type']
  when 'received' then @received_cb.call(data)
  when 'open' then @open_cb.call(data)
  when 'match' then @match_cb.call(data)
  when 'change' then @change_cb.call(data)
  when 'done' then @done_cb.call(data)
  when 'error' then @error_cb.call(data)
  end
end
ws_signature(request_path: '/users/self/verify', body: nil, timestamp: nil, method: 'GET') click to toggle source
# File lib/coinbase/exchange/websocket.rb, line 133
def ws_signature(request_path: '/users/self/verify', body: nil, timestamp: nil, method: 'GET')
  raise "timestamp must not be nil" if timestamp.nil?

  body = body.to_json if body.is_a?(Hash)
  timestamp = Time.now.to_i if !timestamp
  timestamp = timestamp.to_i if timestamp.is_a?(DateTime)

  what = "#{timestamp}#{method}#{request_path}#{body}";

  # create a sha256 hmac with the secret
  secret = Base64.decode64(@secret)
  hash  = OpenSSL::HMAC.digest('sha256', secret, what)
  Base64.strict_encode64(hash)
end