kaesen 0.1.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0981851f6c0c3632b9b25e0228646cd22da6f4dd
4
+ data.tar.gz: 3169b9611d6f37c1e963b1d1973338395b57aad3
5
+ SHA512:
6
+ metadata.gz: 6a1251de775dd42b64ea9914ea40a39aaad252a5bffc0fed0f26ab4c7ec8d213b597510281d0ffbb2f4846081befe8b517b4da645e6d2456383d7df71ef8a6bf
7
+ data.tar.gz: 5f1d81cb4cbd759c4a5ac89a8d62e6ad3d5bc2f5ca7865040401c5598ca395fbf9dbbd1f28c7f1640d2714055eb3b2f06fe6e54c81479423f72f082129d9000b
@@ -0,0 +1,15 @@
1
+ # bitFlyer Lightning
2
+ BITFLYER_KEY=''
3
+ BITFLYER_SECRET=''
4
+
5
+ # btcbox
6
+ BTCBOX_KEY=''
7
+ BTCBOX_SECRET=''
8
+
9
+ # Coincheck
10
+ COINCHECK_KEY=''
11
+ COINCHECK_SECRET=''
12
+
13
+ # zaif
14
+ ZAIF_KEY=''
15
+ ZAIF_SECRET=''
@@ -0,0 +1,44 @@
1
+ ### https://raw.github.com/github/gitignore/def395f811edd4b895690250abadb15ec3a6fd75/ruby.gitignore
2
+
3
+ *.gem
4
+ *.rbc
5
+ /.config
6
+ /coverage/
7
+ /InstalledFiles
8
+ /pkg/
9
+ /spec/reports/
10
+ /spec/examples.txt
11
+ /test/tmp/
12
+ /test/version_tmp/
13
+ /tmp/
14
+
15
+ ## Specific to RubyMotion:
16
+ .dat*
17
+ .repl_history
18
+ build/
19
+
20
+ ## Documentation cache and generated files:
21
+ /.yardoc/
22
+ /_yardoc/
23
+ /doc/
24
+ /rdoc/
25
+
26
+ ## Environment normalization:
27
+ /.bundle/
28
+ /vendor/bundle
29
+ /lib/bundler/man/
30
+
31
+ # for a library or gem, you might want to ignore these files since the code is
32
+ # intended to run in multiple environments; otherwise, check them in:
33
+ # Gemfile.lock
34
+ # .ruby-version
35
+ # .ruby-gemset
36
+
37
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
38
+ .rvmrc
39
+
40
+ # dotenv gem file that set the enviroment values
41
+ .env
42
+
43
+ .rbenv-gemsets
44
+
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.0
4
+ before_install: gem install bundler -v 1.11.2
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at nakashimaorz@gmail.com. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ ruby '>=2.2.0'
4
+
5
+ gemspec
@@ -0,0 +1,37 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ kaesen (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.2.5)
10
+ dotenv (2.1.0)
11
+ rake (10.5.0)
12
+ rspec (3.4.0)
13
+ rspec-core (~> 3.4.0)
14
+ rspec-expectations (~> 3.4.0)
15
+ rspec-mocks (~> 3.4.0)
16
+ rspec-core (3.4.3)
17
+ rspec-support (~> 3.4.0)
18
+ rspec-expectations (3.4.0)
19
+ diff-lcs (>= 1.2.0, < 2.0)
20
+ rspec-support (~> 3.4.0)
21
+ rspec-mocks (3.4.1)
22
+ diff-lcs (>= 1.2.0, < 2.0)
23
+ rspec-support (~> 3.4.0)
24
+ rspec-support (3.4.1)
25
+
26
+ PLATFORMS
27
+ ruby
28
+
29
+ DEPENDENCIES
30
+ bundler (~> 1.11)
31
+ dotenv
32
+ kaesen!
33
+ rake (~> 10.0)
34
+ rspec (~> 3.0)
35
+
36
+ BUNDLED WITH
37
+ 1.11.2
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 him0
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,51 @@
1
+ # Kaesen (beta version)
2
+
3
+ A module of the united wrapper for exchanging Japanese yen and Bitcoin and collecting market information of any exchange markets that provide ordinary customers with API access.
4
+
5
+ ## Installation
6
+
7
+ For each of your applications, add the following line to the application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'kaesen', github: "him0/kaesen"
11
+ ```
12
+
13
+ Then, run bundler:
14
+
15
+ $ bundle install
16
+
17
+ ## Usage
18
+
19
+ ```
20
+ require 'kaesen'
21
+ b = Kaesen::Bitflyer.new()
22
+ b.ticker
23
+ ```
24
+
25
+ ### Currently supported exchange markets to trade:
26
+
27
+ + bitFlyer
28
+ + BtcBox
29
+ + coincheck
30
+ + Zaif
31
+
32
+ ### Currently supported exchange markets to get market information:
33
+
34
+ + bitFlyer Lightning
35
+ + bitFlyer FX
36
+ + BtcBox
37
+ + coincheck
38
+ + Kraken
39
+ + LakeBTC
40
+ + MonetaGo
41
+ + Quoine
42
+ + Zaif
43
+
44
+ ## Contributing
45
+
46
+ Bug reports and pull requests are welcome on GitHub at https://github.com/him0/kaesen. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
47
+
48
+
49
+ ## License
50
+
51
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "kaesen"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'kaesen/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "kaesen"
8
+ spec.version = Kaesen::VERSION
9
+ spec.authors = ["him0"]
10
+ spec.email = ["nakashimaorz@gmail.com"]
11
+
12
+ spec.summary = %q{A module of the united wrapper for exchanging Japanese yen and Bitcoin and collecting market information of any exchange markets that provide ordinary customers with API access.}
13
+ spec.description = %q{This is a module that exchanging Japanese yen and Bitcoin and collecting market information.}
14
+ spec.homepage = "http://github.com/him0/kaesen"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
18
+ # delete this section to allow pushing this gem to any host.
19
+ # if spec.respond_to?(:metadata)
20
+ # spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
21
+ # else
22
+ # raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
23
+ # end
24
+
25
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_development_dependency "bundler", "~> 1.11"
31
+ spec.add_development_dependency "rake", "~> 10.0"
32
+ spec.add_development_dependency "rspec", "~> 3.0"
33
+ spec.add_development_dependency "dotenv"
34
+ end
@@ -0,0 +1,17 @@
1
+ require "kaesen/version"
2
+ require "kaesen/bitflyer"
3
+ require "kaesen/bitflyerfx"
4
+ require "kaesen/btcbox"
5
+ require "kaesen/coincheck"
6
+ require "kaesen/zaif"
7
+ require "kaesen/monetago"
8
+ require "kaesen/kraken"
9
+ require "kaesen/quoine"
10
+ require "kaesen/lakebtc"
11
+ require "kaesen/client"
12
+
13
+ # A module of the united wrapper for exchanging Japanese yen and Bitcoin and
14
+ # collecting market information of any exchange markets that provide ordinary
15
+ # customers with API access.
16
+ module Kaesen
17
+ end
@@ -0,0 +1,390 @@
1
+ require_relative 'market.rb'
2
+ require 'net/http'
3
+ require 'openssl'
4
+ require 'json'
5
+ require 'date'
6
+ require 'bigdecimal'
7
+
8
+ module Kaesen
9
+ # BitFlyer Wrapper Class
10
+ # https://coincheck.jp/documents/exchange/api?locale=ja
11
+ ## API制限
12
+ ## . Private API は 1 分間に約 200 回を上限とします。
13
+ ## . IP アドレスごとに 1 分間に約 500 回を上限とします。
14
+
15
+ class Bitflyer < Market
16
+ @@nonce = 0
17
+
18
+ def initialize()
19
+ super()
20
+ @name = "BitFlyer"
21
+ @api_key = ENV["BITFLYER_KEY"]
22
+ @api_secret = ENV["BITFLYER_SECRET"]
23
+ @url_public = "https://api.bitflyer.jp/v1"
24
+ @url_private = @url_public
25
+ @product_code = "BTC_JPY"
26
+ end
27
+
28
+ #############################################################
29
+ # API for public information
30
+ #############################################################
31
+
32
+ # Get ticker information.
33
+ # @return [hash] ticker
34
+ # ask: [BigDecimal] 最良売気配値
35
+ # bid: [BigDecimal] 最良買気配値
36
+ # last: [BigDecimal] 最近値(?用語要チェック), last price
37
+ # high: [BigDecimal] 高値
38
+ # low: [BigDecimal] 安値
39
+ # volume: [BigDecimal] 取引量
40
+ # ltimestamp: [int] ローカルタイムスタンプ
41
+ # timestamp: [int] タイムスタンプ
42
+ def ticker
43
+ h = get_ssl(@url_public + "/getticker?product_code=#{@product_code}")
44
+ {
45
+ "ask" => BigDecimal.new(h["best_ask"].to_s),
46
+ "bid" => BigDecimal.new(h["best_bid"].to_s),
47
+ "last" => BigDecimal.new(h["ltp"].to_s),
48
+ # "high" is not supplied.
49
+ # "low" is not supplied.
50
+ "volume" => BigDecimal.new(h["volume"].to_s),
51
+ "ltimestamp" => Time.now.to_i,
52
+ "timestamp" => DateTime.parse(h["timestamp"]).to_time.to_i,
53
+ }
54
+ end
55
+
56
+ # Get order book.
57
+ # @abstract
58
+ # @return [hash] array of market depth
59
+ # asks: [Array] 売りオーダー
60
+ # price : [BigDecimal]
61
+ # size : [BigDecimal]
62
+ # bids: [Array] 買いオーダー
63
+ # price : [BigDecimal]
64
+ # size : [BigDecimal]
65
+ # ltimestamp: [int] ローカルタイムスタンプ
66
+ def depth
67
+ h = get_ssl(@url_public + "/getboard?product_code=#{@product_code}")
68
+ {
69
+ "asks" => h["asks"].map{|x| [BigDecimal.new(x["price"].to_s), BigDecimal.new(x["size"].to_s)]},
70
+ "bids" => h["bids"].map{|x| [BigDecimal.new(x["price"].to_s), BigDecimal.new(x["size"].to_s)]},
71
+ "ltimestamp" => Time.now.to_i,
72
+ }
73
+ end
74
+
75
+ #############################################################
76
+ # API for private user data and trading
77
+ #############################################################
78
+
79
+ # Get account balance.
80
+ # @abstract
81
+ # @return [hash] account_balance_hash
82
+ # jpy: [hash]
83
+ # amount: [BigDecimal] 総日本円
84
+ # available: [BigDecimal] 取引可能な日本円
85
+ # btc [hash]
86
+ # amount: [BigDecimal] 総BTC
87
+ # available: [BigDecimal] 取引可能なBTC
88
+ # ltimestamp: [int] ローカルタイムスタンプ
89
+ def balance
90
+ have_key?
91
+ h = get_ssl_with_sign(@url_private + "/me/getbalance")
92
+ {
93
+ "jpy" => {
94
+ "amount" => BigDecimal.new(h[0]["amount"].to_s),
95
+ "available" => BigDecimal.new(h[0]["available"].to_s),
96
+ },
97
+ "btc" => {
98
+ "amount" => BigDecimal.new(h[1]["amount"].to_s),
99
+ "available" => BigDecimal.new(h[1]["available"].to_s),
100
+ },
101
+ "ltimestamp" => Time.now.to_i,
102
+ }
103
+ end
104
+
105
+ # Get open orders.
106
+ # @abstract
107
+ # @return [Array] open_orders_array
108
+ # @return [hash] history_order_hash
109
+ # success: [bool]
110
+ # id: [String] order id in the market
111
+ # rate: [BigDecimal]
112
+ # amount: [BigDecimal]
113
+ # order_type: [String] "sell" or "buy"
114
+ # order_status: [String] "active", "completed" or "canceled"
115
+ # ltimestamp: [int] Local Timestamp
116
+ def opens
117
+ have_key?
118
+ address = @url_private + "/me/getchildorders"
119
+ query = {
120
+ "child_order_state" => "ACTIVE",
121
+ }
122
+ address += "?" + query.to_a.map{|x|"#{x[0]}=#{x[1]}" }.join("&")
123
+ body = {
124
+ "product_code" => @product_code,
125
+ }
126
+ a = get_ssl_with_sign(address, body)
127
+ a.map{|x|
128
+ {
129
+ "success" => "true",
130
+ "id" => x["id"],
131
+ "rate" => BigDecimal.new(x["average_price"].to_s),
132
+ "amount" => BigDecimal.new(x["size"].to_s),
133
+ "order_type" => x["side"].downcase,
134
+ }
135
+ }
136
+ end
137
+
138
+ # Buy the amount of Bitcoin at the rate.
139
+ # 指数注文 買い.
140
+ # @abstract
141
+ # @param [BigDecimal] rate
142
+ # @param [BigDecimal] amount minimal amount is 0.001 BTC
143
+ # @return [hash] history_order_hash
144
+ # success: [String] "true" or "false"
145
+ # id: [String] order id at the market
146
+ # rate: [BigDecimal]
147
+ # amount: [BigDecimal]
148
+ # order_type: [String] "sell" or "buy"
149
+ # ltimestamp: [int] ローカルタイムスタンプ
150
+ def buy(rate, amount=BigDecimal.new(0))
151
+ have_key?
152
+ address = @url_private + "/me/sendchildorder"
153
+ body = {
154
+ "product_code" => @product_code,
155
+ "child_order_type" => "LIMIT",
156
+ "side" => "BUY",
157
+ "price" => rate.to_i,
158
+ "size" => amount.to_f.round(4),
159
+ "minute_to_expire" => 525600,
160
+ "time_in_force" => "GTC",
161
+ }
162
+ h = post_ssl_with_sign(address, body)
163
+ {
164
+ "success" => "true",
165
+ "id" => h["child_order_acceptance_id"].to_s,
166
+ "rate" => BigDecimal.new(rate.to_s),
167
+ "amount" => BigDecimal.new(amount.to_s),
168
+ "order_type" => "buy",
169
+ "ltimestamp" => Time.now.to_i,
170
+ }
171
+ end
172
+
173
+ # Buy the amount of Bitcoin from the market.
174
+ # 成行注文 買い.
175
+ # @abstract
176
+ # @param [BigDecimal] amount
177
+ # @return [hash] history_order_hash
178
+ # success: [bool]
179
+ # id: [String] order id in the market
180
+ # rate: [BigDecimal]
181
+ # amount: [BigDecimal]
182
+ # order_type: [String] "sell" or "buy"
183
+ # ltimestamp: [int] Local Timestamp
184
+ def market_buy(amount=BigDecimal.new("0.0"))
185
+ have_key?
186
+ address = @url_private + "/me/sendchildorder"
187
+ body = {
188
+ "product_code" => @product_code,
189
+ "child_order_type" => "MARKET",
190
+ "side" => "BUY",
191
+ "size" => amount.to_f.round(4),
192
+ "minute_to_expire" => 525600,
193
+ "time_in_force" => "GTC",
194
+ }
195
+ h = post_ssl_with_sign(address, body)
196
+ {
197
+ "success" => "true",
198
+ "id" => h["child_order_acceptance_id"].to_s,
199
+ # "rate" is not supplied.
200
+ "amount" => BigDecimal.new(amount.to_s),
201
+ "order_type" => "buy",
202
+ "ltimestamp" => Time.now.to_i,
203
+ }
204
+ end
205
+
206
+ # Sell the amount of Bitcoin at the rate.
207
+ # 指数注文 売り.
208
+ # Abstract Method.
209
+ # @param [BigDecimal] rate
210
+ # @param [BigDecimal] amount
211
+ # @return [hash] history_order_hash
212
+ # success: [String] "true" or "false"
213
+ # id: [String] order id at the market
214
+ # rate: [BigDecimal]
215
+ # amount: [BigDecimal]
216
+ # order_type: [String] "sell" or "buy"
217
+ # ltimestamp: [int] ローカルタイムスタンプ
218
+ def sell(rate, amount=BigDecimal.new(0))
219
+ have_key?
220
+ address = @url_private + "/me/sendchildorder"
221
+ body = {
222
+ "product_code" => @product_code,
223
+ "child_order_type" => "LIMIT",
224
+ "side" => "SELL",
225
+ "price" => rate.to_i,
226
+ "size" => amount.to_f.round(4),
227
+ "minute_to_expire" => 525600,
228
+ "time_in_force" => "GTC",
229
+ }
230
+ h = post_ssl_with_sign(address, body)
231
+ {
232
+ "success" => "true",
233
+ "id" => h["child_order_acceptance_id"].to_s,
234
+ "rate" => BigDecimal.new(rate.to_s),
235
+ "amount" => BigDecimal.new(amount.to_s),
236
+ "order_type" => "sell",
237
+ "ltimestamp" => Time.now.to_i,
238
+ }
239
+ end
240
+
241
+ # Sell the amount of Bitcoin to the market.
242
+ # 成行注文 売り.
243
+ # @abstract
244
+ # @param [BigDecimal] amount
245
+ # @return [hash] history_order_hash
246
+ # success: [bool]
247
+ # id: [String] order id in the market
248
+ # rate: [BigDecimal]
249
+ # amount: [BigDecimal]
250
+ # order_type: [String] "sell" or "buy"
251
+ # ltimestamp: [int] Local Timestamp
252
+ def market_sell(amount=BigDecimal.new("0.0"))
253
+ have_key?
254
+ address = @url_private + "/me/sendchildorder"
255
+ body = {
256
+ "product_code" => @product_code,
257
+ "child_order_type" => "MARKET",
258
+ "side" => "SELL",
259
+ "size" => amount.to_f.round(4),
260
+ "minute_to_expire" => 525600,
261
+ "time_in_force" => "GTC",
262
+ }
263
+ h = post_ssl_with_sign(address, body)
264
+ {
265
+ "success" => "true",
266
+ "id" => h["child_order_acceptance_id"].to_s,
267
+ # "rate" is not supplied.
268
+ "amount" => BigDecimal.new(amount.to_s),
269
+ "order_type" => "sell",
270
+ "ltimestamp" => Time.now.to_i,
271
+ }
272
+ end
273
+
274
+ private
275
+
276
+ def initialize_https(uri)
277
+ https = Net::HTTP.new(uri.host, uri.port)
278
+ https.use_ssl = true
279
+ https.open_timeout = 5
280
+ https.read_timeout = 15
281
+ https.verify_mode = OpenSSL::SSL::VERIFY_PEER
282
+ https.verify_depth = 5
283
+ https
284
+ end
285
+
286
+ # Connect to address via https, and return json response.
287
+ def get_ssl(address)
288
+ uri = URI.parse(address)
289
+ begin
290
+ https = initialize_https(uri)
291
+ https.start {|w|
292
+ response = w.get(uri.request_uri)
293
+ case response
294
+ when Net::HTTPSuccess
295
+ json = JSON.parse(response.body)
296
+ raise JSONException, response.body if json == nil
297
+ return json
298
+ else
299
+ raise ConnectionFailedException, "Failed to connect to #{@name}."
300
+ end
301
+ }
302
+ rescue
303
+ raise
304
+ end
305
+ end
306
+
307
+ def get_nonce
308
+ pre_nonce = @@nonce
309
+ next_nonce = (1000*Time.now.to_f).to_i
310
+
311
+ if next_nonce <= pre_nonce
312
+ @@nonce = pre_nonce + 1
313
+ else
314
+ @@nonce = next_nonce
315
+ end
316
+
317
+ return @@nonce
318
+ end
319
+
320
+ def get_sign(uri, method, nonce, body)
321
+ secret = @api_secret
322
+ text = nonce.to_s + method + uri.request_uri
323
+ text += body.to_json if body != ""
324
+
325
+ OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha256"), secret, text)
326
+ end
327
+
328
+ def get_headers(uri, method, nonce, body="")
329
+ {
330
+ "ACCESS-KEY" => @api_key,
331
+ "ACCESS-TIMESTAMP" => nonce.to_s,
332
+ "ACCESS-SIGN" => get_sign(uri, method, nonce, body),
333
+ "Content-Type" => "application/json",
334
+ }
335
+ end
336
+
337
+ def get_ssl_with_sign(address, body="")
338
+ uri = URI.parse(address)
339
+ nonce = get_nonce
340
+ headers = get_headers(uri, "GET", nonce, body)
341
+
342
+ begin
343
+ req = Net::HTTP::Get.new(uri, headers)
344
+ req.body = body.to_json if body != ""
345
+
346
+ https = https = initialize_https(uri)
347
+ https.start {|w|
348
+ response = w.request(req)
349
+ case response
350
+ when Net::HTTPSuccess
351
+ json = JSON.parse(response.body)
352
+ raise JSONException, response.body if json == nil
353
+ return json
354
+ else
355
+ raise ConnectionFailedException, "Failed to connect to #{@name}: " + response.value
356
+ end
357
+ }
358
+ rescue
359
+ raise
360
+ end
361
+ end
362
+
363
+ def post_ssl_with_sign(address, body="")
364
+ uri = URI.parse(address)
365
+ nonce = get_nonce
366
+ headers = get_headers(uri, "POST", nonce, body)
367
+
368
+ begin
369
+ req = Net::HTTP::Post.new(uri, headers)
370
+ req.body = body.to_json if body != ""
371
+
372
+ https = initialize_https(uri)
373
+ https.start {|w|
374
+ response = w.request(req)
375
+ case response
376
+ when Net::HTTPSuccess
377
+ json = JSON.parse(response.body)
378
+ raise JSONException, response.body if json == nil
379
+ return json
380
+ else
381
+ raise ConnectionFailedException, "Failed to connect to #{@name}: " + response.value
382
+ end
383
+ }
384
+ rescue
385
+ raise
386
+ end
387
+ end
388
+
389
+ end
390
+ end