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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2a4fdf1c4ef6e43e08853ee0921fe24c7a5055954f09e8994947d319f95e127f
4
- data.tar.gz: fb11c641a84a1f285ef85ea5ad532b3896d3db6971f65ce4c83ec0970c43ed9d
3
+ metadata.gz: 017e8b356e88bb9934ee5e01dce3ef6ce1ccdbf937bd5e8463ccd138c074ccee
4
+ data.tar.gz: 606737426dc9eaf9ca1b3d1f879b0dda17f46dacc89817cacf80990ce8a9fad2
5
5
  SHA512:
6
- metadata.gz: 4bec68b057c3f448e08f4958b7a51964cbda8b99a5689028107928e2b5a385914e78ff703d74ac43542e4f1c93b615be1c3a0a07a130c9fa4264df223be67fe9
7
- data.tar.gz: 9f5d910541029a58e96bb1ef1955671b0ba431bb68acdd59de4e8da7a957485a1e68ad92e79ef278f80dc13f640a9e5c81b148e2a62f4eec4e79ea29ca007b58
6
+ metadata.gz: 38bd1dcc56ce327d8c994f5743310cf3e34d3f70639513dcdfdcb0bd2a9b6a3c5cdef19e5b3b26c4ac43d8ee5742146cfb798b73be17fd4f9838bb14c7b5013c
7
+ data.tar.gz: d338cf9fe623a1a99481581c57142a5637899509f319407d489662ce8c511318d5a5747a8f091072f17a796bc51038382162278b89b5a72b0cd9c1a739e506e2
data/.rubocop.yml CHANGED
@@ -74,7 +74,7 @@ Metrics/ParameterLists:
74
74
  CountKeywordArgs: true
75
75
 
76
76
  Metrics/PerceivedComplexity:
77
- Max: 12
77
+ Max: 20
78
78
 
79
79
  Style/FrozenStringLiteralComment:
80
80
  Enabled: false
data/Gemfile.lock CHANGED
@@ -1,13 +1,15 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- istox (0.1.102)
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.2)
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.15.4)
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.1)
91
+ ffi (1.11.3)
89
92
  globalid (0.4.2)
90
93
  activesupport (>= 4.2.0)
91
- google-protobuf (3.9.1-universal-darwin)
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.6)
97
+ graphlient (0.3.7)
95
98
  faraday
96
99
  faraday_middleware
97
100
  graphql-client
98
- graphql (1.9.12)
99
- graphql-client (0.15.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.23.0-universal-darwin)
105
+ grpc (1.26.0)
103
106
  google-protobuf (~> 3.8)
104
107
  googleapis-common-protos-types (~> 1.0)
105
- grpc-tools (1.23.0)
106
- gruf (2.7.0)
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.0)
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.12.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
@@ -12,6 +12,7 @@ module Istox
12
12
  end
13
13
  end
14
14
 
15
+ require 'istox/helpers/logger'
15
16
  require 'istox/interfaces/chainhub/transaction'
16
17
  require 'istox/helpers/publisher'
17
18
  require 'istox/helpers/bunny_boot'
@@ -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
- puts 'Transaction doesn\'t belong to this backend, skipping...'
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
- puts 'Class not found, skipping...'
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.publish(
53
- 'amq.topic',
54
- model.class.name.gsub('::', '').underscore.to_s,
55
- data: {
56
- id: model.id,
57
- extra: model.handle_extra
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.publish(
62
- 'amq.topic',
63
- sid,
64
- data: {
65
- success: success,
66
- purpose: receipt.activity,
67
- message: receipt.message
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
- Rails.logger.warning "Unable to publish to frontend for receipt #{receipt.inspect},
79
+ log.warn "Unable to publish to frontend for receipt #{receipt.inspect},
72
80
  but will silently ignore the error"
73
- Rails.logger.warning e
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
- Rails.logger.warning "Unable to update resource_handled for receipt #{receipt.inspect},
87
+ log.warn "Unable to update resource_handled for receipt #{receipt.inspect},
80
88
  but will silently ignore the error"
81
- Rails.logger.warning e
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
- @@amqp_config_path = amqp_config_path
7
- ::Istox::Publisher.initialize!(amqp_config_path)
8
- connect
9
- end
9
+ @amqp_config_path = amqp_config_path
10
10
 
11
- def start_subscribe
12
- subscribe_to_queues
11
+ data
13
12
  end
14
13
 
15
- def connect
16
- connection = Bunny.new(data[:connect].symbolize_keys)
17
- connection.start
18
- $channel = connection.create_channel
19
- end
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
- protected
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
- private
31
+ #############################################################################################
32
+ ## INTERNAL METHODS START
33
+ ############################################################################################
58
34
 
59
- def read_file
60
- YAML.safe_load(ERB.new(File.read(@@amqp_config_path)).result)
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
- def data
64
- OpenStruct.new(read_file)
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 exchange(host_exchange, exchange_type)
68
- case exchange_type
69
- when :fanout
70
- $channel.fanout(host_exchange, durable: true)
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
- $channel.direct(host_exchange, durable: true)
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
- Rails.logger.debug "Querying Graphql host: #{host_type}, query: #{query}, variables: #{variables.inspect}"
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
- Rails.logger.debug "Graphql result: #{return_values.inspect}"
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
- Rails.logger.debug "Calling method in grpc method: #{method.inspect}, params: #{keyword_args.inspect}"
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
- Rails.logger.debug "Time taken for grpc execution: #{Time.now - t1} seconds"
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
- Rails.logger.debug "Result: #{return_values}"
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
- Rails.logger.debug 'Reinitiating to grpc host at ' + host_url
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
- Rails.logger.debug "Time taken for reinitiating grpc host: #{Time.now - t1} seconds"
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
- class GrufListenerHook < ::Gruf::Hooks::Base
3
- def before_server_start(server:)
4
- # do my thing before the server starts
2
+ class GrufListenerHook < ::Gruf::Hooks::Base
3
+ def before_server_start(server:)
4
+ # do my thing before the server starts
5
5
 
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
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
- 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
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
- 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
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
- 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
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
- 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
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
- private
39
+ private
40
40
 
41
- def publish(type, payload)
42
- ::Istox::Publisher.publish('message', "#{type}.message", payload)
43
- end
44
- end
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
- def initialize!(amqp_config_path)
5
- @@amqp_config_path = amqp_config_path
6
- end
7
-
8
- def publish(exchange, routing_key, message, persistent: true)
9
- Rails.logger.debug 'Before publish retrieve data..'
10
- durable = data.fetch('publish')[exchange]['durable']
11
- Rails.logger.debug "Publishing message: #{message} with exchange: #{exchange} routing key: #{routing_key}"
12
- enqueue do
13
- $channel
14
- .direct(exchange, durable: durable)
15
- .publish(message.to_json, routing_key: routing_key, durable: durable, persistent: persistent)
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
- def publish_to_fanout(exchange, message, persistent: true)
20
- Rails.logger.debug 'Before publish retrieve data..'
21
- durable = data.fetch('publish')[exchange]['durable']
22
- enqueue do
23
- $channel
24
- .fanout(exchange, durable: durable)
25
- .publish(message.to_json, durable: durable, persistent: persistent)
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 enqueue
32
- initialize_channel! unless !!$channel
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
- def initialize_channel!
37
- ::Istox::BunnyBoot.connect
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
- YAML.safe_load(ERB.new(File.read(@@amqp_config_path)).result)
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
@@ -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
- Rails.logger.debug { "Generate vault TOTP for key #{totp_key(sid).inspect}" }
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
- Rails.logger.debug { "Generate 6-digit OTP code: key #{totp_code_key(sid)}" }
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
- Rails.logger.debug { "Validate TOTP code: key #{totp_code_key(sid)}, code: #{code}" }
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
- Rails.logger.debug { "Code is not valid, it should be #{code}" }
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
- Rails.logger.info 'Vault token not found, OTP will not be able to use'
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
@@ -1,3 +1,3 @@
1
1
  module Istox
2
- VERSION = '0.1.103'.freeze
2
+ VERSION = '0.1.104'.freeze
3
3
  end
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.103
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: 2019-12-02 00:00:00.000000000 Z
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