sidekiq-bus 0.8.2 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2c633c91c5b55a5e08ec80f73ee6a174df07d59c
4
- data.tar.gz: '00095d6bcdc1407137cab9051990b91f359df304'
3
+ metadata.gz: 1f2be4d5e020e0a15769b9b1afcf3f7ed36d1d6b
4
+ data.tar.gz: 9f1d638cf9f47eb1afa87bb21b8141d2baa27f10
5
5
  SHA512:
6
- metadata.gz: a4dcb3d6a379ceda40fe1da42c6cdb00662b85f37bbfcf9010ed7303883d8e44a9f43f9ab9c587793503ce4ade15a09f1c23cbdd6ec07ae5f4d85af0ce8ced04
7
- data.tar.gz: 2631baff2bc6724686516f34cc04955fef78884228566f961b2f51dd069130bf67c65a562200299e833b241d8ed18c6e7a17636768bfd6310d318de1c8997c0f
6
+ metadata.gz: 1f9783a99bf3c8b0c6fb2df111362d77507d8d245112ec66707e82ee4c172bb78cc28f5e32026adbbb3ca4e1c0f11fc15c27f67cbd79d32545e40b1bb48a424b
7
+ data.tar.gz: 66b88100b6068b47ce2f28080eeb4eca7ce5ef669cef9bd71cf195893c43c88a976ccf4040cf0e08d14a45031f4195725079e6da29f1cc5e14a6b03eec3dfb1f
@@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.9.0] - 2019-12-03
10
+
11
+ ### Added
12
+ - Tab in sidekiq web ui for bus info
13
+
9
14
  ### [0.8.2] - 2019-08-06
10
15
 
11
16
  ### Fixed
@@ -3,6 +3,7 @@
3
3
  require 'queue-bus'
4
4
  require 'sidekiq_bus/adapter'
5
5
  require 'sidekiq_bus/version'
6
+ require 'sidekiq_bus/server'
6
7
  require 'sidekiq_bus/middleware/retry'
7
8
 
8
9
  module SidekiqBus
@@ -0,0 +1,139 @@
1
+ require 'sidekiq/web'
2
+
3
+ module SidekiqBus
4
+ module Server
5
+ def self.registered(app)
6
+ app.get('/bus') do
7
+ # you can define @instance_variables for passing into template
8
+ # Sidekiq uses erb for its templates so you should do it aswell
9
+ erb File.read(File.join(File.dirname(__FILE__), "server/views/bus.erb"))
10
+ end
11
+
12
+ app.post '/bus/unsubscribe' do
13
+ bus_app = ::QueueBus::Application.new(params[:name]).unsubscribe
14
+ redirect "#{root_path}bus"
15
+ end
16
+ end
17
+
18
+ class Helpers
19
+ class << self
20
+ def parse_query(query_string)
21
+ has_open_brace = query_string.include?("{")
22
+ has_close_brace = query_string.include?("}")
23
+ has_multiple_lines = query_string.include?("\n")
24
+ has_colon = query_string.include?(":")
25
+ has_comma = query_string.include?(",")
26
+ has_quote = query_string.include?("\"")
27
+
28
+ exception = nil
29
+
30
+ # first let's see if it parses
31
+ begin
32
+ query_attributes = JSON.parse(query_string)
33
+ raise "Not a JSON Object" unless query_attributes.is_a?(Hash)
34
+ rescue Exception => e
35
+ exception = e
36
+ end
37
+ return query_attributes unless exception
38
+
39
+ if query_attributes
40
+ # it parsed but it's something else
41
+ if query_attributes.is_a?(Array) && query_attributes.length == 1
42
+ # maybe it's the thing from the queue
43
+ json_string = query_attributes.first
44
+ fixed = JSON.parse(json_string) rescue nil
45
+ return fixed if fixed
46
+ end
47
+
48
+ # something else?
49
+ raise exception
50
+ end
51
+
52
+ if !has_open_brace && !has_close_brace
53
+ # maybe they just forgot the braces
54
+ fixed = JSON.parse("{ #{query_string} }") rescue nil
55
+ return fixed if fixed
56
+ end
57
+
58
+ if !has_open_brace
59
+ # maybe they just forgot the braces
60
+ fixed = JSON.parse("{ #{query_string}") rescue nil
61
+ return fixed if fixed
62
+ end
63
+
64
+ if !has_close_brace
65
+ # maybe they just forgot the braces
66
+ fixed = JSON.parse("#{query_string} }") rescue nil
67
+ return fixed if fixed
68
+ end
69
+
70
+ if !has_multiple_lines && !has_colon && !has_open_brace && !has_close_brace
71
+ # we say they just put a bus_event type here, so help them out
72
+ return {"bus_event_type" => query_string, "more_here" => true}
73
+ end
74
+
75
+ if has_colon && !has_quote
76
+ # maybe it's some search syntax like this: field: value other: true, etc
77
+ # maybe use something like this later: https://github.com/dxwcyber/search-query-parser
78
+
79
+ # quote all the strings, (simply) tries to avoid integers
80
+ test_query = query_string.gsub(/([a-zA-z]\w*)/,'"\0"')
81
+ if !has_comma
82
+ test_query.gsub!("\n", ",\n")
83
+ end
84
+ if !has_open_brace && !has_close_brace
85
+ test_query = "{ #{test_query} }"
86
+ end
87
+
88
+ fixed = JSON.parse(test_query) rescue nil
89
+ return fixed if fixed
90
+ end
91
+
92
+ if has_open_brace && has_close_brace
93
+ # maybe the whole thing is a hash output from a hash.inspect log
94
+ ruby_hash_text = query_string.clone
95
+ # https://stackoverflow.com/questions/1667630/how-do-i-convert-a-string-object-into-a-hash-object
96
+ # Transform object string symbols to quoted strings
97
+ ruby_hash_text.gsub!(/([{,]\s*):([^>\s]+)\s*=>/, '\1"\2"=>')
98
+ # Transform object string numbers to quoted strings
99
+ ruby_hash_text.gsub!(/([{,]\s*)([0-9]+\.?[0-9]*)\s*=>/, '\1"\2"=>')
100
+ # Transform object value symbols to quotes strings
101
+ ruby_hash_text.gsub!(/([{,]\s*)(".+?"|[0-9]+\.?[0-9]*)\s*=>\s*:([^,}\s]+\s*)/, '\1\2=>"\3"')
102
+ # Transform array value symbols to quotes strings
103
+ ruby_hash_text.gsub!(/([\[,]\s*):([^,\]\s]+)/, '\1"\2"')
104
+ # fix up nil situation
105
+ ruby_hash_text.gsub!(/=>nil/, '=>null')
106
+ # Transform object string object value delimiter to colon delimiter
107
+ ruby_hash_text.gsub!(/([{,]\s*)(".+?"|[0-9]+\.?[0-9]*)\s*=>/, '\1\2:')
108
+ fixed = JSON.parse(ruby_hash_text) rescue nil
109
+ return fixed if fixed
110
+ end
111
+
112
+ raise exception
113
+ end
114
+
115
+ def sort_query(query_attributes)
116
+ query_attributes.each do |key, value|
117
+ if value.is_a?(Hash)
118
+ query_attributes[key] = sort_query(value)
119
+ end
120
+ end
121
+ query_attributes.sort_by { |key| key }.to_h
122
+ end
123
+
124
+ def query_subscriptions(app, query_attributes)
125
+ # TODO: all of this can move to method in queue-bus to replace event_display_tuples
126
+ if query_attributes
127
+ subscriptions = app.subscription_matches(query_attributes)
128
+ else
129
+ subscriptions = app.send(:subscriptions).all
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
136
+
137
+ Sidekiq::Web.register SidekiqBus::Server
138
+ Sidekiq::Web.locales << File.expand_path(File.dirname(__FILE__) + "/web/locales")
139
+ Sidekiq::Web.tabs['Bus'] = 'bus'
@@ -0,0 +1,202 @@
1
+
2
+ <script LANGUAGE="JavaScript">
3
+ <!--
4
+ function confirmSubmit()
5
+ {
6
+ var agree=confirm("Are you sure you wish to continue?");
7
+ if (agree)
8
+ return true ;
9
+ else
10
+ return false ;
11
+ }
12
+
13
+ function setSample() {
14
+ var text = document.getElementById("query_attributes").textContent;
15
+ var textArea = document.getElementById('querytext');
16
+ textArea.value = text;
17
+ return false;
18
+ }
19
+ // -->
20
+ </script>
21
+
22
+ <%
23
+ app_hash = {}
24
+ class_hash = {}
25
+ event_hash = {}
26
+ query_string = params[:query].to_s.strip
27
+
28
+ query_attributes = nil
29
+ query_error = nil
30
+ if query_string.length > 0
31
+ begin
32
+ query_attributes = ::SidekiqBus::Server::Helpers.parse_query(query_string)
33
+ raise "Not a JSON Object" unless query_attributes.is_a?(Hash)
34
+ rescue Exception => e
35
+ query_attributes = nil
36
+ query_error = e.message
37
+ end
38
+
39
+ if query_attributes
40
+ # sort keys for display
41
+ query_attributes = ::SidekiqBus::Server::Helpers.sort_query(query_attributes)
42
+ end
43
+ end
44
+
45
+ # collect each differently
46
+ ::QueueBus::Application.all.each do |app|
47
+ app_key = app.app_key
48
+
49
+ subscriptions = ::SidekiqBus::Server::Helpers.query_subscriptions(app, query_attributes)
50
+ subscriptions.each do |sub|
51
+ class_name = sub.class_name
52
+ queue = sub.queue_name
53
+ filters = sub.matcher.filters
54
+ sub_key = sub.key
55
+
56
+ if filters["bus_event_type"]
57
+ event = filters["bus_event_type"]
58
+ else
59
+ event = "see filter"
60
+ end
61
+
62
+ app_hash[app_key] ||= []
63
+ app_hash[app_key] << [sub_key, event, class_name, queue, filters]
64
+
65
+ class_hash[class_name] ||= []
66
+ class_hash[class_name] << [app_key, sub_key, event, queue, filters]
67
+
68
+ event_hash[event] ||= []
69
+ event_hash[event] << [app_key, sub_key, class_name, queue, filters]
70
+ end
71
+ end
72
+
73
+ # sort each list item by secondary label
74
+ class_hash.each do |_, array|
75
+ array.sort!{ |a,b| a.first <=> b.first }
76
+ end
77
+ event_hash.each do |_, array|
78
+ array.sort!{ |a,b| a.first <=> b.first }
79
+ end
80
+
81
+ # helper to display either
82
+ def display_row(name, val, button=nil, first=false)
83
+ form = ""
84
+ if button
85
+ text, url = button
86
+ form = "<form method='POST' action='#{url}' style='float:left; padding:0 5px 0 0;margin:0;'>#{csrf_tag}<input type='submit' name='' value='#{h(text)}' style='padding:0;margin:0;' onclick=\"return confirmSubmit();\"/><input type='hidden' name='name' value='#{h(name)}' /></form>"
87
+ end
88
+
89
+ if !val
90
+ out = "<td>&nbsp;</td><td>&nbsp;</td>"
91
+ else
92
+ one, two, three, queue, filters = val
93
+ out = "<td>#{h(one)}</td><td>#{h(two)}</td><td>#{h(three)}</td><td><a href='#{"queues/#{queue}"}'>#{h(queue)}</a></td>"
94
+ out << "<td>#{h(::QueueBus::Util.encode(filters).gsub(/\"bus_special_value_(\w+)\"/){ "(#{$1})" }).gsub(" ", "&nbsp;").gsub('&quot;,&quot;', '&quot;, &quot;')}</td>"
95
+ end
96
+
97
+ if first
98
+ "<tr><td>#{h(name)}#{form}</td>#{out}</tr>\n"
99
+ else
100
+ "<tr><td>&nbsp;</td>#{out}</tr>\n"
101
+ end
102
+ end
103
+
104
+ def output_hash(hash, action=nil)
105
+ out = ""
106
+ hash.keys.sort.each do |item|
107
+ display = hash[item]
108
+ first = display.shift
109
+ out << display_row(item, first, action, true)
110
+ display.each do |val|
111
+ out << display_row(item, val, action)
112
+ end
113
+ end
114
+ out
115
+ end
116
+ %>
117
+
118
+ <h1 class='wi'>Sample Event</h1>
119
+ <p class='intro'>Enter JSON of an event to see applicable subscriptions.</p>
120
+ <div style="text-align: center;width:700px;">
121
+ -<form method="GET" action="<%= "bus" %>" style="float:none;padding:0;margin:0;">
122
+ <textarea id="querytext" name="query" style="padding: 10px;height:150px;width:700px;font-size:14px;font-family:monospace"><%=
123
+ h(query_string)
124
+ %></textarea>
125
+ <br/>
126
+ <button onclick="window.location.href = '<%= "bus" %>'; return false;">Clear</button>
127
+ <input type="submit" name="" value="Filter results to this event"/>
128
+ </form>
129
+ </div>
130
+
131
+ <% if query_error %>
132
+ <blockquote><pre style="text-align:left;font-family:monospace;margin:5px 0 5px 0;padding:10px;background:#f2dede;color:#a94442;"><code><%=
133
+ h(query_error.strip)
134
+ %></code></pre></blockquote>
135
+ <% end %>
136
+ <% if query_attributes %>
137
+ <blockquote><pre style="text-align:left;font-family:monospace;margin:5px 0 5px 0;padding:10px;background:#dff0d8;color:#3c763d;"><code id="query_attributes"><%=
138
+ h(JSON.pretty_generate(query_attributes).strip)
139
+ %></code></pre></blockquote>
140
+ <div style="text-align:right;">
141
+ <button onclick="return setSample();">Set Sample</button>
142
+ </div>
143
+ <% end %>
144
+
145
+ <hr/>
146
+
147
+ <h1 class='wi'>Applications</h1>
148
+ <p class='intro'>The apps below have registered the given classes and queues.</p>
149
+ <table class='table-striped table-bordered'>
150
+ <thead class="thead-dark">
151
+ <tr>
152
+ <th>App Key</th>
153
+ <th>Subscription Key</th>
154
+ <th>Event Type</th>
155
+ <th>Class Name</th>
156
+ <th>Queue</th>
157
+ <th>Filters</th>
158
+ </tr>
159
+ </thead>
160
+
161
+ <%= output_hash(app_hash, query_attributes ? false : ["Unsubscribe", "bus/unsubscribe"]) %>
162
+ </table>
163
+
164
+ <p>&nbsp;</p>
165
+
166
+ <h1 class='wi'>Events</h1>
167
+ <p class='intro'>The events below have been registered by the given applications and queues.</p>
168
+
169
+ <table class='table-striped table-bordered'>
170
+ <thead class="thead-dark">
171
+ <tr>
172
+ <th>Event Type</th>
173
+ <th>App Key</th>
174
+ <th>Subscription Key</th>
175
+ <th>Class Name</th>
176
+ <th>Queue</th>
177
+ <th>Filters</th>
178
+ </tr>
179
+ </thead>
180
+ <%= output_hash(event_hash, false) %>
181
+ </table>
182
+
183
+
184
+
185
+ <p>&nbsp;</p>
186
+
187
+ <h1 class='wi'>Classes</h1>
188
+ <p class='intro'>The classes below have been registered by the given applications and queues.</p>
189
+ <table class='table-striped table-bordered'>
190
+ <thead class="thead-dark">
191
+ <tr>
192
+ <th>Class Name</th>
193
+ <th>App Key</th>
194
+ <th>Subscription Key</th>
195
+ <th>Event Type</th>
196
+ <th>Queue</th>
197
+ <th>Filters</th>
198
+ </tr>
199
+ </thead>
200
+ <%= output_hash(class_hash, false) %>
201
+ </table>
202
+
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SidekiqBus
4
- VERSION = '0.8.2'
4
+ VERSION = '0.9.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq-bus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.2
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Leonard
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-08-06 00:00:00.000000000 Z
11
+ date: 2019-12-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: queue-bus
@@ -184,6 +184,8 @@ files:
184
184
  - lib/sidekiq-bus.rb
185
185
  - lib/sidekiq_bus/adapter.rb
186
186
  - lib/sidekiq_bus/middleware/retry.rb
187
+ - lib/sidekiq_bus/server.rb
188
+ - lib/sidekiq_bus/server/views/bus.erb
187
189
  - lib/sidekiq_bus/tasks.rb
188
190
  - lib/sidekiq_bus/version.rb
189
191
  - sidekiq-bus.gemspec