istox 0.1.103 → 0.1.104
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/.rubocop.yml +1 -1
- data/Gemfile.lock +19 -13
- data/istox.gemspec +2 -0
- data/lib/istox.rb +1 -0
- data/lib/istox/consumers/blockchain_status_handler.rb +27 -19
- data/lib/istox/helpers/bunny_boot.rb +101 -54
- data/lib/istox/helpers/graphql_client.rb +3 -2
- data/lib/istox/helpers/grpc_client.rb +7 -5
- data/lib/istox/helpers/gruf_listener_hook.rb +18 -18
- data/lib/istox/helpers/logger.rb +18 -0
- data/lib/istox/helpers/message_service.rb +44 -39
- data/lib/istox/helpers/publisher.rb +85 -27
- data/lib/istox/helpers/vault.rb +6 -8
- data/lib/istox/version.rb +1 -1
- metadata +31 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 017e8b356e88bb9934ee5e01dce3ef6ce1ccdbf937bd5e8463ccd138c074ccee
|
|
4
|
+
data.tar.gz: 606737426dc9eaf9ca1b3d1f879b0dda17f46dacc89817cacf80990ce8a9fad2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 38bd1dcc56ce327d8c994f5743310cf3e34d3f70639513dcdfdcb0bd2a9b6a3c5cdef19e5b3b26c4ac43d8ee5742146cfb798b73be17fd4f9838bb14c7b5013c
|
|
7
|
+
data.tar.gz: d338cf9fe623a1a99481581c57142a5637899509f319407d489662ce8c511318d5a5747a8f091072f17a796bc51038382162278b89b5a72b0cd9c1a739e506e2
|
data/.rubocop.yml
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
istox (0.1.
|
|
4
|
+
istox (0.1.103)
|
|
5
|
+
awesome_print
|
|
5
6
|
binding_of_caller
|
|
6
7
|
bunny (>= 2.12.0)
|
|
7
8
|
graphlient
|
|
8
9
|
gruf
|
|
9
10
|
istox_gruf
|
|
10
11
|
listen (~> 3.0.5)
|
|
12
|
+
ougai
|
|
11
13
|
paranoia (~> 2.2)
|
|
12
14
|
vault (~> 0.1)
|
|
13
15
|
|
|
@@ -57,6 +59,7 @@ GEM
|
|
|
57
59
|
tzinfo (~> 1.1)
|
|
58
60
|
amq-protocol (2.3.0)
|
|
59
61
|
arel (9.0.0)
|
|
62
|
+
awesome_print (1.8.0)
|
|
60
63
|
aws-eventstream (1.0.3)
|
|
61
64
|
aws-sigv4 (1.1.0)
|
|
62
65
|
aws-eventstream (~> 1.0, >= 1.0.2)
|
|
@@ -66,7 +69,7 @@ GEM
|
|
|
66
69
|
bullet (5.7.6)
|
|
67
70
|
activesupport (>= 3.0.0)
|
|
68
71
|
uniform_notifier (~> 1.11.0)
|
|
69
|
-
bunny (2.14.
|
|
72
|
+
bunny (2.14.3)
|
|
70
73
|
amq-protocol (~> 2.3, >= 2.3.0)
|
|
71
74
|
concurrent-ruby (1.1.4)
|
|
72
75
|
crass (1.0.4)
|
|
@@ -81,29 +84,29 @@ GEM
|
|
|
81
84
|
railties (>= 3.0.0)
|
|
82
85
|
faker (1.7.3)
|
|
83
86
|
i18n (~> 0.5)
|
|
84
|
-
faraday (0.
|
|
87
|
+
faraday (0.17.3)
|
|
85
88
|
multipart-post (>= 1.2, < 3)
|
|
86
89
|
faraday_middleware (0.13.1)
|
|
87
90
|
faraday (>= 0.7.4, < 1.0)
|
|
88
|
-
ffi (1.11.
|
|
91
|
+
ffi (1.11.3)
|
|
89
92
|
globalid (0.4.2)
|
|
90
93
|
activesupport (>= 4.2.0)
|
|
91
|
-
google-protobuf (3.
|
|
94
|
+
google-protobuf (3.11.2)
|
|
92
95
|
googleapis-common-protos-types (1.0.4)
|
|
93
96
|
google-protobuf (~> 3.0)
|
|
94
|
-
graphlient (0.3.
|
|
97
|
+
graphlient (0.3.7)
|
|
95
98
|
faraday
|
|
96
99
|
faraday_middleware
|
|
97
100
|
graphql-client
|
|
98
|
-
graphql (1.9.
|
|
99
|
-
graphql-client (0.
|
|
101
|
+
graphql (1.9.17)
|
|
102
|
+
graphql-client (0.16.0)
|
|
100
103
|
activesupport (>= 3.0)
|
|
101
104
|
graphql (~> 1.8)
|
|
102
|
-
grpc (1.
|
|
105
|
+
grpc (1.26.0)
|
|
103
106
|
google-protobuf (~> 3.8)
|
|
104
107
|
googleapis-common-protos-types (~> 1.0)
|
|
105
|
-
grpc-tools (1.
|
|
106
|
-
gruf (2.7.
|
|
108
|
+
grpc-tools (1.26.0)
|
|
109
|
+
gruf (2.7.1)
|
|
107
110
|
activesupport (> 4)
|
|
108
111
|
concurrent-ruby (> 1)
|
|
109
112
|
grpc (~> 1.10)
|
|
@@ -136,6 +139,9 @@ GEM
|
|
|
136
139
|
nio4r (2.3.1)
|
|
137
140
|
nokogiri (1.10.1)
|
|
138
141
|
mini_portile2 (~> 2.4.0)
|
|
142
|
+
oj (3.10.0)
|
|
143
|
+
ougai (1.8.2)
|
|
144
|
+
oj (~> 3.4)
|
|
139
145
|
paranoia (2.4.2)
|
|
140
146
|
activerecord (>= 4.0, < 6.1)
|
|
141
147
|
rack (2.0.6)
|
|
@@ -167,7 +173,7 @@ GEM
|
|
|
167
173
|
thor (>= 0.19.0, < 2.0)
|
|
168
174
|
rake (10.5.0)
|
|
169
175
|
rb-fsevent (0.10.3)
|
|
170
|
-
rb-inotify (0.10.
|
|
176
|
+
rb-inotify (0.10.1)
|
|
171
177
|
ffi (~> 1.0)
|
|
172
178
|
rspec (3.8.0)
|
|
173
179
|
rspec-core (~> 3.8.0)
|
|
@@ -204,7 +210,7 @@ GEM
|
|
|
204
210
|
tzinfo (1.2.5)
|
|
205
211
|
thread_safe (~> 0.1)
|
|
206
212
|
uniform_notifier (1.11.0)
|
|
207
|
-
vault (0.
|
|
213
|
+
vault (0.13.0)
|
|
208
214
|
aws-sigv4
|
|
209
215
|
websocket-driver (0.7.0)
|
|
210
216
|
websocket-extensions (>= 0.1.0)
|
data/istox.gemspec
CHANGED
|
@@ -39,6 +39,8 @@ Gem::Specification.new do |spec|
|
|
|
39
39
|
spec.add_dependency "graphlient"
|
|
40
40
|
spec.add_dependency 'listen', '~> 3.0.5'
|
|
41
41
|
spec.add_dependency "binding_of_caller"
|
|
42
|
+
spec.add_dependency "ougai"
|
|
43
|
+
spec.add_dependency "awesome_print"
|
|
42
44
|
spec.add_development_dependency "bundler", "~> 1.16"
|
|
43
45
|
spec.add_development_dependency "rake", "~> 10.0"
|
|
44
46
|
spec.add_development_dependency "rspec", "~> 3.0"
|
data/lib/istox.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'istox/helpers/logger'
|
|
2
|
+
|
|
1
3
|
module Istox
|
|
2
4
|
class BlockchainStatusHandler
|
|
3
5
|
class << self
|
|
@@ -14,7 +16,7 @@ module Istox
|
|
|
14
16
|
def chainhub_response_event(transaction)
|
|
15
17
|
receipt = ::Istox::BlockchainReceipt.where(txid: transaction.uuid).first
|
|
16
18
|
if receipt.blank?
|
|
17
|
-
|
|
19
|
+
log.info 'Transaction doesn\'t belong to this backend, skipping...'
|
|
18
20
|
return
|
|
19
21
|
end
|
|
20
22
|
|
|
@@ -26,7 +28,7 @@ module Istox
|
|
|
26
28
|
resource = begin
|
|
27
29
|
class_eval("::#{receipt.resource_name}", __FILE__, __LINE__).find(receipt.resource_id)
|
|
28
30
|
rescue NameError
|
|
29
|
-
|
|
31
|
+
log.warn "Transaction bind to #{receipt.resource_name} with id #{receipt.resource_id} class not found, skipping..."
|
|
30
32
|
return
|
|
31
33
|
end
|
|
32
34
|
|
|
@@ -49,36 +51,42 @@ module Istox
|
|
|
49
51
|
private
|
|
50
52
|
|
|
51
53
|
def publish_to_frontend(model, success, receipt, sid)
|
|
52
|
-
::Istox::Publisher.
|
|
53
|
-
'amq.topic',
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
::Istox::Publisher.manual_publish(
|
|
55
|
+
exchange: 'amq.topic',
|
|
56
|
+
exchange_type: 'direct',
|
|
57
|
+
routing_key: model.class.name.gsub('::', '').underscore.to_s,
|
|
58
|
+
message: {
|
|
59
|
+
data: {
|
|
60
|
+
id: model.id,
|
|
61
|
+
extra: model.handle_extra
|
|
62
|
+
}
|
|
58
63
|
}
|
|
59
64
|
)
|
|
60
65
|
|
|
61
|
-
::Istox::Publisher.
|
|
62
|
-
'amq.topic',
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
::Istox::Publisher.manual_publish(
|
|
67
|
+
exchange: 'amq.topic',
|
|
68
|
+
exchange_type: 'direct',
|
|
69
|
+
routing_key: sid,
|
|
70
|
+
message: {
|
|
71
|
+
data: {
|
|
72
|
+
success: success,
|
|
73
|
+
purpose: receipt.activity,
|
|
74
|
+
message: receipt.message
|
|
75
|
+
}
|
|
68
76
|
}
|
|
69
77
|
)
|
|
70
78
|
rescue StandardError => e
|
|
71
|
-
|
|
79
|
+
log.warn "Unable to publish to frontend for receipt #{receipt.inspect},
|
|
72
80
|
but will silently ignore the error"
|
|
73
|
-
|
|
81
|
+
log.warn e
|
|
74
82
|
end
|
|
75
83
|
|
|
76
84
|
def mark_resource_handled(receipt)
|
|
77
85
|
receipt.update(resource_handled: true)
|
|
78
86
|
rescue StandardError => e
|
|
79
|
-
|
|
87
|
+
log.warn "Unable to update resource_handled for receipt #{receipt.inspect},
|
|
80
88
|
but will silently ignore the error"
|
|
81
|
-
|
|
89
|
+
log.warn e
|
|
82
90
|
end
|
|
83
91
|
|
|
84
92
|
def resource_handled?(receipt)
|
|
@@ -1,77 +1,124 @@
|
|
|
1
1
|
require 'bunny'
|
|
2
|
+
require 'istox/helpers/logger'
|
|
3
|
+
|
|
2
4
|
module Istox
|
|
3
5
|
class BunnyBoot
|
|
4
6
|
class << self
|
|
7
|
+
# path to amqp.yml
|
|
5
8
|
def initialize!(amqp_config_path)
|
|
6
|
-
|
|
7
|
-
::Istox::Publisher.initialize!(amqp_config_path)
|
|
8
|
-
connect
|
|
9
|
-
end
|
|
9
|
+
@amqp_config_path = amqp_config_path
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
subscribe_to_queues
|
|
11
|
+
data
|
|
13
12
|
end
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
# optionally can pass in consumer_key for single subscription / consumer_keys for multiple subcriptions
|
|
15
|
+
# consumer_key must be defined in amqp.yml
|
|
16
|
+
# if nothing pass in it will auto subscribe to all available consumers defined in amqp.yml queues key
|
|
17
|
+
def start_subscribe(consumer_key: nil, consumer_keys: nil)
|
|
18
|
+
subscribing_consumer_keys = consumer_keys.present? ? consumer_keys : []
|
|
19
|
+
|
|
20
|
+
if subscribing_consumer_keys.empty? && consumer_key.nil?
|
|
21
|
+
subscribing_consumer_keys = data['queues'].keys
|
|
22
|
+
elsif subscribing_consumer_keys.empty? && consumer_key.present?
|
|
23
|
+
subscribing_consumer_keys = [consumer_key]
|
|
24
|
+
end
|
|
20
25
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def subscribe_to_queues
|
|
24
|
-
data&.queues&.each do |data|
|
|
25
|
-
config = OpenStruct.new(data[1])
|
|
26
|
-
klass = Object.const_get('::' + "#{data[0]}_consumer".camelize)
|
|
27
|
-
exchange_type = if config.exchange.ends_with?('.fanout')
|
|
28
|
-
:fanout
|
|
29
|
-
else
|
|
30
|
-
:direct
|
|
31
|
-
end
|
|
32
|
-
options = {}
|
|
33
|
-
options[:routing_key] = config.name if exchange_type != :fanout
|
|
34
|
-
queue = $channel.queue(
|
|
35
|
-
config.name,
|
|
36
|
-
durable: config.durable
|
|
37
|
-
).bind(exchange(config.exchange, exchange_type), options)
|
|
38
|
-
|
|
39
|
-
manual_ack = true
|
|
40
|
-
manual_ack = config.manual_ack unless config.manual_ack.nil?
|
|
41
|
-
|
|
42
|
-
queue.subscribe manual_ack: manual_ack do |delivery_info, metadata, payload|
|
|
43
|
-
Rails.logger.debug("Processing in consumer: #{klass}")
|
|
44
|
-
klass.new.process(
|
|
45
|
-
Hashie::Mash.new(JSON.parse(payload)),
|
|
46
|
-
metadata,
|
|
47
|
-
delivery_info
|
|
48
|
-
)
|
|
49
|
-
$channel.ack(delivery_info.delivery_tag) if manual_ack
|
|
50
|
-
rescue StandardError => e
|
|
51
|
-
Rails.logger.error(e)
|
|
52
|
-
$channel.nack(delivery_info.delivery_tag, false, true)
|
|
53
|
-
end
|
|
26
|
+
subscribing_consumer_keys.each do |key|
|
|
27
|
+
subscribe_to_consumer(key.to_s)
|
|
54
28
|
end
|
|
55
29
|
end
|
|
56
30
|
|
|
57
|
-
|
|
31
|
+
#############################################################################################
|
|
32
|
+
## INTERNAL METHODS START
|
|
33
|
+
############################################################################################
|
|
58
34
|
|
|
59
|
-
def
|
|
60
|
-
|
|
35
|
+
def channel
|
|
36
|
+
return @channel if @channel.present?
|
|
37
|
+
|
|
38
|
+
@channel = connection.create_channel(nil, data['channel_pool_size'] || 1)
|
|
39
|
+
@channel.prefetch(data['channel_prefetch'] || 1)
|
|
40
|
+
|
|
41
|
+
@channel
|
|
61
42
|
end
|
|
62
43
|
|
|
63
|
-
|
|
64
|
-
|
|
44
|
+
# calling this method will spawn another channel, please use the normal channel method if you like to use the same channel
|
|
45
|
+
def create_new_channel(channel_config)
|
|
46
|
+
channel = connection.create_channel(nil, channel_config['channel_pool_size'] || data['channel_pool_size'] || 1)
|
|
47
|
+
channel.prefetch(channel_config['channel_prefetch'] || data['channel_prefetch'] || 1)
|
|
48
|
+
|
|
49
|
+
channel
|
|
65
50
|
end
|
|
66
51
|
|
|
67
|
-
def
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
52
|
+
def subscribe_to_consumer(consumer_key)
|
|
53
|
+
queue_config = data['queues'][consumer_key]
|
|
54
|
+
|
|
55
|
+
raise "Unable to find consumer with key #{consumer_key}, have you forgotten to define it in amqp.yml?" if queue_config.nil?
|
|
56
|
+
|
|
57
|
+
klass = Object.const_get(
|
|
58
|
+
'::' + (queue_config['ruby_class'].nil? ? "#{consumer_key.to_s.underscore}_consumer" : queue_config['ruby_class']).camelize
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
exchange = nil
|
|
62
|
+
exchange_config = exchange_config!(consumer_key)
|
|
63
|
+
|
|
64
|
+
active_channel = queue_config['channel'].present? ? create_new_channel(queue_config['channel']) : channel
|
|
65
|
+
|
|
66
|
+
queue_options = {}
|
|
67
|
+
|
|
68
|
+
exchange_durable = exchange_config['durable'].nil? ? true : exchange_config['durable']
|
|
69
|
+
|
|
70
|
+
case exchange_config['type']
|
|
71
|
+
when 'fanout'
|
|
72
|
+
exchange = active_channel.fanout(queue_config['exchange'], durable: exchange_durable)
|
|
73
|
+
when 'direct'
|
|
74
|
+
exchange = active_channel.direct(queue_config['exchange'], durable: exchange_durable)
|
|
75
|
+
queue_options[:routing_key] = queue_config['queue_name']
|
|
71
76
|
else
|
|
72
|
-
|
|
77
|
+
raise "Exchange type #{exchange_config.type} is not valid/supported."
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
queue = active_channel.queue(queue_config['queue_name'],
|
|
81
|
+
durable: queue_config['durable'].nil? ? exchange_durable : queue_config['durable']).bind(exchange, queue_options)
|
|
82
|
+
|
|
83
|
+
manual_ack = queue_config['manual_ack'].nil? ? true : queue_config['manual_ack']
|
|
84
|
+
|
|
85
|
+
queue.subscribe manual_ack: manual_ack do |delivery_info, metadata, payload|
|
|
86
|
+
processing_paylod = JSON.parse(payload)
|
|
87
|
+
log.info "Processing in consumer: #{klass}, paylod: #{processing_paylod.inspect}"
|
|
88
|
+
|
|
89
|
+
klass.new.process(::Istox::CommonHelper.to_open_struct(processing_paylod, metadata, delivery_info))
|
|
90
|
+
active_channel.ack(delivery_info.delivery_tag) if manual_ack
|
|
91
|
+
rescue StandardError => e
|
|
92
|
+
log.error(e)
|
|
93
|
+
active_channel.nack(delivery_info.delivery_tag, false, true) if manual_ack
|
|
73
94
|
end
|
|
74
95
|
end
|
|
96
|
+
|
|
97
|
+
def data
|
|
98
|
+
raise 'Unable to find amqp configuration file, have you forgotten to initialise Istox::BunnyBoot?' if @amqp_config_path.empty?
|
|
99
|
+
|
|
100
|
+
@data ||= JSON.parse(YAML.load_file(@amqp_config_path).to_json)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def connection
|
|
104
|
+
return @connection if @connection.present?
|
|
105
|
+
|
|
106
|
+
raise 'RabbitMQ connection configuration not found, have you forgotten to define connect key in amqp.yml?' if data['connect'].nil?
|
|
107
|
+
|
|
108
|
+
@connection = Bunny.new(data['connect'].symbolize_keys)
|
|
109
|
+
@connection.start
|
|
110
|
+
|
|
111
|
+
@connection
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def exchange_config!(consumer_key)
|
|
115
|
+
exchange_name = data['queues'][consumer_key]['exchange']
|
|
116
|
+
exchange_config = data['exchanges'][exchange_name]
|
|
117
|
+
|
|
118
|
+
raise "Exchange #{exchange_name} config not found, have you forgotten to define the exchange in amqp.yml?" if exchange_config.nil?
|
|
119
|
+
|
|
120
|
+
exchange_config
|
|
121
|
+
end
|
|
75
122
|
end
|
|
76
123
|
end
|
|
77
124
|
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'graphlient'
|
|
2
|
+
require 'istox/helpers/logger'
|
|
2
3
|
|
|
3
4
|
module Istox
|
|
4
5
|
class GraphqlClient
|
|
@@ -13,12 +14,12 @@ module Istox
|
|
|
13
14
|
|
|
14
15
|
raise "Please make sure you have initialised graphql cient for host #{host_type}" unless client
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
log.info "Querying Graphql host: #{host_type}, query: #{query}, variables: #{variables.inspect}"
|
|
17
18
|
result = client.query(query, variables)
|
|
18
19
|
|
|
19
20
|
return_values = ::Istox::CommonHelper.to_open_struct(result&.data)
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
log.info "Graphql result: #{return_values.inspect}"
|
|
22
23
|
|
|
23
24
|
return_values
|
|
24
25
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'istox/helpers/logger'
|
|
2
|
+
|
|
1
3
|
module Istox
|
|
2
4
|
class GrpcClient
|
|
3
5
|
class << self
|
|
@@ -18,14 +20,14 @@ module Istox
|
|
|
18
20
|
private
|
|
19
21
|
|
|
20
22
|
def execute(host_type, service, method, **keyword_args)
|
|
21
|
-
|
|
23
|
+
log.info "Calling method in grpc method: #{method.inspect}, params: #{keyword_args.inspect}"
|
|
22
24
|
t1 = Time.now
|
|
23
25
|
|
|
24
26
|
result = get_host(host_type, service).call(method, keyword_args)
|
|
25
|
-
|
|
27
|
+
log.info "Time taken for grpc execution: #{Time.now - t1} seconds"
|
|
26
28
|
|
|
27
29
|
return_values = ::Istox::CommonHelper.to_open_struct(result.message)
|
|
28
|
-
|
|
30
|
+
log.info "Result: #{return_values}"
|
|
29
31
|
|
|
30
32
|
return_values
|
|
31
33
|
end
|
|
@@ -49,10 +51,10 @@ module Istox
|
|
|
49
51
|
host_url = @@hosts[host_type]
|
|
50
52
|
raise StandardError, 'Unable to find host, have you forgotten to add host to grpc client?' unless host_url
|
|
51
53
|
|
|
52
|
-
|
|
54
|
+
log.info 'Reinitiating to grpc host at ' + host_url
|
|
53
55
|
t1 = Time.now
|
|
54
56
|
@@services[get_key(host_type, service)] = ::Gruf::Client.new(service: service, options: { hostname: host_url })
|
|
55
|
-
|
|
57
|
+
log.info "Time taken for reinitiating grpc host: #{Time.now - t1} seconds"
|
|
56
58
|
end
|
|
57
59
|
|
|
58
60
|
def get_key(host_type, service)
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
module Istox
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
class GrufListenerHook < ::Gruf::Hooks::Base
|
|
3
|
+
def before_server_start(server:)
|
|
4
|
+
# do my thing before the server starts
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
end
|
|
6
|
+
@listener = ::Listen.to('app/rpc') do |modified, added, removed|
|
|
7
|
+
puts "modified absolute path: #{modified}"
|
|
8
|
+
puts "added absolute path: #{added}"
|
|
9
|
+
puts "removed absolute path: #{removed}"
|
|
10
|
+
|
|
11
|
+
server.init_restart
|
|
12
|
+
end
|
|
13
|
+
@listener.start # not blocking
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def after_server_stop(server:)
|
|
17
|
+
# do my thing after the server stops
|
|
18
|
+
@listener.stop
|
|
20
19
|
end
|
|
21
|
-
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'ougai'
|
|
2
|
+
|
|
3
|
+
module Istox
|
|
4
|
+
class Logger
|
|
5
|
+
def self.logger
|
|
6
|
+
return @logger if @logger.present?
|
|
7
|
+
|
|
8
|
+
@logger = ::Ougai::Logger.new(STDOUT)
|
|
9
|
+
@logger.formatter = ::Ougai::Formatters::Readable.new unless Rails.env.production?
|
|
10
|
+
|
|
11
|
+
@logger
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def log
|
|
17
|
+
::Istox::Logger.logger
|
|
18
|
+
end
|
|
@@ -1,46 +1,51 @@
|
|
|
1
1
|
module Istox
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
2
|
+
class MessageService
|
|
3
|
+
class << self
|
|
4
|
+
def send_sms(number, subject, content)
|
|
5
|
+
publish('sms', data: {
|
|
6
|
+
to: number,
|
|
7
|
+
subject: subject,
|
|
8
|
+
body: content
|
|
9
|
+
},
|
|
10
|
+
type: __method__.to_s.upcase!)
|
|
11
|
+
end
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
def send_sms_template(number, template)
|
|
14
|
+
publish('sms', data: {
|
|
15
|
+
to: number,
|
|
16
|
+
template: template
|
|
17
|
+
},
|
|
18
|
+
type: __method__.to_s.upcase!)
|
|
19
|
+
end
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
21
|
+
def send_email(email, subject, content)
|
|
22
|
+
publish('email', data: {
|
|
23
|
+
to: email,
|
|
24
|
+
subject: subject,
|
|
25
|
+
type: 'text/plain',
|
|
26
|
+
body: content
|
|
27
|
+
},
|
|
28
|
+
type: __method__.to_s.upcase!)
|
|
29
|
+
end
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
def send_email_template(email, template)
|
|
32
|
+
publish('email', data: {
|
|
33
|
+
to: email,
|
|
34
|
+
template: template
|
|
35
|
+
},
|
|
36
|
+
type: __method__.to_s.upcase!)
|
|
37
|
+
end
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
private
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
def publish(type, payload)
|
|
42
|
+
::Istox::Publisher.manual_publish(
|
|
43
|
+
exchange: 'message',
|
|
44
|
+
exchange_type: 'direct',
|
|
45
|
+
routing_key: "#{type}.message",
|
|
46
|
+
message: payload
|
|
47
|
+
)
|
|
48
|
+
end
|
|
45
49
|
end
|
|
46
|
-
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -1,44 +1,102 @@
|
|
|
1
|
+
require 'istox/helpers/logger'
|
|
2
|
+
|
|
1
3
|
module Istox
|
|
4
|
+
# Publisher is relying on BunnyBoot to publish message, please make sure BunnyBoot is initalised properly first during runtime.
|
|
2
5
|
class Publisher
|
|
3
6
|
class << self
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def publish(exchange, routing_key, message
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
7
|
+
# routing_key can be nil if publishing to fanout exchange
|
|
8
|
+
# exchange can be nil if routing_key is unique in "publish" section, this function will be able to identify which exchange it is using
|
|
9
|
+
# else both routing_key and exchange should be provided
|
|
10
|
+
# check http://reference.rubybunny.info/Bunny/Exchange.html#publish-instance_method for available publish options
|
|
11
|
+
def publish(exchange: nil, routing_key: nil, message:, options: {})
|
|
12
|
+
raise 'Exchange and routing key cannot be nil at the same time.' if exchange.nil? && routing_key.nil?
|
|
13
|
+
|
|
14
|
+
queue_publish_config = nil
|
|
15
|
+
if routing_key.present?
|
|
16
|
+
exchange = search_exchange_of_routing_key!(routing_key) if exchange.nil?
|
|
17
|
+
|
|
18
|
+
puts "EXCYANGE IS #{exchange}"
|
|
19
|
+
|
|
20
|
+
queue_publish_config = queue_publish_config!(routing_key: routing_key, exchange: exchange)
|
|
16
21
|
end
|
|
22
|
+
|
|
23
|
+
exchange_config = exchange_config!(exchange)
|
|
24
|
+
exchange_durable = exchange_config['durable'].nil? ? true : exchange_config['durable']
|
|
25
|
+
|
|
26
|
+
queue_durable = queue_publish_config.present? ? queue_publish_config['durable'] : nil
|
|
27
|
+
queue_durable = exchange_config['durable'].nil? ? true : exchange_config['durable'] if queue_durable.nil?
|
|
28
|
+
|
|
29
|
+
options[:durable] = queue_durable
|
|
30
|
+
options[:persistent] = options[:persistent].nil? ? true : options[:persistent]
|
|
31
|
+
|
|
32
|
+
send_message(exchange: exchange, routing_key: routing_key, message: message,
|
|
33
|
+
exchange_type: exchange_config['type'], exchange_durable: exchange_durable, options: options)
|
|
17
34
|
end
|
|
18
35
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
durable =
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
end
|
|
36
|
+
# publish without defining exchange and queue in amqp.yml
|
|
37
|
+
def manual_publish(exchange:, routing_key: nil, message:, exchange_type: 'direct', exchange_durable: true, options: {})
|
|
38
|
+
options[:durable] = options[:durable].nil? ? true : options[:durable]
|
|
39
|
+
options[:persistent] = options[:persistent].nil? ? true : options[:persistent]
|
|
40
|
+
|
|
41
|
+
send_message(exchange: exchange, routing_key: routing_key, message: message,
|
|
42
|
+
exchange_type: exchange_type, exchange_durable: exchange_durable, options: options)
|
|
27
43
|
end
|
|
28
44
|
|
|
29
45
|
private
|
|
30
46
|
|
|
31
|
-
def
|
|
32
|
-
|
|
33
|
-
yield
|
|
34
|
-
end
|
|
47
|
+
def send_message(exchange:, routing_key: nil, message:, exchange_type:, exchange_durable:, options: {})
|
|
48
|
+
log.info "Publishing RABBITMQ message to exchange: #{exchange}, routing key: #{routing_key}, data: #{message}, options: #{options.inspect}"
|
|
35
49
|
|
|
36
|
-
|
|
37
|
-
|
|
50
|
+
case exchange_type
|
|
51
|
+
when 'direct'
|
|
52
|
+
raise 'Routing key cannot be empty for exchange type direct' if routing_key.blank?
|
|
53
|
+
|
|
54
|
+
options[:routing_key] = routing_key
|
|
55
|
+
channel.direct(exchange, durable: exchange_durable).publish(message.to_json, options)
|
|
56
|
+
when 'fanout'
|
|
57
|
+
channel.fanout(exchange, durable: exchange_durable).publish(message.to_json, options)
|
|
58
|
+
else
|
|
59
|
+
raise "Exchange type #{exchange_config.type} is not valid/supported."
|
|
60
|
+
end
|
|
38
61
|
end
|
|
39
62
|
|
|
40
63
|
def data
|
|
41
|
-
|
|
64
|
+
::Istox::BunnyBoot.data
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def channel
|
|
68
|
+
::Istox::BunnyBoot.channel
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def queue_publish_config!(routing_key:, exchange:)
|
|
72
|
+
queue_publish_config = data['publish'][exchange][routing_key]
|
|
73
|
+
unless data['publish'][exchange].key?(routing_key)
|
|
74
|
+
raise "Cannot find publish queue config for exchange #{exchange} and routing key #{routing_key},
|
|
75
|
+
have you forgotten to define it in exchange section in amqp.yml"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
queue_publish_config
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def search_exchange_of_routing_key!(routing_key)
|
|
82
|
+
data['publish'].each do |k, v|
|
|
83
|
+
v.each do |k2, _v2|
|
|
84
|
+
return k if k2 == routing_key
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
raise "Cannot find exchange of routing key #{routing_key}, have you forgotten to define it in exchange section in amqp.yml"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def exchange_config!(exchange_name)
|
|
92
|
+
exchange_config = data['exchanges'][exchange_name]
|
|
93
|
+
|
|
94
|
+
if exchange_config.nil?
|
|
95
|
+
raise "Exchange config of #{exchange_name} cannot be found, have you
|
|
96
|
+
forgotten to define it in exchange section in amqp.yml"
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
exchange_config
|
|
42
100
|
end
|
|
43
101
|
end
|
|
44
102
|
end
|
data/lib/istox/helpers/vault.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
require 'istox/helpers/logger'
|
|
1
2
|
require 'vault'
|
|
2
3
|
|
|
3
4
|
module Istox
|
|
@@ -5,7 +6,7 @@ module Istox
|
|
|
5
6
|
module TOTP
|
|
6
7
|
class << self
|
|
7
8
|
def create(sid, host)
|
|
8
|
-
|
|
9
|
+
log.debug { "Generate vault TOTP for key #{totp_key(sid).inspect}" }
|
|
9
10
|
|
|
10
11
|
write_data(totp_key(sid),
|
|
11
12
|
generate: true,
|
|
@@ -16,17 +17,17 @@ module Istox
|
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
def generate_code(sid)
|
|
19
|
-
|
|
20
|
+
log.debug { "Generate 6-digit OTP code: key #{totp_code_key(sid)}" }
|
|
20
21
|
read_data(totp_code_key(sid)).data[:code]
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
def validate?(sid, code)
|
|
24
|
-
|
|
25
|
+
log.debug { "Validate TOTP code: key #{totp_code_key(sid)}, code: #{code}" }
|
|
25
26
|
result = write_data(totp_code_key(sid), code: code).data[:valid]
|
|
26
27
|
|
|
27
28
|
unless result
|
|
28
29
|
code = read_data(totp_code_key(sid)).data[:code]
|
|
29
|
-
|
|
30
|
+
log.debug { "Code is not valid, it should be #{code}" }
|
|
30
31
|
end
|
|
31
32
|
|
|
32
33
|
result
|
|
@@ -67,7 +68,7 @@ module Istox
|
|
|
67
68
|
config.ssl_verify = false
|
|
68
69
|
config.timeout = 60
|
|
69
70
|
else
|
|
70
|
-
|
|
71
|
+
log.info 'Vault token not found, OTP will not be able to use'
|
|
71
72
|
end
|
|
72
73
|
end
|
|
73
74
|
end
|
|
@@ -79,9 +80,6 @@ module Istox
|
|
|
79
80
|
|
|
80
81
|
def validate_otp(sid, otp)
|
|
81
82
|
::Istox::Vault::TOTP.validate?(sid, otp)
|
|
82
|
-
rescue StandardError => e
|
|
83
|
-
raise e
|
|
84
|
-
false
|
|
85
83
|
end
|
|
86
84
|
end
|
|
87
85
|
end
|
data/lib/istox/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: istox
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.104
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Siong Leng
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2020-01-01 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bunny
|
|
@@ -122,6 +122,34 @@ dependencies:
|
|
|
122
122
|
- - ">="
|
|
123
123
|
- !ruby/object:Gem::Version
|
|
124
124
|
version: '0'
|
|
125
|
+
- !ruby/object:Gem::Dependency
|
|
126
|
+
name: ougai
|
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
|
128
|
+
requirements:
|
|
129
|
+
- - ">="
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: '0'
|
|
132
|
+
type: :runtime
|
|
133
|
+
prerelease: false
|
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
- - ">="
|
|
137
|
+
- !ruby/object:Gem::Version
|
|
138
|
+
version: '0'
|
|
139
|
+
- !ruby/object:Gem::Dependency
|
|
140
|
+
name: awesome_print
|
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
|
142
|
+
requirements:
|
|
143
|
+
- - ">="
|
|
144
|
+
- !ruby/object:Gem::Version
|
|
145
|
+
version: '0'
|
|
146
|
+
type: :runtime
|
|
147
|
+
prerelease: false
|
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
149
|
+
requirements:
|
|
150
|
+
- - ">="
|
|
151
|
+
- !ruby/object:Gem::Version
|
|
152
|
+
version: '0'
|
|
125
153
|
- !ruby/object:Gem::Dependency
|
|
126
154
|
name: bundler
|
|
127
155
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -297,6 +325,7 @@ files:
|
|
|
297
325
|
- lib/istox/helpers/graphql_client.rb
|
|
298
326
|
- lib/istox/helpers/grpc_client.rb
|
|
299
327
|
- lib/istox/helpers/gruf_listener_hook.rb
|
|
328
|
+
- lib/istox/helpers/logger.rb
|
|
300
329
|
- lib/istox/helpers/message_service.rb
|
|
301
330
|
- lib/istox/helpers/my_open_struct.rb
|
|
302
331
|
- lib/istox/helpers/order_book_price_time.rb
|