cryptomarket-sdk 1.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|