peatio-jruby 2.6.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.drone.yml +29 -0
- data/.gitignore +16 -0
- data/.rspec +3 -0
- data/.rubocop.yml +148 -0
- data/.simplecov +17 -0
- data/.tool-versions +1 -0
- data/.travis.yml +18 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +198 -0
- data/README.md +47 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/peatio +12 -0
- data/bin/setup +8 -0
- data/lib/peatio.rb +52 -0
- data/lib/peatio/adapter_registry.rb +25 -0
- data/lib/peatio/auth/error.rb +18 -0
- data/lib/peatio/auth/jwt_authenticator.rb +127 -0
- data/lib/peatio/block.rb +29 -0
- data/lib/peatio/blockchain/abstract.rb +161 -0
- data/lib/peatio/blockchain/error.rb +37 -0
- data/lib/peatio/blockchain/registry.rb +16 -0
- data/lib/peatio/command/base.rb +11 -0
- data/lib/peatio/command/db.rb +20 -0
- data/lib/peatio/command/inject.rb +13 -0
- data/lib/peatio/command/root.rb +14 -0
- data/lib/peatio/command/security.rb +29 -0
- data/lib/peatio/command/service.rb +40 -0
- data/lib/peatio/error.rb +18 -0
- data/lib/peatio/executor.rb +64 -0
- data/lib/peatio/injectors/peatio_events.rb +240 -0
- data/lib/peatio/logger.rb +39 -0
- data/lib/peatio/metrics/server.rb +15 -0
- data/lib/peatio/mq/client.rb +51 -0
- data/lib/peatio/ranger/connection.rb +117 -0
- data/lib/peatio/ranger/events.rb +11 -0
- data/lib/peatio/ranger/router.rb +234 -0
- data/lib/peatio/ranger/web_socket.rb +68 -0
- data/lib/peatio/security/key_generator.rb +26 -0
- data/lib/peatio/sql/client.rb +19 -0
- data/lib/peatio/sql/schema.rb +72 -0
- data/lib/peatio/transaction.rb +122 -0
- data/lib/peatio/upstream/base.rb +116 -0
- data/lib/peatio/upstream/registry.rb +14 -0
- data/lib/peatio/version.rb +3 -0
- data/lib/peatio/wallet/abstract.rb +189 -0
- data/lib/peatio/wallet/error.rb +37 -0
- data/lib/peatio/wallet/registry.rb +16 -0
- data/peatio.gemspec +59 -0
- metadata +480 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
module Peatio
|
2
|
+
module Blockchain
|
3
|
+
Error = Class.new(StandardError)
|
4
|
+
|
5
|
+
class ClientError < Error
|
6
|
+
|
7
|
+
attr_reader :wrapped_ex
|
8
|
+
|
9
|
+
def initialize(ex_or_string)
|
10
|
+
@wrapped_ex = nil
|
11
|
+
|
12
|
+
if ex_or_string.respond_to?(:backtrace)
|
13
|
+
super(ex_or_string.message)
|
14
|
+
@wrapped_exception = ex_or_string
|
15
|
+
else
|
16
|
+
super(ex_or_string.to_s)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class MissingSettingError < Error
|
22
|
+
def initialize(key)
|
23
|
+
super "#{key.capitalize} setting is missing"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class UnavailableAddressBalanceError < Error
|
28
|
+
def initialize(address)
|
29
|
+
@address = address
|
30
|
+
end
|
31
|
+
|
32
|
+
def message
|
33
|
+
"Unable to load #{@address} balance"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Peatio::Command::DB
|
2
|
+
class Create < Peatio::Command::Base
|
3
|
+
def execute
|
4
|
+
client = Peatio::Sql::Client.new
|
5
|
+
database_name = client.config.delete(:database)
|
6
|
+
Peatio::Sql::Schema.new(client.connect).create_database(database_name)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class Migrate < Peatio::Command::Base
|
11
|
+
def execute
|
12
|
+
Peatio::Sql::Schema.new(sql_client).create_tables
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Root < Peatio::Command::Base
|
17
|
+
subcommand "create", "Create database", Peatio::Command::DB::Create
|
18
|
+
subcommand "migrate", "Create tables", Peatio::Command::DB::Migrate
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Peatio::Command
|
2
|
+
class Inject < Peatio::Command::Base
|
3
|
+
class PeatioEvents < Peatio::Command::Base
|
4
|
+
option ["-e", "--exchange"], "NAME", "exchange name to inject messages to", default: "peatio.events.ranger"
|
5
|
+
def execute
|
6
|
+
Peatio::Logger.logger.level = :debug
|
7
|
+
Peatio::Injectors::PeatioEvents.new.run!(exchange)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
subcommand "peatio_events", "Inject peatio events in mq", PeatioEvents
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require "peatio/command/base"
|
2
|
+
require "peatio/command/service"
|
3
|
+
require "peatio/command/db"
|
4
|
+
require "peatio/command/inject"
|
5
|
+
require "peatio/command/security"
|
6
|
+
|
7
|
+
module Peatio
|
8
|
+
class Root < Command::Base
|
9
|
+
subcommand "db", "Database related sub-commands", Peatio::Command::DB::Root
|
10
|
+
subcommand "service", "Services management related sub-commands", Peatio::Command::Service::Root
|
11
|
+
subcommand "inject", "Data injectors", Peatio::Command::Inject
|
12
|
+
subcommand "security", "Security management related sub-commands", Peatio::Command::Security
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Peatio::Command
|
4
|
+
class Security < Peatio::Command::Base
|
5
|
+
class KeyGenerator < Peatio::Command::Base
|
6
|
+
option "--print", :flag, "print on screen"
|
7
|
+
option "--path", "FOLDER", "save keypair into folder", default: "secrets"
|
8
|
+
|
9
|
+
def execute
|
10
|
+
keypair = Peatio::Security::KeyGenerator.new
|
11
|
+
|
12
|
+
if print?
|
13
|
+
puts keypair.private, keypair.public
|
14
|
+
puts "-----BASE64 ENCODED-----"
|
15
|
+
puts Base64.urlsafe_encode64(keypair.public)
|
16
|
+
else
|
17
|
+
begin
|
18
|
+
keypair.save(path)
|
19
|
+
puts "Files saved in #{File.join(path, 'rsa-key')}"
|
20
|
+
rescue IOError => e
|
21
|
+
abort("Failed saving files")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
subcommand "keygen", "Generate a public private rsa key pair", KeyGenerator
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Peatio::Command::Service
|
4
|
+
class Start < Peatio::Command::Base
|
5
|
+
class Ranger < Peatio::Command::Base
|
6
|
+
option ["-e", "--exchange"], "NAME", "exchange name to inject messages to", default: "peatio.events.ranger"
|
7
|
+
option "--[no-]stats", :flag, "display periodically connections statistics", default: true
|
8
|
+
option "--stats-period", "SECONDS", "period of displaying stats in seconds", default: 30
|
9
|
+
def execute
|
10
|
+
raise ArgumentError, "JWT_PUBLIC_KEY was not specified." if ENV["JWT_PUBLIC_KEY"].to_s.empty?
|
11
|
+
|
12
|
+
key_decoded = Base64.urlsafe_decode64(ENV["JWT_PUBLIC_KEY"])
|
13
|
+
|
14
|
+
jwt_public_key = OpenSSL::PKey.read(key_decoded)
|
15
|
+
if jwt_public_key.private?
|
16
|
+
raise ArgumentError, "JWT_PUBLIC_KEY was set to private key, however it should be public."
|
17
|
+
end
|
18
|
+
|
19
|
+
raise "stats period missing" if stats? && !stats_period
|
20
|
+
|
21
|
+
Prometheus::Client.config.data_store = Prometheus::Client::DataStores::SingleThreaded.new()
|
22
|
+
registry = Prometheus::Client.registry
|
23
|
+
|
24
|
+
opts = {
|
25
|
+
display_stats: stats?,
|
26
|
+
stats_period: stats_period.to_f,
|
27
|
+
metrics_port: 8082,
|
28
|
+
registry: registry
|
29
|
+
}
|
30
|
+
::Peatio::Ranger.run!(jwt_public_key, exchange, opts)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
subcommand "ranger", "Start ranger process", Ranger
|
35
|
+
end
|
36
|
+
|
37
|
+
class Root < Peatio::Command::Base
|
38
|
+
subcommand "start", "Start a service", Start
|
39
|
+
end
|
40
|
+
end
|
data/lib/peatio/error.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
class Peatio::Error < ::StandardError
|
2
|
+
@@default_code = 2000
|
3
|
+
|
4
|
+
attr :code, :text
|
5
|
+
|
6
|
+
def initialize(opts = {})
|
7
|
+
@code = opts[:code] || @@default_code
|
8
|
+
@text = opts[:text] || ""
|
9
|
+
|
10
|
+
@message = {error: {code: @code, message: @text}}
|
11
|
+
|
12
|
+
if @text != ""
|
13
|
+
super("#{@code}: #{text}")
|
14
|
+
else
|
15
|
+
super("#{@code}")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require "mysql2"
|
2
|
+
require "benchmark"
|
3
|
+
|
4
|
+
client = Mysql2::Client.new(
|
5
|
+
host: "172.19.0.3",
|
6
|
+
username: "root",
|
7
|
+
password: "changeme",
|
8
|
+
port: 3306,
|
9
|
+
database: "peatio_development")
|
10
|
+
|
11
|
+
queries = [
|
12
|
+
"INSERT INTO `trades` (`ask_id`, `ask_member_id`, `bid_id`, `bid_member_id`, `price`, `volume`, `funds`, `market_id`, `trend`, `created_at`, `updated_at`) VALUES (18711, 81, 18708, 82, 0.99999999, 50.0, 49.9999995, 'eurusd', 0, NOW(), NOW())",
|
13
|
+
"UPDATE `accounts` SET `accounts`.`locked` = 3571.09999702 WHERE `accounts`.`id` = 164",
|
14
|
+
"UPDATE `accounts` SET `accounts`.`balance` = 999995119.5335 WHERE `accounts`.`id` = 163",
|
15
|
+
"UPDATE `accounts` SET `accounts`.`locked` = 4257.0 WHERE `accounts`.`id` = 161",
|
16
|
+
"UPDATE `accounts` SET `accounts`.`balance` = 999995825.720262199325 WHERE `accounts`.`id` = 162",
|
17
|
+
"UPDATE `orders` SET `volume` = 20.0, `locked` = 19.9999998, `funds_received` = 53.0, `trades_count` = 2, `updated_at` = '2018-06-25 23:44:37' WHERE `orders`.`id` = 18708",
|
18
|
+
"UPDATE `orders` SET `volume` = 0.0, `locked` = 0.0, `funds_received` = 78.59999924, `trades_count` = 2, `state` = 200, `updated_at` = '2018-06-25 23:44:37' WHERE `orders`.`id` = 18711"
|
19
|
+
]
|
20
|
+
|
21
|
+
puts Benchmark.measure {
|
22
|
+
1_000.times {
|
23
|
+
|
24
|
+
client.query("begin")
|
25
|
+
begin
|
26
|
+
|
27
|
+
100.times {
|
28
|
+
queries.each do |q|
|
29
|
+
client.query q
|
30
|
+
end
|
31
|
+
}
|
32
|
+
|
33
|
+
rescue Mysql2::Error => e
|
34
|
+
puts "+++++++ DB ERROR - ROLLING BACK ++++++++"
|
35
|
+
puts e
|
36
|
+
client.query("rollback")
|
37
|
+
exit
|
38
|
+
end
|
39
|
+
client.query("commit") #commit the changes to the DB
|
40
|
+
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
client.close
|
45
|
+
|
46
|
+
__END__
|
47
|
+
|
48
|
+
require 'mysql2/em'
|
49
|
+
|
50
|
+
EM.run do
|
51
|
+
client = Mysql2::EM::Client.new(
|
52
|
+
:host => '172.19.0.3',
|
53
|
+
:username => 'root',
|
54
|
+
:password => 'changeme',
|
55
|
+
:port => 3306,
|
56
|
+
:database => 'peatio_development')
|
57
|
+
|
58
|
+
|
59
|
+
defer1 = client.query "SELECT sleep(3) as first_query"
|
60
|
+
defer1.callback do |result|
|
61
|
+
puts "Result: #{result.to_a.inspect}"
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,240 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Peatio::Injectors
|
4
|
+
class PeatioEvents
|
5
|
+
attr_accessor :market, :market_name, :base_unit, :quote_unit, :seller_uid, :buyer_uid, :logger
|
6
|
+
|
7
|
+
def run!(exchange_name)
|
8
|
+
require "time"
|
9
|
+
@logger = Peatio::Logger.logger
|
10
|
+
@market = "eurusd"
|
11
|
+
@market_name = "EUR/USD"
|
12
|
+
@base_unit = "eur"
|
13
|
+
@quote_unit = "usd"
|
14
|
+
@seller_uid = 21
|
15
|
+
@buyer_uid = 42
|
16
|
+
@messages = create_messages
|
17
|
+
@opts = {
|
18
|
+
ex_name: exchange_name
|
19
|
+
}
|
20
|
+
EventMachine.run do
|
21
|
+
inject_message()
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def inject_message()
|
26
|
+
if message = @messages.shift
|
27
|
+
type, id, event, data = message
|
28
|
+
Peatio::Ranger::Events.publish(type, id, event, data, @opts)
|
29
|
+
EM.next_tick do
|
30
|
+
inject_message()
|
31
|
+
end
|
32
|
+
else
|
33
|
+
Peatio::MQ::Client.disconnect
|
34
|
+
EventMachine.stop
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def create_messages
|
39
|
+
[
|
40
|
+
public_tickers,
|
41
|
+
public_orderbook,
|
42
|
+
private_order,
|
43
|
+
private_trade_user1,
|
44
|
+
private_trade_user2,
|
45
|
+
public_trade,
|
46
|
+
public_orderbook_increment1,
|
47
|
+
public_orderbook_snapshot1,
|
48
|
+
public_orderbook_increment2,
|
49
|
+
public_orderbook_increment3,
|
50
|
+
]
|
51
|
+
end
|
52
|
+
|
53
|
+
def created_at
|
54
|
+
Time.now - 600
|
55
|
+
end
|
56
|
+
|
57
|
+
def updated_at
|
58
|
+
Time.now
|
59
|
+
end
|
60
|
+
|
61
|
+
alias completed_at updated_at
|
62
|
+
alias canceled_at updated_at
|
63
|
+
|
64
|
+
def public_orderbook
|
65
|
+
[
|
66
|
+
"public",
|
67
|
+
market,
|
68
|
+
"update",
|
69
|
+
{
|
70
|
+
"asks": [
|
71
|
+
["1020.0", "0.005"],
|
72
|
+
["1026.0", "0.03"]
|
73
|
+
],
|
74
|
+
"bids": [
|
75
|
+
["1000.0", "0.25"],
|
76
|
+
["999.0", "0.005"],
|
77
|
+
["994.0", "0.005"],
|
78
|
+
["1.0", "11.0"]
|
79
|
+
]
|
80
|
+
}
|
81
|
+
]
|
82
|
+
end
|
83
|
+
|
84
|
+
def public_orderbook_snapshot1
|
85
|
+
[
|
86
|
+
"public",
|
87
|
+
market,
|
88
|
+
"ob-snap",
|
89
|
+
{
|
90
|
+
"asks": [
|
91
|
+
["1020.0", "0.005"],
|
92
|
+
["1026.0", "0.03"]
|
93
|
+
],
|
94
|
+
"bids": [
|
95
|
+
["1000.0", "0.25"],
|
96
|
+
["999.0", "0.005"],
|
97
|
+
["994.0", "0.005"],
|
98
|
+
["1.0", "11.0"]
|
99
|
+
]
|
100
|
+
}
|
101
|
+
]
|
102
|
+
end
|
103
|
+
|
104
|
+
def public_orderbook_increment1
|
105
|
+
[
|
106
|
+
"public",
|
107
|
+
market,
|
108
|
+
"ob-inc",
|
109
|
+
{
|
110
|
+
"asks": [
|
111
|
+
["1020.0", "0.015"],
|
112
|
+
],
|
113
|
+
}
|
114
|
+
]
|
115
|
+
end
|
116
|
+
|
117
|
+
def public_orderbook_increment2
|
118
|
+
[
|
119
|
+
"public",
|
120
|
+
market,
|
121
|
+
"ob-inc",
|
122
|
+
{
|
123
|
+
"bids": [
|
124
|
+
["1000.0", "0"],
|
125
|
+
],
|
126
|
+
}
|
127
|
+
]
|
128
|
+
end
|
129
|
+
|
130
|
+
def public_orderbook_increment3
|
131
|
+
[
|
132
|
+
"public",
|
133
|
+
market,
|
134
|
+
"ob-inc",
|
135
|
+
{
|
136
|
+
"bids": [
|
137
|
+
["999.0", "0.001"],
|
138
|
+
],
|
139
|
+
}
|
140
|
+
]
|
141
|
+
end
|
142
|
+
|
143
|
+
def public_tickers
|
144
|
+
[
|
145
|
+
"public",
|
146
|
+
"global",
|
147
|
+
"tickers",
|
148
|
+
{
|
149
|
+
market => {
|
150
|
+
"name": market_name,
|
151
|
+
"base_unit": base_unit,
|
152
|
+
"quote_unit": quote_unit,
|
153
|
+
"low": "1000.0",
|
154
|
+
"high": "10000.0",
|
155
|
+
"last": "1000.0",
|
156
|
+
"open": 1000.0,
|
157
|
+
"volume": "0.0",
|
158
|
+
"sell": "1020.0",
|
159
|
+
"buy": "1000.0",
|
160
|
+
"at": Time.now.to_i
|
161
|
+
}
|
162
|
+
}
|
163
|
+
]
|
164
|
+
end
|
165
|
+
|
166
|
+
def private_order
|
167
|
+
[
|
168
|
+
"private",
|
169
|
+
"IDABC0000001",
|
170
|
+
"order",
|
171
|
+
{
|
172
|
+
"id": 22,
|
173
|
+
"at": created_at.to_i,
|
174
|
+
"market": market,
|
175
|
+
"kind": "bid",
|
176
|
+
"price": "1026.0",
|
177
|
+
"state": "wait",
|
178
|
+
"volume": "0.001",
|
179
|
+
"origin_volume": "0.001"
|
180
|
+
}
|
181
|
+
]
|
182
|
+
end
|
183
|
+
|
184
|
+
def private_trade_user1
|
185
|
+
[
|
186
|
+
"private",
|
187
|
+
"IDABC0000001",
|
188
|
+
"trade",
|
189
|
+
{
|
190
|
+
"id": 7,
|
191
|
+
"kind": "ask",
|
192
|
+
"at": created_at.to_i,
|
193
|
+
"price": "1020.0",
|
194
|
+
"volume": "0.001",
|
195
|
+
"ask_id": 15,
|
196
|
+
"bid_id": 22,
|
197
|
+
"market": market
|
198
|
+
}
|
199
|
+
]
|
200
|
+
end
|
201
|
+
|
202
|
+
def private_trade_user2
|
203
|
+
[
|
204
|
+
"private",
|
205
|
+
"IDABC0000002",
|
206
|
+
"trade",
|
207
|
+
{
|
208
|
+
"id": 7,
|
209
|
+
"kind": "bid",
|
210
|
+
"at": created_at.to_i,
|
211
|
+
"price": "1020.0",
|
212
|
+
"volume": "0.001",
|
213
|
+
"ask_id": 15,
|
214
|
+
"bid_id": 22,
|
215
|
+
"market": market
|
216
|
+
}
|
217
|
+
]
|
218
|
+
end
|
219
|
+
|
220
|
+
def public_trade
|
221
|
+
[
|
222
|
+
"public",
|
223
|
+
market,
|
224
|
+
"trades",
|
225
|
+
{
|
226
|
+
"trades": [
|
227
|
+
{
|
228
|
+
"tid": 7,
|
229
|
+
"taker_type": "buy",
|
230
|
+
"date": created_at.to_i,
|
231
|
+
"price": "1020.0",
|
232
|
+
"amount":
|
233
|
+
"0.001"
|
234
|
+
}
|
235
|
+
]
|
236
|
+
}
|
237
|
+
]
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|