eventhub-processor2 1.26.2 → 1.27.1
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/CHANGELOG.md +13 -0
- data/README.md +10 -14
- data/eventhub-processor2.gemspec +1 -1
- data/example/config/example.json +15 -0
- data/example/config/receiver.json +4 -1
- data/example/config/router.json +4 -1
- data/example/example.rb +4 -0
- data/example/publisher.rb +5 -8
- data/example/receiver.rb +4 -0
- data/example/router.rb +4 -0
- data/lib/eventhub/actor_heartbeat.rb +1 -7
- data/lib/eventhub/actor_listener_http.rb +5 -4
- data/lib/eventhub/actor_publisher.rb +1 -7
- data/lib/eventhub/assets/app.css +79 -1
- data/lib/eventhub/configuration.rb +1 -5
- data/lib/eventhub/docs_renderer.rb +144 -27
- data/lib/eventhub/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 902f7f788754624f1f2bb0aaf604cbb40950c0c214e58d0a340d6bd9d2f847a9
|
|
4
|
+
data.tar.gz: '092db4a1078ccc754bae694153c20a87e26218a731d88e1b37863d93cb900a4f'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8d6993b13c319ad59d1b2a65212cc7c402044117d530d35f2387ca20db038d4cc6ab44b8a84e4a16dd99db3693c2f057203d81e61d6a4c51240068de08dad1c2
|
|
7
|
+
data.tar.gz: 1474a5bddd07a229101a2fec20bafb22252437d33f51c6c3ffdf193ba206f2125ff965890d2d450121a7994fa7c879dc2ccc7f721b2a1ce5c98d383f641c4e37
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog of EventHub::Processor2
|
|
2
2
|
|
|
3
|
+
# 1.27.1 / 2026-04-08
|
|
4
|
+
|
|
5
|
+
* Read markdown files (README, CHANGELOG) as UTF-8 to correctly render Unicode characters (e.g. umlauts, accented characters, emojis)
|
|
6
|
+
|
|
7
|
+
# 1.27.0 / 2026-04-01
|
|
8
|
+
|
|
9
|
+
* Adapt to Bunny 3.0 publisher confirms: use `confirm_select(tracking: true)` for automatic backpressure, remove manual `wait_for_confirms` calls
|
|
10
|
+
* Remove `:configuration` from default HTTP resources to prevent automatic exposure of sensitive config on upgrade (opt-in via `http_resources` method)
|
|
11
|
+
* Improve configuration page: compact rendering for nested hashes and arrays, show `(not set)` for empty values, add client-side filter with reset button, visual distinction for top-level sections
|
|
12
|
+
* Fix deprecation logic to only warn when `heartbeat.*` and `http.*` values actually differ; remove defaults from deprecated `heartbeat` config block
|
|
13
|
+
* Fix example processors: add unique HTTP ports, create missing `data/` directory in publisher
|
|
14
|
+
* Fix flaky sleeper specs by widening timing tolerance and using idiomatic RSpec `be_within` matcher
|
|
15
|
+
|
|
3
16
|
# 1.26.2 / 2026-03-25
|
|
4
17
|
|
|
5
18
|
* Change default `http.bind_address` from `localhost` to `0.0.0.0` for container compatibility (ECS, Docker, K8s)
|
data/README.md
CHANGED
|
@@ -321,7 +321,7 @@ Resources are mounted under the `base_path`:
|
|
|
321
321
|
- `{base_path}/heartbeat` - Health check
|
|
322
322
|
- `{base_path}/version` - Version info as JSON
|
|
323
323
|
- `{base_path}/docs` - README documentation as HTML
|
|
324
|
-
- `{base_path}/docs/configuration` - Configuration as HTML table
|
|
324
|
+
- `{base_path}/docs/configuration` - Configuration as HTML table (opt-in, see [Enabling Resources](#enabling-resources))
|
|
325
325
|
- `{base_path}/docs/changelog` - CHANGELOG as HTML
|
|
326
326
|
- `{base_path}/assets/*` - Static assets (CSS, images)
|
|
327
327
|
|
|
@@ -401,6 +401,8 @@ GET {base_path}/docs
|
|
|
401
401
|
|
|
402
402
|
**Response:** `200 OK` with HTML page
|
|
403
403
|
|
|
404
|
+
Markdown files are read as UTF-8, so Unicode characters (umlauts, accented characters, emojis, etc.) are rendered correctly.
|
|
405
|
+
|
|
404
406
|
By default, looks for `README.md` in the current directory, then `doc/README.md`. You can customize the path via configuration:
|
|
405
407
|
|
|
406
408
|
```json
|
|
@@ -469,7 +471,7 @@ GET {base_path}/docs/configuration
|
|
|
469
471
|
|
|
470
472
|
**Response:** `200 OK` with HTML page
|
|
471
473
|
|
|
472
|
-
By default, the following keys are redacted: `password`, `secret`, `token`, `api_key`, `credential`. You can customize the list by defining a `sensitive_keys` method in your processor:
|
|
474
|
+
By default, the following keys are redacted: `password`, `secret`, `token`, `api_key`, `credential`, `username`, `user`, `login`. You can customize the list by defining a `sensitive_keys` method in your processor:
|
|
473
475
|
|
|
474
476
|
```ruby
|
|
475
477
|
# Override the entire list
|
|
@@ -497,28 +499,22 @@ class MyProcessor < EventHub::Processor2
|
|
|
497
499
|
end
|
|
498
500
|
```
|
|
499
501
|
|
|
500
|
-
###
|
|
502
|
+
### Enabling Resources
|
|
501
503
|
|
|
502
|
-
By default,
|
|
504
|
+
By default, the following HTTP resources are enabled: `:heartbeat`, `:version`, `:docs`, and `:changelog`. The `:configuration` resource is **disabled by default** because it displays server configuration which may contain sensitive values. Although passwords, tokens, and keys are automatically redacted, we prefer a secure-by-default approach where processors must explicitly opt in to exposing configuration.
|
|
503
505
|
|
|
504
|
-
|
|
505
|
-
class MyProcessor < EventHub::Processor2
|
|
506
|
-
def http_resources
|
|
507
|
-
[:heartbeat, :version, :docs, :changelog, :configuration] # default: all enabled
|
|
508
|
-
end
|
|
509
|
-
end
|
|
510
|
-
```
|
|
511
|
-
|
|
512
|
-
To disable the configuration page for example:
|
|
506
|
+
To enable the configuration page, define an `http_resources` method in your processor:
|
|
513
507
|
|
|
514
508
|
```ruby
|
|
515
509
|
class MyProcessor < EventHub::Processor2
|
|
516
510
|
def http_resources
|
|
517
|
-
[:heartbeat, :version, :docs, :changelog]
|
|
511
|
+
[:heartbeat, :version, :docs, :changelog, :configuration]
|
|
518
512
|
end
|
|
519
513
|
end
|
|
520
514
|
```
|
|
521
515
|
|
|
516
|
+
You can also use `http_resources` to disable any of the default resources. The navbar adapts automatically.
|
|
517
|
+
|
|
522
518
|
### Customizing Footer
|
|
523
519
|
|
|
524
520
|
The documentation pages display company name, version, and environment in the footer. Company name defaults to "Novartis" but can be customized by defining a `company_name` method in your processor:
|
data/eventhub-processor2.gemspec
CHANGED
|
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
|
|
|
24
24
|
|
|
25
25
|
spec.add_dependency "celluloid", "~> 0.18"
|
|
26
26
|
spec.add_dependency "webrick", "~> 1.8"
|
|
27
|
-
spec.add_dependency "bunny", "~>
|
|
27
|
+
spec.add_dependency "bunny", "~> 3.0"
|
|
28
28
|
spec.add_dependency "eventhub-components", "~> 0.4"
|
|
29
29
|
spec.add_dependency "base64", "~> 0.3.0"
|
|
30
30
|
spec.add_dependency "logger", "~> 1.6"
|
data/example/config/router.json
CHANGED
data/example/example.rb
CHANGED
|
@@ -6,6 +6,10 @@ module EventHub
|
|
|
6
6
|
"1.0.0" # define your version
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
+
def http_resources
|
|
10
|
+
[:heartbeat, :version, :docs, :changelog, :configuration]
|
|
11
|
+
end
|
|
12
|
+
|
|
9
13
|
def handle_message(message, args = {})
|
|
10
14
|
# deal with your parsed EventHub message
|
|
11
15
|
# message.class => EventHub::Message
|
data/example/publisher.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require "bunny"
|
|
2
2
|
require "celluloid"
|
|
3
|
+
require "fileutils"
|
|
3
4
|
require "json"
|
|
4
5
|
require "securerandom"
|
|
5
6
|
require "eventhub/components"
|
|
@@ -38,6 +39,7 @@ module Publisher
|
|
|
38
39
|
@files_sent = 0
|
|
39
40
|
|
|
40
41
|
@filename = "data/store.json"
|
|
42
|
+
FileUtils.mkdir_p(File.dirname(@filename))
|
|
41
43
|
if File.exist?(@filename)
|
|
42
44
|
cleanup
|
|
43
45
|
else
|
|
@@ -119,7 +121,7 @@ module Publisher
|
|
|
119
121
|
logger: Logger.new(File::NULL))
|
|
120
122
|
@connection.start
|
|
121
123
|
@channel = @connection.create_channel
|
|
122
|
-
@channel.confirm_select
|
|
124
|
+
@channel.confirm_select(tracking: true)
|
|
123
125
|
@exchange = @channel.direct("example.outbound", durable: true)
|
|
124
126
|
end
|
|
125
127
|
|
|
@@ -135,13 +137,8 @@ module Publisher
|
|
|
135
137
|
Publisher.logger.info("[#{id}] - Message/File created")
|
|
136
138
|
|
|
137
139
|
@exchange.publish(data, persistent: true)
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
Celluloid::Actor[:transaction_store]&.stop(id)
|
|
141
|
-
Publisher&.logger&.info("[#{id}] - Message sent")
|
|
142
|
-
else
|
|
143
|
-
Publisher&.logger&.error("[#{id}] - Published message not confirmed")
|
|
144
|
-
end
|
|
140
|
+
Celluloid::Actor[:transaction_store]&.stop(id)
|
|
141
|
+
Publisher&.logger&.info("[#{id}] - Message sent")
|
|
145
142
|
end
|
|
146
143
|
end
|
|
147
144
|
|
data/example/receiver.rb
CHANGED
data/example/router.rb
CHANGED
|
@@ -38,15 +38,9 @@ module EventHub
|
|
|
38
38
|
connection = create_bunny_connection
|
|
39
39
|
connection.start
|
|
40
40
|
channel = connection.create_channel
|
|
41
|
-
channel.confirm_select
|
|
41
|
+
channel.confirm_select(tracking: true)
|
|
42
42
|
exchange = channel.direct(EventHub::EH_X_INBOUND, durable: true)
|
|
43
43
|
exchange.publish(message, persistent: true)
|
|
44
|
-
success = channel.wait_for_confirms
|
|
45
|
-
|
|
46
|
-
unless success
|
|
47
|
-
raise "Published heartbeat message has " \
|
|
48
|
-
"not been confirmed by the server"
|
|
49
|
-
end
|
|
50
44
|
ensure
|
|
51
45
|
connection&.close
|
|
52
46
|
end
|
|
@@ -10,7 +10,7 @@ module EventHub
|
|
|
10
10
|
include Helper
|
|
11
11
|
|
|
12
12
|
DEFAULT_VERSION = "?.?.?"
|
|
13
|
-
DEFAULT_HTTP_RESOURCES = [:heartbeat, :version, :docs, :changelog
|
|
13
|
+
DEFAULT_HTTP_RESOURCES = [:heartbeat, :version, :docs, :changelog].freeze
|
|
14
14
|
CONTENT_TYPES = {
|
|
15
15
|
".css" => "text/css",
|
|
16
16
|
".svg" => "image/svg+xml",
|
|
@@ -183,16 +183,17 @@ module EventHub
|
|
|
183
183
|
private
|
|
184
184
|
|
|
185
185
|
def http_config(key)
|
|
186
|
-
#
|
|
186
|
+
# Prefer deprecated heartbeat config for backward compatibility,
|
|
187
|
+
# fall back to http config. Only warn when values actually differ.
|
|
187
188
|
heartbeat_value = EventHub::Configuration.server.dig(:heartbeat, key)
|
|
188
189
|
http_value = EventHub::Configuration.server.dig(:http, key)
|
|
189
190
|
|
|
190
|
-
if heartbeat_value && http_value !=
|
|
191
|
+
if heartbeat_value && http_value && heartbeat_value != http_value
|
|
191
192
|
EventHub.logger.warn("[DEPRECATION] heartbeat.#{key} is deprecated. Please use http.#{key} instead.")
|
|
192
193
|
return heartbeat_value
|
|
193
194
|
end
|
|
194
195
|
|
|
195
|
-
http_value
|
|
196
|
+
http_value || heartbeat_value
|
|
196
197
|
end
|
|
197
198
|
|
|
198
199
|
def resource_enabled?(name)
|
|
@@ -25,7 +25,7 @@ module EventHub
|
|
|
25
25
|
exchange_name = args[:exchange_name] || EH_X_INBOUND
|
|
26
26
|
|
|
27
27
|
channel = @connection.create_channel
|
|
28
|
-
channel.confirm_select
|
|
28
|
+
channel.confirm_select(tracking: true)
|
|
29
29
|
exchange = channel.direct(exchange_name, durable: true)
|
|
30
30
|
|
|
31
31
|
publish_options = {persistent: true}
|
|
@@ -33,12 +33,6 @@ module EventHub
|
|
|
33
33
|
publish_options[:correlation_id] = correlation_id if correlation_id
|
|
34
34
|
|
|
35
35
|
exchange.publish(message, publish_options)
|
|
36
|
-
success = channel.wait_for_confirms
|
|
37
|
-
|
|
38
|
-
unless success
|
|
39
|
-
raise "Published message from Listener actor " \
|
|
40
|
-
"has not been confirmed by the server"
|
|
41
|
-
end
|
|
42
36
|
ensure
|
|
43
37
|
channel&.close
|
|
44
38
|
end
|
data/lib/eventhub/assets/app.css
CHANGED
|
@@ -94,6 +94,54 @@ body {
|
|
|
94
94
|
width: auto;
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
/* Config filter */
|
|
98
|
+
.config-filter {
|
|
99
|
+
margin-bottom: 1rem;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.config-filter-row {
|
|
103
|
+
display: flex;
|
|
104
|
+
align-items: center;
|
|
105
|
+
max-width: 400px;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.config-filter .input {
|
|
109
|
+
flex: 1;
|
|
110
|
+
padding: 0.5rem 0.75rem;
|
|
111
|
+
font-size: 0.95rem;
|
|
112
|
+
border: 1px solid #dbdbdb;
|
|
113
|
+
border-radius: 4px 0 0 4px;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.config-filter .input:focus {
|
|
117
|
+
border-color: hsl(212, 55%, 48%);
|
|
118
|
+
outline: none;
|
|
119
|
+
box-shadow: 0 0 0 2px hsla(212, 55%, 48%, 0.2);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.config-filter-reset {
|
|
123
|
+
padding: 0 0.75rem;
|
|
124
|
+
font-size: 1.1rem;
|
|
125
|
+
border: 1px solid #dbdbdb;
|
|
126
|
+
border-left: none;
|
|
127
|
+
border-radius: 0 4px 4px 0;
|
|
128
|
+
background: #f5f5f5;
|
|
129
|
+
color: #7a7a7a;
|
|
130
|
+
cursor: pointer;
|
|
131
|
+
align-self: stretch;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.config-filter-reset:hover {
|
|
135
|
+
background: #e8e8e8;
|
|
136
|
+
color: #363636;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.config-filter-count {
|
|
140
|
+
margin-top: 0.25rem;
|
|
141
|
+
font-size: 0.85rem;
|
|
142
|
+
color: #7a7a7a;
|
|
143
|
+
}
|
|
144
|
+
|
|
97
145
|
/* Config table */
|
|
98
146
|
.config-table thead th {
|
|
99
147
|
background-color: #1a1a1a !important;
|
|
@@ -107,6 +155,10 @@ body {
|
|
|
107
155
|
font-weight: 600;
|
|
108
156
|
}
|
|
109
157
|
|
|
158
|
+
.config-table .is-section-top td {
|
|
159
|
+
background-color: #d5d5d5;
|
|
160
|
+
}
|
|
161
|
+
|
|
110
162
|
.config-table tbody tr:not(.is-section):hover td {
|
|
111
163
|
background-color: hsl(212, 55%, 93%) !important;
|
|
112
164
|
}
|
|
@@ -116,11 +168,37 @@ body {
|
|
|
116
168
|
padding-left: 2rem;
|
|
117
169
|
}
|
|
118
170
|
|
|
119
|
-
.config-table .redacted
|
|
171
|
+
.config-table .redacted,
|
|
172
|
+
.config-table .not-set {
|
|
120
173
|
color: #b5b5b5;
|
|
121
174
|
font-style: italic;
|
|
122
175
|
}
|
|
123
176
|
|
|
177
|
+
.config-array {
|
|
178
|
+
list-style: none;
|
|
179
|
+
margin: 0;
|
|
180
|
+
padding: 0;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.config-array > li {
|
|
184
|
+
padding: 0.25rem 0;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.config-array > li + li {
|
|
188
|
+
border-top: 1px solid #e8e8e8;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.config-subtable {
|
|
192
|
+
margin: 0 !important;
|
|
193
|
+
font-size: 0.9rem;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.config-subtable td:first-child {
|
|
197
|
+
font-weight: 600;
|
|
198
|
+
white-space: nowrap;
|
|
199
|
+
width: 1%;
|
|
200
|
+
}
|
|
201
|
+
|
|
124
202
|
/* Footer */
|
|
125
203
|
.footer {
|
|
126
204
|
padding: 1.5rem;
|
|
@@ -147,11 +147,7 @@ module EventHub
|
|
|
147
147
|
}
|
|
148
148
|
},
|
|
149
149
|
# deprecated: use http instead (kept for backward compatibility)
|
|
150
|
-
heartbeat: {
|
|
151
|
-
bind_address: "0.0.0.0",
|
|
152
|
-
port: 8080,
|
|
153
|
-
path: "/svc/#{@name}/heartbeat"
|
|
154
|
-
}
|
|
150
|
+
heartbeat: {}
|
|
155
151
|
},
|
|
156
152
|
processor: {
|
|
157
153
|
heartbeat_cycle_in_s: 300,
|
|
@@ -10,7 +10,7 @@ module EventHub
|
|
|
10
10
|
DEFAULT_CHANGELOG_LOCATIONS = ["CHANGELOG.md", "doc/CHANGELOG.md"].freeze
|
|
11
11
|
DEFAULT_COMPANY_NAME = "Novartis"
|
|
12
12
|
|
|
13
|
-
DEFAULT_HTTP_RESOURCES = [:heartbeat, :version, :docs, :changelog
|
|
13
|
+
DEFAULT_HTTP_RESOURCES = [:heartbeat, :version, :docs, :changelog].freeze
|
|
14
14
|
|
|
15
15
|
def initialize(processor:, base_path:)
|
|
16
16
|
@processor = processor
|
|
@@ -35,7 +35,7 @@ module EventHub
|
|
|
35
35
|
def asset(name)
|
|
36
36
|
path = File.join(ASSETS_PATH, name)
|
|
37
37
|
return nil unless File.exist?(path)
|
|
38
|
-
File.read(path)
|
|
38
|
+
File.read(path, encoding: "utf-8")
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
private
|
|
@@ -63,7 +63,7 @@ module EventHub
|
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
if config_path && File.exist?(config_path)
|
|
66
|
-
return File.read(config_path)
|
|
66
|
+
return File.read(config_path, encoding: "utf-8")
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
locations = case type
|
|
@@ -75,7 +75,7 @@ module EventHub
|
|
|
75
75
|
|
|
76
76
|
locations.each do |location|
|
|
77
77
|
path = File.join(Dir.pwd, location)
|
|
78
|
-
return File.read(path) if File.exist?(path)
|
|
78
|
+
return File.read(path, encoding: "utf-8") if File.exist?(path)
|
|
79
79
|
end
|
|
80
80
|
|
|
81
81
|
"No #{(type == :readme) ? "README" : "CHANGELOG"} available."
|
|
@@ -91,19 +91,101 @@ module EventHub
|
|
|
91
91
|
"<p>Active configuration for the <strong>#{ERB::Util.html_escape(EventHub::Configuration.environment)}</strong> environment. " \
|
|
92
92
|
"Sensitive values such as passwords, tokens, and keys are automatically redacted.</p>"
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
filter = '<div class="config-filter">' \
|
|
95
|
+
'<div class="config-filter-row">' \
|
|
96
|
+
'<input type="text" id="config-filter-input" class="input" placeholder="Filter configuration keys..." autocomplete="off">' \
|
|
97
|
+
'<button type="button" id="config-filter-reset" class="config-filter-reset" title="Reset filter">×</button>' \
|
|
98
|
+
"</div>" \
|
|
99
|
+
'<p id="config-filter-count" class="config-filter-count"></p>' \
|
|
100
|
+
"</div>"
|
|
101
|
+
|
|
102
|
+
script = <<~JS
|
|
103
|
+
<script>
|
|
104
|
+
(function() {
|
|
105
|
+
var input = document.getElementById('config-filter-input');
|
|
106
|
+
var reset = document.getElementById('config-filter-reset');
|
|
107
|
+
var count = document.getElementById('config-filter-count');
|
|
108
|
+
var table = document.querySelector('.config-table');
|
|
109
|
+
if (!input || !table) return;
|
|
110
|
+
|
|
111
|
+
input.addEventListener('input', function() {
|
|
112
|
+
var term = this.value.toLowerCase();
|
|
113
|
+
var rows = table.querySelectorAll('tbody tr');
|
|
114
|
+
var visible = 0;
|
|
115
|
+
var total = 0;
|
|
116
|
+
|
|
117
|
+
// Filter individual rows by content (includes sub-tables)
|
|
118
|
+
rows.forEach(function(row) {
|
|
119
|
+
if (row.classList.contains('is-section')) {
|
|
120
|
+
row.style.display = '';
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
total++;
|
|
124
|
+
if (!term || row.textContent.toLowerCase().indexOf(term) !== -1) {
|
|
125
|
+
row.style.display = '';
|
|
126
|
+
visible++;
|
|
127
|
+
} else {
|
|
128
|
+
row.style.display = 'none';
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Hide section headers with no visible rows after them
|
|
133
|
+
var sections = table.querySelectorAll('tbody tr.is-section');
|
|
134
|
+
sections.forEach(function(section) {
|
|
135
|
+
var next = section.nextElementSibling;
|
|
136
|
+
var hasVisible = false;
|
|
137
|
+
while (next && !next.classList.contains('is-section')) {
|
|
138
|
+
if (next.style.display !== 'none') hasVisible = true;
|
|
139
|
+
next = next.nextElementSibling;
|
|
140
|
+
}
|
|
141
|
+
section.style.display = hasVisible ? '' : 'none';
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
if (term) {
|
|
145
|
+
count.textContent = visible + ' of ' + total + ' entries';
|
|
146
|
+
} else {
|
|
147
|
+
count.textContent = '';
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
reset.addEventListener('click', function() {
|
|
151
|
+
input.value = '';
|
|
152
|
+
input.dispatchEvent(new Event('input'));
|
|
153
|
+
input.focus();
|
|
154
|
+
});
|
|
155
|
+
})();
|
|
156
|
+
</script>
|
|
157
|
+
JS
|
|
158
|
+
|
|
159
|
+
intro + filter + config_to_html_table(config) + script
|
|
95
160
|
end
|
|
96
161
|
|
|
97
|
-
def config_to_html_table(hash, depth = 0)
|
|
162
|
+
def config_to_html_table(hash, depth = 0, prefix = "")
|
|
98
163
|
rows = hash.map do |key, value|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
"
|
|
164
|
+
full_key = prefix.empty? ? key.to_s : "#{prefix}.#{key}"
|
|
165
|
+
if depth == 0 && value.is_a?(Hash) && !value.empty?
|
|
166
|
+
"<tr class=\"is-section is-section-top\"><td colspan=\"2\"><strong>#{ERB::Util.html_escape(full_key)}</strong></td></tr>\n" \
|
|
167
|
+
"#{config_to_html_table(value, 1, full_key)}"
|
|
168
|
+
elsif value.is_a?(Hash) && value.empty?
|
|
169
|
+
"<tr><td class=\"config-key\">#{ERB::Util.html_escape(full_key)}</td><td><span class=\"not-set\">(empty)</span></td></tr>"
|
|
170
|
+
elsif value.is_a?(Hash) && value.values.all? { |v| v.is_a?(Hash) && v.empty? }
|
|
171
|
+
items = value.keys.map { |k| "<li>#{ERB::Util.html_escape(k)}</li>" }.join("\n")
|
|
172
|
+
"<tr><td class=\"config-key\">#{ERB::Util.html_escape(full_key)}</td><td><ul class=\"config-array\">#{items}</ul></td></tr>"
|
|
173
|
+
elsif value.is_a?(Hash) && compact_hash?(value)
|
|
174
|
+
"<tr><td class=\"config-key\">#{ERB::Util.html_escape(full_key)}</td><td>#{format_nested_value(value)}</td></tr>"
|
|
175
|
+
elsif value.is_a?(Hash)
|
|
176
|
+
"<tr class=\"is-section\"><td colspan=\"2\"><strong>#{ERB::Util.html_escape(full_key)}</strong></td></tr>\n" \
|
|
177
|
+
"#{config_to_html_table(value, depth + 1, full_key)}"
|
|
102
178
|
elsif value.is_a?(Array)
|
|
103
|
-
format_array_rows(key, value, depth)
|
|
179
|
+
format_array_rows(full_key, key, value, depth)
|
|
104
180
|
else
|
|
105
|
-
display_value = sensitive_key?(key)
|
|
106
|
-
|
|
181
|
+
display_value = if sensitive_key?(key)
|
|
182
|
+
"<span class=\"redacted\">***</span>"
|
|
183
|
+
elsif value.nil? || value.to_s.strip.empty?
|
|
184
|
+
"<span class=\"not-set\">(not set)</span>"
|
|
185
|
+
else
|
|
186
|
+
ERB::Util.html_escape(value.to_s)
|
|
187
|
+
end
|
|
188
|
+
"<tr><td class=\"config-key\">#{ERB::Util.html_escape(full_key)}</td><td>#{display_value}</td></tr>"
|
|
107
189
|
end
|
|
108
190
|
end.join("\n")
|
|
109
191
|
|
|
@@ -114,24 +196,59 @@ module EventHub
|
|
|
114
196
|
end
|
|
115
197
|
end
|
|
116
198
|
|
|
117
|
-
def format_array_rows(key, array,
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
199
|
+
def format_array_rows(full_key, key, array, _depth)
|
|
200
|
+
return "<tr><td class=\"config-key\">#{ERB::Util.html_escape(full_key)}</td><td><span class=\"not-set\">(empty)</span></td></tr>" if array.empty?
|
|
201
|
+
|
|
202
|
+
if sensitive_key?(key)
|
|
203
|
+
return "<tr><td class=\"config-key\">#{ERB::Util.html_escape(full_key)}</td><td><span class=\"redacted\">***</span></td></tr>"
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
inner = array.map { |item| format_array_item(item) }.join("\n")
|
|
207
|
+
"<tr><td class=\"config-key\">#{ERB::Util.html_escape(full_key)}</td><td><ul class=\"config-array\">#{inner}</ul></td></tr>"
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def format_array_item(item)
|
|
211
|
+
if item.is_a?(Hash)
|
|
212
|
+
rows = item.map do |k, v|
|
|
213
|
+
value = format_nested_value(v)
|
|
214
|
+
"<tr><td>#{ERB::Util.html_escape(k)}</td><td>#{value}</td></tr>"
|
|
215
|
+
end.join
|
|
216
|
+
"<li><table class=\"table is-bordered is-narrow config-subtable\">#{rows}</table></li>"
|
|
217
|
+
elsif item.is_a?(Array)
|
|
218
|
+
inner = item.map { |i| format_array_item(i) }.join("\n")
|
|
219
|
+
"<li><ul class=\"config-array\">#{inner}</ul></li>"
|
|
128
220
|
else
|
|
129
|
-
|
|
130
|
-
|
|
221
|
+
"<li>#{ERB::Util.html_escape(item.to_s)}</li>"
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def format_nested_value(value)
|
|
226
|
+
if value.is_a?(Hash)
|
|
227
|
+
rows = value.map do |k, v|
|
|
228
|
+
"<tr><td>#{ERB::Util.html_escape(k)}</td><td>#{format_nested_value(v)}</td></tr>"
|
|
229
|
+
end.join
|
|
230
|
+
"<table class=\"table is-bordered is-narrow config-subtable\">#{rows}</table>"
|
|
231
|
+
elsif value.is_a?(Array)
|
|
232
|
+
items = value.map { |i| format_array_item(i) }.join("\n")
|
|
233
|
+
"<ul class=\"config-array\">#{items}</ul>"
|
|
234
|
+
elsif value.nil? || value.to_s.strip.empty?
|
|
235
|
+
"<span class=\"not-set\">(not set)</span>"
|
|
236
|
+
else
|
|
237
|
+
ERB::Util.html_escape(value.to_s)
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def compact_hash?(hash)
|
|
242
|
+
hash.values.all? do |v|
|
|
243
|
+
if v.is_a?(Hash)
|
|
244
|
+
compact_hash?(v)
|
|
245
|
+
else
|
|
246
|
+
!v.is_a?(Array)
|
|
247
|
+
end
|
|
131
248
|
end
|
|
132
249
|
end
|
|
133
250
|
|
|
134
|
-
DEFAULT_SENSITIVE_KEYS = %w[password secret token api_key credential].freeze
|
|
251
|
+
DEFAULT_SENSITIVE_KEYS = %w[password secret token api_key credential username user login].freeze
|
|
135
252
|
|
|
136
253
|
def sensitive_key?(key)
|
|
137
254
|
keys = if @processor&.class&.method_defined?(:sensitive_keys)
|
|
@@ -148,7 +265,7 @@ module EventHub
|
|
|
148
265
|
|
|
149
266
|
def render_layout(title:, content:, content_class: "")
|
|
150
267
|
template_path = File.join(TEMPLATES_PATH, "layout.erb")
|
|
151
|
-
template = File.read(template_path)
|
|
268
|
+
template = File.read(template_path, encoding: "utf-8")
|
|
152
269
|
|
|
153
270
|
processor_name = EventHub::Configuration.name
|
|
154
271
|
version = processor_version
|
data/lib/eventhub/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: eventhub-processor2
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.27.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Steiner, Thomas
|
|
@@ -43,14 +43,14 @@ dependencies:
|
|
|
43
43
|
requirements:
|
|
44
44
|
- - "~>"
|
|
45
45
|
- !ruby/object:Gem::Version
|
|
46
|
-
version: '
|
|
46
|
+
version: '3.0'
|
|
47
47
|
type: :runtime
|
|
48
48
|
prerelease: false
|
|
49
49
|
version_requirements: !ruby/object:Gem::Requirement
|
|
50
50
|
requirements:
|
|
51
51
|
- - "~>"
|
|
52
52
|
- !ruby/object:Gem::Version
|
|
53
|
-
version: '
|
|
53
|
+
version: '3.0'
|
|
54
54
|
- !ruby/object:Gem::Dependency
|
|
55
55
|
name: eventhub-components
|
|
56
56
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -192,6 +192,7 @@ files:
|
|
|
192
192
|
- eventhub-processor2.gemspec
|
|
193
193
|
- example/CHANGELOG.md
|
|
194
194
|
- example/README.md
|
|
195
|
+
- example/config/example.json
|
|
195
196
|
- example/config/receiver.json
|
|
196
197
|
- example/config/router.json
|
|
197
198
|
- example/crasher.rb
|