cryptomarket-sdk 1.0.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +161 -78
- data/lib/cryptomarket/client.rb +1154 -730
- data/lib/cryptomarket/constants.rb +123 -0
- data/lib/cryptomarket/credentials_factory.rb +53 -0
- data/lib/cryptomarket/exceptions.rb +18 -19
- data/lib/cryptomarket/http_manager.rb +98 -0
- data/lib/cryptomarket/websocket/auth_client.rb +72 -0
- data/lib/cryptomarket/websocket/callback_cache.rb +54 -0
- data/lib/cryptomarket/websocket/client_base.rb +135 -0
- data/lib/cryptomarket/websocket/market_data_client.rb +302 -0
- data/lib/cryptomarket/websocket/market_data_client_core.rb +62 -0
- data/lib/cryptomarket/websocket/methods.rb +36 -54
- data/lib/cryptomarket/websocket/reusable_callback.rb +21 -0
- data/lib/cryptomarket/websocket/trading_client.rb +274 -0
- data/lib/cryptomarket/websocket/wallet_client.rb +170 -0
- data/lib/cryptomarket/websocket/ws_manager.rb +65 -0
- metadata +77 -18
- data/lib/cryptomarket/HttpManager.rb +0 -71
- data/lib/cryptomarket/utils.rb +0 -57
- data/lib/cryptomarket/websocket/accountClient.rb +0 -110
- data/lib/cryptomarket/websocket/authClient.rb +0 -53
- data/lib/cryptomarket/websocket/callbackCache.rb +0 -51
- data/lib/cryptomarket/websocket/orderbookCache.rb +0 -123
- data/lib/cryptomarket/websocket/publicClient.rb +0 -239
- data/lib/cryptomarket/websocket/tradingClient.rb +0 -123
- data/lib/cryptomarket/websocket/wsClientBase.rb +0 -157
- data/lib/cryptomarket/websocket/wsManager.rb +0 -59
@@ -0,0 +1,123 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cryptomarket
|
4
|
+
module Args
|
5
|
+
module Sort
|
6
|
+
ASC = 'ASC'
|
7
|
+
DESC = 'DESC'
|
8
|
+
end
|
9
|
+
|
10
|
+
module Period # rubocop:disable Style/Documentation
|
11
|
+
_1_MINS = 'M1' # rubocop:disable Naming/VariableName
|
12
|
+
_3_MINS = 'M3' # rubocop:disable Naming/VariableName
|
13
|
+
_5_MINS = 'M5' # rubocop:disable Naming/VariableName
|
14
|
+
_15_MINS = 'M15' # rubocop:disable Naming/VariableName
|
15
|
+
_30_MINS = 'M30' # rubocop:disable Naming/VariableName
|
16
|
+
_1_HOURS = 'H1' # rubocop:disable Naming/VariableName
|
17
|
+
_4_HOURS = 'H4' # rubocop:disable Naming/VariableName
|
18
|
+
_1_DAYS = 'D1' # rubocop:disable Naming/VariableName
|
19
|
+
_7_DAYS = 'D7' # rubocop:disable Naming/VariableName
|
20
|
+
_1_MONTHS = '1M' # rubocop:disable Naming/VariableName
|
21
|
+
end
|
22
|
+
|
23
|
+
module Side
|
24
|
+
BUY = 'buy'
|
25
|
+
SELL = 'sell'
|
26
|
+
end
|
27
|
+
|
28
|
+
module OrderType
|
29
|
+
LIMIT = 'limit'
|
30
|
+
MARKET = 'market'
|
31
|
+
STOP_LIMIT = 'stopLimit'
|
32
|
+
STOP_MARKET = 'stopMarket'
|
33
|
+
TAKE_PROFIT_LIMIT = 'takeProfitLimit'
|
34
|
+
TAKE_PROFIT_MARKET = 'takeProfitMarket'
|
35
|
+
end
|
36
|
+
|
37
|
+
module TimeInForce
|
38
|
+
GTC = 'GTC' # Good till canceled
|
39
|
+
IOC = 'IOC' # Immediate or cancell
|
40
|
+
FOK = 'FOK' # Fill or kill
|
41
|
+
DAY = 'Day' # Good for the day
|
42
|
+
GTD = 'GDT' # Good till date
|
43
|
+
end
|
44
|
+
|
45
|
+
module IdentifyBy
|
46
|
+
USERNAME = 'username'
|
47
|
+
EMAIL = 'email'
|
48
|
+
end
|
49
|
+
|
50
|
+
module Offchain
|
51
|
+
NEVER = 'never'
|
52
|
+
OPTIONALLY = 'optionally'
|
53
|
+
REQUIRED = 'required'
|
54
|
+
end
|
55
|
+
|
56
|
+
module Account
|
57
|
+
SPOT = 'spot'
|
58
|
+
WALLET = 'wallet'
|
59
|
+
end
|
60
|
+
|
61
|
+
module TransactionType
|
62
|
+
DEPOSIT = 'DEPOSIT'
|
63
|
+
WITHDRAW = 'WITHDRAW'
|
64
|
+
TRANSFER = 'TRANSFER'
|
65
|
+
SAWAP = 'SAWAP'
|
66
|
+
end
|
67
|
+
|
68
|
+
module TransactionSubtype
|
69
|
+
UNCLASSIFIED = 'UNCLASSIFIED'
|
70
|
+
BLOCKCHAIN = 'BLOCKCHAIN'
|
71
|
+
AIRDROP = 'AIRDROP'
|
72
|
+
AFFILIATE = 'AFFILIATE'
|
73
|
+
STAKING = 'STAKING'
|
74
|
+
BUY_CRYPTO = 'BUY_CRYPTO'
|
75
|
+
OFFCHAIN = 'OFFCHAIN'
|
76
|
+
FIAT = 'FIAT'
|
77
|
+
SUB_ACCOUNT = 'SUB_ACCOUNT'
|
78
|
+
WALLET_TO_SPOT = 'WALLET_TO_SPOT'
|
79
|
+
SPOT_TO_WALLET = 'SPOT_TO_WALLET'
|
80
|
+
WALLET_TO_DERIVATIVES = 'WALLET_TO_DERIVATIVES'
|
81
|
+
DERIVATIVES_TO_WALLET = 'DERIVATIVES_TO_WALLET'
|
82
|
+
CHAIN_SWITCH_FROM = 'CHAIN_SWITCH_FROM'
|
83
|
+
CHAIN_SWITCH_TO = 'CHAIN_SWITCH_TO'
|
84
|
+
INSTANT_EXCHANGE = 'INSTANT_EXCHANGE'
|
85
|
+
end
|
86
|
+
|
87
|
+
module TransactionStatus
|
88
|
+
CREATED = 'CREATED'
|
89
|
+
PENDING = 'PENDING'
|
90
|
+
FAILED = 'FAILED'
|
91
|
+
SUCCESS = 'SUCCESS'
|
92
|
+
ROLLED_BACK = 'ROLLED_BACK'
|
93
|
+
end
|
94
|
+
|
95
|
+
module SortBy
|
96
|
+
CREATED_AT = 'created_at'
|
97
|
+
ID = 'id'
|
98
|
+
end
|
99
|
+
|
100
|
+
module Contingency
|
101
|
+
ALL_OR_NONE = 'allOrNone'
|
102
|
+
AON = 'allOrNone'
|
103
|
+
ONE_CANCEL_OTHER = 'oneCancelOther'
|
104
|
+
OCO = 'oneCancelOther'
|
105
|
+
ONE_TRIGGER_OTHER = 'oneTriggerOther'
|
106
|
+
OTO = 'oneTriggerOther'
|
107
|
+
ONE_TRIGGER_ONE_CANCEL_OTHER = 'oneTriggerOneCancelOther'
|
108
|
+
OTOCO = 'oneTriggerOneCancelOther'
|
109
|
+
end
|
110
|
+
|
111
|
+
module NotificationType
|
112
|
+
SNAPSHOT = 'snapshot'
|
113
|
+
UPDATE = 'update'
|
114
|
+
DATA = 'data'
|
115
|
+
COMMAND = 'command'
|
116
|
+
end
|
117
|
+
|
118
|
+
module SubscriptionMode
|
119
|
+
UPDATES = 'updates'
|
120
|
+
BATCHES = 'batches'
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'uri'
|
5
|
+
require 'json'
|
6
|
+
require 'base64'
|
7
|
+
require 'rest-client'
|
8
|
+
require 'date'
|
9
|
+
require_relative 'exceptions'
|
10
|
+
|
11
|
+
module Cryptomarket
|
12
|
+
# Builds a credential used by the cryptomarket server
|
13
|
+
class CredentialsFactory
|
14
|
+
def initialize(api_version:, api_key:, api_secret:, window: nil)
|
15
|
+
@api_version = api_version
|
16
|
+
@api_key = api_key
|
17
|
+
@api_secret = api_secret
|
18
|
+
@window = window
|
19
|
+
end
|
20
|
+
|
21
|
+
def get_credential(http_method, method, params)
|
22
|
+
timestamp = DateTime.now.strftime('%Q')
|
23
|
+
msg = build_credential_message(http_method, method, timestamp, params)
|
24
|
+
digest = OpenSSL::Digest.new 'sha256'
|
25
|
+
signature = OpenSSL::HMAC.hexdigest digest, @api_secret, msg
|
26
|
+
signed = "#{@api_key}:#{signature}:#{timestamp}"
|
27
|
+
signed += ":#{@window}" unless @window.nil?
|
28
|
+
encoded = Base64.encode64(signed).delete "\n"
|
29
|
+
"HS256 #{encoded}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def build_credential_message(http_method, method, timestamp, params)
|
33
|
+
msg = http_method + @api_version + method
|
34
|
+
msg += if http_method.upcase == 'POST'
|
35
|
+
params
|
36
|
+
else
|
37
|
+
not_post_params(http_method, params)
|
38
|
+
end
|
39
|
+
msg += timestamp
|
40
|
+
msg += @window unless @window.nil?
|
41
|
+
msg
|
42
|
+
end
|
43
|
+
|
44
|
+
def not_post_params(http_method, params)
|
45
|
+
msg = ''
|
46
|
+
if !params.nil? && params.keys.any?
|
47
|
+
msg += '?' if http_method.upcase == 'GET'
|
48
|
+
msg += URI.encode_www_form(params)
|
49
|
+
end
|
50
|
+
msg
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -1,24 +1,23 @@
|
|
1
|
-
|
2
|
-
class SDKException < ::StandardError
|
3
|
-
end
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
@message = hash['message']
|
9
|
-
@description = hash['description']
|
10
|
-
end
|
3
|
+
module Cryptomarket
|
4
|
+
class SDKException < ::StandardError
|
5
|
+
end
|
11
6
|
|
12
|
-
|
13
|
-
|
14
|
-
|
7
|
+
# Exception representing an error from the server
|
8
|
+
class APIException < SDKException
|
9
|
+
def initialize(hash)
|
10
|
+
@code = hash['code']
|
11
|
+
raw_message = hash['message']
|
12
|
+
@description = hash.key?('description') ? hash['description'] : ''
|
13
|
+
@message = "#{self.class.name} (code=#{@code}): #{raw_message}. #{@description}"
|
14
|
+
super
|
15
|
+
end
|
15
16
|
|
16
|
-
|
17
|
-
return @message
|
18
|
-
end
|
17
|
+
attr_reader :code, :message, :description
|
19
18
|
|
20
|
-
|
21
|
-
|
22
|
-
end
|
19
|
+
def to_s
|
20
|
+
@message
|
23
21
|
end
|
24
|
-
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'uri'
|
5
|
+
require 'json'
|
6
|
+
require 'base64'
|
7
|
+
require 'rest-client'
|
8
|
+
require 'date'
|
9
|
+
require_relative 'exceptions'
|
10
|
+
require_relative 'credentials_factory'
|
11
|
+
|
12
|
+
def post?(method)
|
13
|
+
method.upcase == 'POST'
|
14
|
+
end
|
15
|
+
|
16
|
+
def get?(method)
|
17
|
+
method.upcase == 'GET'
|
18
|
+
end
|
19
|
+
|
20
|
+
def put?(method)
|
21
|
+
method.upcase == 'PUT'
|
22
|
+
end
|
23
|
+
|
24
|
+
def patch?(method)
|
25
|
+
method.upcase == 'PATCH'
|
26
|
+
end
|
27
|
+
|
28
|
+
module Cryptomarket
|
29
|
+
# Manager of http requests to the cryptomarket server
|
30
|
+
class HttpManager
|
31
|
+
@@API_URL = 'https://api.exchange.cryptomkt.com' # rubocop:disable Naming/VariableName,Style/ClassVars
|
32
|
+
@@API_VERSION = '/api/3/' # rubocop:disable Naming/VariableName,Style/ClassVars
|
33
|
+
|
34
|
+
def initialize(api_key:, api_secret:, window: nil)
|
35
|
+
@credential_factory = Cryptomarket::CredentialsFactory.new(
|
36
|
+
api_version: @@API_VERSION, api_key: api_key, api_secret: api_secret, window: window
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
def make_request(method:, endpoint:, params: nil, public: false)
|
41
|
+
uri = URI(@@API_URL + @@API_VERSION + endpoint)
|
42
|
+
payload = build_payload(params)
|
43
|
+
headers = build_headers(method, endpoint, payload, public)
|
44
|
+
if ((method.upcase == 'GET') || (method.upcase == 'PUT')) && !payload.nil?
|
45
|
+
uri.query = URI.encode_www_form payload
|
46
|
+
payload = nil
|
47
|
+
end
|
48
|
+
do_request(method, uri, payload, headers)
|
49
|
+
end
|
50
|
+
|
51
|
+
def make_post_request(method:, endpoint:, params: nil)
|
52
|
+
uri = URI(@@API_URL + @@API_VERSION + endpoint)
|
53
|
+
payload = build_payload(params)
|
54
|
+
do_request(method, uri, payload, build_post_headers(endpoint, payload))
|
55
|
+
end
|
56
|
+
|
57
|
+
def build_headers(method, endpoint, params, public)
|
58
|
+
return {} if public
|
59
|
+
|
60
|
+
{ 'Authorization' => @credential_factory.get_credential(method.upcase, endpoint, params) }
|
61
|
+
end
|
62
|
+
|
63
|
+
def build_payload(params)
|
64
|
+
return nil if params.nil?
|
65
|
+
|
66
|
+
payload = params.compact
|
67
|
+
payload = Hash[payload.sort_by { |key, _val| key.to_s }] if payload.is_a?(Hash)
|
68
|
+
payload
|
69
|
+
end
|
70
|
+
|
71
|
+
def do_request(method, uri, payload, headers)
|
72
|
+
args = { method: method.downcase.to_sym, url: uri.to_s, headers: headers }
|
73
|
+
if post?(method) || patch?(method)
|
74
|
+
args[:payload] = post?(method) ? payload.to_json : payload
|
75
|
+
end
|
76
|
+
response = RestClient::Request.execute(**args)
|
77
|
+
handle_response(response)
|
78
|
+
rescue RestClient::ExceptionWithResponse => e
|
79
|
+
handle_response(e.response)
|
80
|
+
end
|
81
|
+
|
82
|
+
def build_post_headers(endpoint, params)
|
83
|
+
{ 'Content-Type' => 'application/json',
|
84
|
+
'Authorization' => @credential_factory.get_credential('POST'.upcase, endpoint, params.to_json) }
|
85
|
+
end
|
86
|
+
|
87
|
+
def handle_response(response)
|
88
|
+
result = response.body
|
89
|
+
parsed_result = JSON.parse result
|
90
|
+
if (response.code != 200) && !parsed_result['error'].nil?
|
91
|
+
error = parsed_result['error']
|
92
|
+
exception = Cryptomarket::APIException.new error
|
93
|
+
raise exception
|
94
|
+
end
|
95
|
+
parsed_result
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'securerandom'
|
4
|
+
require_relative 'client_base'
|
5
|
+
|
6
|
+
module Cryptomarket
|
7
|
+
module Websocket
|
8
|
+
# A websocket client that authenticates at the moment of connection
|
9
|
+
class AuthClient < ClientBase
|
10
|
+
# Creates a new client
|
11
|
+
def initialize(url:, api_key:, api_secret:, subscription_keys:, window: nil)
|
12
|
+
@api_key = api_key
|
13
|
+
@api_secret = api_secret
|
14
|
+
@window = window
|
15
|
+
super url: url, subscription_keys: subscription_keys
|
16
|
+
@authed = false
|
17
|
+
end
|
18
|
+
|
19
|
+
def connected?
|
20
|
+
(super.connected? and @authed)
|
21
|
+
end
|
22
|
+
|
23
|
+
# connects via websocket to the exchange and authenticates it.
|
24
|
+
def connect
|
25
|
+
super
|
26
|
+
authenticate(proc { |err, _result|
|
27
|
+
raise err unless err.nil?
|
28
|
+
|
29
|
+
@authed = true
|
30
|
+
})
|
31
|
+
wait_authed
|
32
|
+
end
|
33
|
+
|
34
|
+
def wait_authed
|
35
|
+
current_try = 0
|
36
|
+
max_tries = 60
|
37
|
+
while !@authed && (current_try < max_tries)
|
38
|
+
current_try += 1
|
39
|
+
sleep(1)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Authenticates the websocket
|
44
|
+
#
|
45
|
+
# https://api.exchange.cryptomkt.com/#socket-session-authentication
|
46
|
+
#
|
47
|
+
# +Proc+ +callback+:: Optional. A +Proc+ to call with the result data. It takes two arguments, err and result.
|
48
|
+
# err is None for successful calls, result is None for calls with error: Proc.new {|err, result| ...}
|
49
|
+
|
50
|
+
def authenticate(callback = nil)
|
51
|
+
timestamp = Time.now.to_i * 1000
|
52
|
+
digest = OpenSSL::Digest.new 'sha256'
|
53
|
+
message = timestamp.to_s
|
54
|
+
message += @window.to_s unless @window.nil?
|
55
|
+
signature = OpenSSL::HMAC.hexdigest digest, @api_secret, message.to_s
|
56
|
+
params = build_auth_payload timestamp, signature
|
57
|
+
request('login', callback, params)
|
58
|
+
end
|
59
|
+
|
60
|
+
def build_auth_payload(timestamp, signature)
|
61
|
+
params = {
|
62
|
+
'type' => 'HS256',
|
63
|
+
'api_key' => @api_key,
|
64
|
+
'timestamp' => timestamp,
|
65
|
+
'signature' => signature
|
66
|
+
}
|
67
|
+
params['window'] = @window unless @window.nil?
|
68
|
+
params
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'reusable_callback'
|
4
|
+
|
5
|
+
module Cryptomarket
|
6
|
+
module Websocket
|
7
|
+
# A cache store for callbacks. uses reusable callbacks, so it cans use a callback for more than one time.
|
8
|
+
# Each callback stored
|
9
|
+
class CallbackCache
|
10
|
+
def initialize
|
11
|
+
@reusable_callbacks = {}
|
12
|
+
@subscription_callbacks = {}
|
13
|
+
@next_id = 1
|
14
|
+
end
|
15
|
+
|
16
|
+
def _get_next_id
|
17
|
+
next_id = @next_id
|
18
|
+
@next_id += 1
|
19
|
+
@next_id = 1 if @next_id.negative?
|
20
|
+
next_id
|
21
|
+
end
|
22
|
+
|
23
|
+
def store_callback(callback, call_count = 1)
|
24
|
+
id = _get_next_id
|
25
|
+
@reusable_callbacks[id] = ReusableCallback.new(callback, call_count)
|
26
|
+
id
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_callback(id)
|
30
|
+
return nil unless @reusable_callbacks.key? id
|
31
|
+
|
32
|
+
callback, done_using = @reusable_callbacks[id].get_callback
|
33
|
+
@reusable_callbacks.delete(id) if done_using
|
34
|
+
callback
|
35
|
+
end
|
36
|
+
|
37
|
+
def store_subscription_callback(key, callback)
|
38
|
+
@subscription_callbacks[key] = callback
|
39
|
+
end
|
40
|
+
|
41
|
+
def get_subscription_callback(key)
|
42
|
+
return nil unless @subscription_callbacks.key? key
|
43
|
+
|
44
|
+
@subscription_callbacks[key]
|
45
|
+
end
|
46
|
+
|
47
|
+
def delete_subscription_callback(key)
|
48
|
+
return unless @subscription_callbacks.key? key
|
49
|
+
|
50
|
+
@subscription_callbacks.delete(key)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'callback_cache'
|
4
|
+
require_relative 'ws_manager'
|
5
|
+
require_relative '../exceptions'
|
6
|
+
|
7
|
+
module Cryptomarket
|
8
|
+
module Websocket
|
9
|
+
# websockt client able to handle requests and subscriptions
|
10
|
+
class ClientBase
|
11
|
+
def initialize(url:, subscription_keys:, on_connect: -> {}, on_error: ->(error) {}, on_close: -> {})
|
12
|
+
@subscription_keys = subscription_keys
|
13
|
+
@callback_cache = CallbackCache.new
|
14
|
+
@ws_manager = WSManager.new self, url: url
|
15
|
+
@on_connect = on_connect
|
16
|
+
@on_error = on_error
|
17
|
+
@on_close = on_close
|
18
|
+
end
|
19
|
+
|
20
|
+
def connected?
|
21
|
+
@ws_manager.connected?
|
22
|
+
end
|
23
|
+
|
24
|
+
# connects via websocket to the exchange, it blocks until the connection is stablished
|
25
|
+
def connect
|
26
|
+
@ws_manager.connect
|
27
|
+
sleep(1) until @ws_manager.connected?
|
28
|
+
end
|
29
|
+
|
30
|
+
def on_open
|
31
|
+
@on_connect.call
|
32
|
+
end
|
33
|
+
|
34
|
+
def on_connect=(callback = nil, &block)
|
35
|
+
callback ||= block
|
36
|
+
@on_connect = callback
|
37
|
+
end
|
38
|
+
|
39
|
+
def on_connect
|
40
|
+
@on_connect.call
|
41
|
+
end
|
42
|
+
|
43
|
+
def on_error=(callback = nil, &block)
|
44
|
+
callback ||= block
|
45
|
+
@on_error = callback
|
46
|
+
end
|
47
|
+
|
48
|
+
def on_error(error)
|
49
|
+
@on_error.call(error)
|
50
|
+
end
|
51
|
+
|
52
|
+
def on_close=(callback = nil, &block)
|
53
|
+
callback ||= block
|
54
|
+
@on_close = callback
|
55
|
+
end
|
56
|
+
|
57
|
+
def on_close
|
58
|
+
@on_close.call
|
59
|
+
end
|
60
|
+
|
61
|
+
def close
|
62
|
+
@ws_manager.close
|
63
|
+
end
|
64
|
+
|
65
|
+
def send_subscription(method, callback, params, result_callback)
|
66
|
+
@callback_cache.store_subscription_callback(@subscription_keys[method][0], callback)
|
67
|
+
store_callback_and_send(method, params, result_callback)
|
68
|
+
end
|
69
|
+
|
70
|
+
def send_unsubscription(method, callback, params)
|
71
|
+
@callback_cache.delete_subscription_callback(@subscription_keys[method][0])
|
72
|
+
store_callback_and_send(method, params, callback)
|
73
|
+
end
|
74
|
+
|
75
|
+
def request(method, callback, params = {}, call_count = 1)
|
76
|
+
store_callback_and_send(method, params, callback, call_count)
|
77
|
+
end
|
78
|
+
|
79
|
+
def store_callback_and_send(method, params, callback_to_store = nil, call_count = 1)
|
80
|
+
params = params.compact unless params.nil?
|
81
|
+
payload = { 'method' => method, 'params' => params }
|
82
|
+
unless callback_to_store.nil?
|
83
|
+
id = @callback_cache.store_callback(callback_to_store, call_count)
|
84
|
+
payload['id'] = id
|
85
|
+
end
|
86
|
+
@ws_manager.send(payload)
|
87
|
+
end
|
88
|
+
|
89
|
+
def handle(message)
|
90
|
+
if message.key? 'id'
|
91
|
+
handle_response(message)
|
92
|
+
elsif message.key? 'method'
|
93
|
+
handle_notification(message)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def handle_notification(notification)
|
98
|
+
method = notification['method']
|
99
|
+
method_data = @subscription_keys[method]
|
100
|
+
notification_type = method_data[1]
|
101
|
+
callback = @callback_cache.get_subscription_callback(method_data[0])
|
102
|
+
return if callback.nil?
|
103
|
+
|
104
|
+
callback.call(notification['params'], notification_type)
|
105
|
+
end
|
106
|
+
|
107
|
+
def get_callback_for_response(response)
|
108
|
+
id = response['id']
|
109
|
+
return if id.nil?
|
110
|
+
|
111
|
+
@callback_cache.get_callback(id)
|
112
|
+
end
|
113
|
+
|
114
|
+
def handle_response(response)
|
115
|
+
callback = get_callback_for_response(response)
|
116
|
+
return if callback.nil?
|
117
|
+
|
118
|
+
if response.key? 'error'
|
119
|
+
callback.call(Cryptomarket::APIException.new(response['error']), nil)
|
120
|
+
nil
|
121
|
+
end
|
122
|
+
handle_good_response(response, callback)
|
123
|
+
end
|
124
|
+
|
125
|
+
def handle_good_response(response, callback)
|
126
|
+
result = response['result']
|
127
|
+
if result.is_a?(Hash) && result.key?('data')
|
128
|
+
callback.call(nil, result['data'])
|
129
|
+
else
|
130
|
+
callback.call(nil, result)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|