class Bibox::Websocket::Client

Websocket client for Bibox

Attributes

callbacks[RW]
keepalive[RW]
matchers[RW]
prefix[RW]
reactor_owner[RW]
socket[RW]
url[RW]

Public Class Methods

new(options: {}) click to toggle source
# File lib/bibox/websocket/client.rb, line 7
def initialize(options: {})
  self.url          =   options.fetch(:url, "wss://push.bibox.com")
  self.prefix       =   options.fetch(:prefix, "bibox_sub_spot_")
  self.keepalive    =   options.fetch(:keepalive, false)
  
  self.matchers     =   {
    trading_pairs:          /\d?[A-Z]+_[A-Z]+_market/,
    order_book:             /\d?[A-Z]+_[A-Z]+_depth$/,
    trades:                 /\d?[A-Z]+_[A-Z]+_deals$/,
    ticker:                 /\d?[A-Z]+_[A-Z]+_ticker$/,
    klines:                 /\d?[A-Z]+_[A-Z]+_kline_(?<period>.*)$/,
    
    index_markets:          /\d?[A-Z]+_[A-Z]+_indexMarket/,
    contract_price_limits:  /\d?[A-Z]+_[A-Z]+_contractPriceLimit$/,
  }
  
  self.callbacks    =   {
    subscribe:              ->  { subscribe! },
    message:                ->  (data) { message(data) },
    trading_pairs:          ->  (data) { nil },
    order_book:             ->  (data) { nil },
    trades:                 ->  (data) { nil },
    ticker:                 ->  (data) { nil },
    klines:                 ->  (data) { nil },
    
    index_markets:          ->  (data) { nil },
    contract_price_limits:  ->  (data) { nil },
  }
end

Public Instance Methods

channel_name(channel) click to toggle source
# File lib/bibox/websocket/client.rb, line 106
def channel_name(channel)
  "#{self.prefix}#{channel}"
end
login!() click to toggle source
# File lib/bibox/websocket/client.rb, line 65
def login!
  subscribe_to! channel_name("ALL_ALL_login")
end
message(data) click to toggle source
# File lib/bibox/websocket/client.rb, line 110
def message(data)
  channel   =   data.fetch("channel", nil)&.gsub(self.prefix, "")
  
  case channel
    when self.matchers[:trading_pairs]
      self.callbacks[:trading_pairs].call(data)
    when self.matchers[:order_book]
      self.callbacks[:order_book].call(data)
    when self.matchers[:trades]
      self.callbacks[:trades].call(data)
    when self.matchers[:ticker]
      self.callbacks[:ticker].call(data)
    when self.matchers[:klines]
      period = channel.match(self.matchers[:klines])&.[](:period)
      data.merge!("period" => period) if !period.to_s.empty?
      self.callbacks[:klines].call(data)
    when self.matchers[:index_markets]
      self.callbacks[:index_markets].call(data)
    when self.matchers[:contract_price_limits]
      self.callbacks[:contract_price_limits].call(data)
  end
end
refresh!() click to toggle source
# File lib/bibox/websocket/client.rb, line 57
def refresh!
  self.socket             =   Faye::WebSocket::Client.new(self.url)
  self.socket.onopen      =   method(:on_open)
  self.socket.onmessage   =   method(:on_message)
  self.socket.onclose     =   method(:on_close)
  self.socket.onerror     =   method(:on_error)
end
start!() click to toggle source
# File lib/bibox/websocket/client.rb, line 37
def start!
  if EventMachine.reactor_running?
    self.reactor_owner    =   false
    refresh!
  else
    self.reactor_owner    =   true
    EM.run { refresh! }
  end
end
stop!() click to toggle source
# File lib/bibox/websocket/client.rb, line 47
def stop!
  if self.reactor_owner == true
    self.socket.onclose   =   -> (_event) { EM.stop }
  else
    self.socket.onclose   =   -> (_event) { nil }
  end

  self.socket.close
end
subscribe_to!(channel, binary: 0) click to toggle source
# File lib/bibox/websocket/client.rb, line 101
def subscribe_to!(channel, binary: 0)
  message = { event: "addChannel", channel: channel, binary: binary }
  self.socket.send(message.to_json)
end
subscribe_to_contract_price_limits!() click to toggle source
# File lib/bibox/websocket/client.rb, line 77
def subscribe_to_contract_price_limits!
  subscribe_to! channel_name("ALL_ALL_contractPriceLimit")
end
subscribe_to_index_markets!() click to toggle source
# File lib/bibox/websocket/client.rb, line 73
def subscribe_to_index_markets!
  subscribe_to! channel_name("ALL_ALL_indexMarket")
end
subscribe_to_klines!(pairs: [], periods: ["5min"]) click to toggle source
# File lib/bibox/websocket/client.rb, line 93
def subscribe_to_klines!(pairs: [], periods: ["5min"])
  pairs&.each do |pair|
    periods&.each do |period|
      subscribe_to! channel_name("#{pair}_kline_#{period}")
    end
  end
end
subscribe_to_order_book!(pairs: []) click to toggle source
# File lib/bibox/websocket/client.rb, line 81
def subscribe_to_order_book!(pairs: [])
  pairs&.each { |pair| subscribe_to! channel_name("#{pair}_depth") }
end
subscribe_to_ticker!(pairs: []) click to toggle source
# File lib/bibox/websocket/client.rb, line 89
def subscribe_to_ticker!(pairs: [])
  pairs&.each { |pair| subscribe_to! channel_name("#{pair}_ticker") }
end
subscribe_to_trades!(pairs: []) click to toggle source
# File lib/bibox/websocket/client.rb, line 85
def subscribe_to_trades!(pairs: [])
  pairs&.each { |pair| subscribe_to! channel_name("#{pair}_deals") }
end
subscribe_to_trading_pairs!() click to toggle source
# File lib/bibox/websocket/client.rb, line 69
def subscribe_to_trading_pairs!
  subscribe_to! channel_name("ALL_ALL_market")
end

Private Instance Methods

on_close(_event) click to toggle source
# File lib/bibox/websocket/client.rb, line 169
def on_close(_event)
  if self.keepalive
    refresh!
  else
    EM.stop
  end
end
on_error(event) click to toggle source
# File lib/bibox/websocket/client.rb, line 177
def on_error(event)
  raise ::Bibox::Errors::WebsocketError.new(event.message)
end
on_message(event) click to toggle source
# File lib/bibox/websocket/client.rb, line 149
def on_message(event)
  parsed                =   parse(event.data)
  
  if parsed
    if parsed.is_a?(Hash)
      send_pong(parsed["ping"]) unless parsed.fetch("ping", nil).to_s.empty?
    elsif parsed.is_a?(Array)
      parsed            =   parsed.first
    end
    
    is_binary           =   parsed.fetch("binary", nil)&.eql?("1")

    if is_binary && !parsed.fetch("data", nil).to_s.empty?
      parsed["data"]    =   parse(Bibox::Utilities.decode_and_inflate(parsed["data"]))
    end
  
    self.callbacks[:message].call(parsed)
  end
end
on_open(_event) click to toggle source
# File lib/bibox/websocket/client.rb, line 145
def on_open(_event)
  self.callbacks[:subscribe].call
end
parse(data) click to toggle source
# File lib/bibox/websocket/client.rb, line 134
def parse(data)
  return data if data.is_a? Hash
  return JSON.parse(data)
rescue => err
  return data
end
send_pong(timestamp) click to toggle source
# File lib/bibox/websocket/client.rb, line 141
def send_pong(timestamp)
  self.socket.send({pong: timestamp}.to_json)
end