require 'websocket-client-simple' module BinanceAPI class Stream BASE_ENDPOINT = 'wss://stream.binance.com:9443/'.freeze def initialize(endpoints, on_open: nil, on_close: nil, on_error: nil, on_message: nil) raise 'on_open can accept a block only' if !on_open.nil? && !on_open.is_a?(Proc) raise 'on_close can accept a block only' if !on_close.nil? && !on_close.is_a?(Proc) raise 'on_error can accept a block only' if !on_error.nil? && !on_error.is_a?(Proc) raise 'on_data can accept a block only' if !on_message.nil? && !on_message.is_a?(Proc) @endpoints = Array(endpoints).reject(&:nil?).reject(&:empty?) raise 'endpoints cannot be empty' if @endpoints.empty? @on_open = on_open @on_close = on_close @on_error = on_error @on_message = on_message @stream_type = @endpoints.length > 1 ? :combined : :single end def start @ws = WebSocket::Client::Simple.connect "#{BASE_ENDPOINT}#{stream_url}" ws.on :message, &on_message ws.on :open, &on_open ws.on :close, &on_close ws.on :error, &on_error ws end def close ws.close end protected attr_reader :ws, :endpoints, :stream_type def stream_url stream_type == :combined ? combined_url(endpoints) : single_url(endpoints.first) end def single_url(stream_name) "ws/#{stream_name}" end def combined_url(stream_names) "stream?streams=#{stream_names.join('/')}" end def on_open @on_open || ->() { puts "-- websocket open (#{url})" } end def on_close @on_close || ->(e) { puts "-- websocket close (#{e.inspect})" } end def on_error @on_error || ->(e) { puts "-- error (#{e.inspect})" } end def on_message @on_message || ->(msg) { puts ">> #{msg.data}" } end end end