startback-websocket 0.14.0 → 0.14.3

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.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -2
  3. data/README.md +64 -9
  4. data/dist/client.js +1 -0
  5. data/lib/startback/ext/context.rb +6 -0
  6. data/lib/startback/ext.rb +1 -2
  7. data/lib/startback/websocket/app.rb +82 -0
  8. data/lib/startback/websocket/hub/app.rb +28 -0
  9. data/lib/startback/websocket/hub/builder.rb +55 -0
  10. data/lib/startback/websocket/hub/errors.rb +9 -0
  11. data/lib/startback/websocket/hub/message.rb +29 -0
  12. data/lib/startback/websocket/hub/middleware/command_handler.rb +34 -0
  13. data/lib/startback/websocket/hub/middleware/room_handler.rb +30 -0
  14. data/lib/startback/websocket/hub/middleware.rb +12 -0
  15. data/lib/startback/websocket/hub/participant.rb +16 -0
  16. data/lib/startback/websocket/hub/room.rb +46 -0
  17. data/lib/startback/websocket/hub.rb +15 -0
  18. data/lib/startback/websocket.rb +8 -0
  19. data/spec/spec_helper.rb +21 -32
  20. data/spec/unit/hub/test_builder.rb +141 -0
  21. data/spec/unit/hub/test_room.rb +27 -0
  22. data/spec/unit/test_app.rb +35 -0
  23. data/tasks/test.rake +0 -1
  24. metadata +21 -91
  25. data/lib/startback/audit/prometheus.rb +0 -87
  26. data/lib/startback/audit/shared.rb +0 -17
  27. data/lib/startback/audit/trailer.rb +0 -129
  28. data/lib/startback/audit.rb +0 -3
  29. data/lib/startback/caching/entity_cache.rb +0 -157
  30. data/lib/startback/caching/no_store.rb +0 -28
  31. data/lib/startback/caching/store.rb +0 -34
  32. data/lib/startback/context/h_factory.rb +0 -43
  33. data/lib/startback/context/middleware.rb +0 -53
  34. data/lib/startback/context.rb +0 -122
  35. data/lib/startback/errors.rb +0 -197
  36. data/lib/startback/event/agent.rb +0 -84
  37. data/lib/startback/event/bus/bunny/async.rb +0 -162
  38. data/lib/startback/event/bus/bunny.rb +0 -1
  39. data/lib/startback/event/bus/memory/async.rb +0 -45
  40. data/lib/startback/event/bus/memory/sync.rb +0 -35
  41. data/lib/startback/event/bus/memory.rb +0 -2
  42. data/lib/startback/event/bus.rb +0 -100
  43. data/lib/startback/event/engine.rb +0 -94
  44. data/lib/startback/event/ext/context.rb +0 -5
  45. data/lib/startback/event/ext/operation.rb +0 -13
  46. data/lib/startback/event.rb +0 -47
  47. data/lib/startback/ext/date_time.rb +0 -9
  48. data/lib/startback/ext/time.rb +0 -9
  49. data/lib/startback/model.rb +0 -6
  50. data/lib/startback/operation/error_operation.rb +0 -19
  51. data/lib/startback/operation/multi_operation.rb +0 -28
  52. data/lib/startback/operation.rb +0 -78
  53. data/lib/startback/services.rb +0 -11
  54. data/lib/startback/support/data_object.rb +0 -71
  55. data/lib/startback/support/env.rb +0 -41
  56. data/lib/startback/support/fake_logger.rb +0 -18
  57. data/lib/startback/support/hooks.rb +0 -48
  58. data/lib/startback/support/log_formatter.rb +0 -34
  59. data/lib/startback/support/logger.rb +0 -34
  60. data/lib/startback/support/operation_runner.rb +0 -150
  61. data/lib/startback/support/robustness.rb +0 -157
  62. data/lib/startback/support/transaction_manager.rb +0 -25
  63. data/lib/startback/support/transaction_policy.rb +0 -33
  64. data/lib/startback/support/world.rb +0 -54
  65. data/lib/startback/support.rb +0 -26
  66. data/lib/startback/version.rb +0 -8
  67. data/lib/startback/web/api.rb +0 -99
  68. data/lib/startback/web/auto_caching.rb +0 -85
  69. data/lib/startback/web/catch_all.rb +0 -52
  70. data/lib/startback/web/cors_headers.rb +0 -80
  71. data/lib/startback/web/health_check.rb +0 -49
  72. data/lib/startback/web/magic_assets/ng_html_transformer.rb +0 -80
  73. data/lib/startback/web/magic_assets/rake_tasks.rb +0 -64
  74. data/lib/startback/web/magic_assets.rb +0 -98
  75. data/lib/startback/web/middleware.rb +0 -13
  76. data/lib/startback/web/prometheus.rb +0 -16
  77. data/lib/startback/web/shield.rb +0 -58
  78. data/lib/startback.rb +0 -43
  79. data/spec/unit/audit/test_prometheus.rb +0 -72
  80. data/spec/unit/audit/test_trailer.rb +0 -105
  81. data/spec/unit/caching/test_entity_cache.rb +0 -136
  82. data/spec/unit/context/test_abstraction_factory.rb +0 -64
  83. data/spec/unit/context/test_dup.rb +0 -42
  84. data/spec/unit/context/test_fork.rb +0 -37
  85. data/spec/unit/context/test_h_factory.rb +0 -31
  86. data/spec/unit/context/test_middleware.rb +0 -45
  87. data/spec/unit/context/test_with_world.rb +0 -20
  88. data/spec/unit/context/test_world.rb +0 -17
  89. data/spec/unit/event/bus/memory/test_async.rb +0 -43
  90. data/spec/unit/event/bus/memory/test_sync.rb +0 -43
  91. data/spec/unit/support/hooks/test_after_hook.rb +0 -54
  92. data/spec/unit/support/hooks/test_before_hook.rb +0 -54
  93. data/spec/unit/support/operation_runner/test_around_run.rb +0 -156
  94. data/spec/unit/support/operation_runner/test_before_after_call.rb +0 -48
  95. data/spec/unit/support/test_data_object.rb +0 -156
  96. data/spec/unit/support/test_env.rb +0 -75
  97. data/spec/unit/support/test_robusteness.rb +0 -229
  98. data/spec/unit/support/test_transaction_manager.rb +0 -64
  99. data/spec/unit/support/test_world.rb +0 -72
  100. data/spec/unit/test_event.rb +0 -62
  101. data/spec/unit/test_operation.rb +0 -55
  102. data/spec/unit/test_support.rb +0 -40
  103. data/spec/unit/web/fixtures/assets/app/hello.es6 +0 -4
  104. data/spec/unit/web/fixtures/assets/app/hello.html +0 -1
  105. data/spec/unit/web/fixtures/assets/index.es6 +0 -1
  106. data/spec/unit/web/test_api.rb +0 -82
  107. data/spec/unit/web/test_auto_caching.rb +0 -81
  108. data/spec/unit/web/test_catch_all.rb +0 -77
  109. data/spec/unit/web/test_cors_headers.rb +0 -88
  110. data/spec/unit/web/test_healthcheck.rb +0 -59
  111. data/spec/unit/web/test_magic_assets.rb +0 -82
@@ -0,0 +1,141 @@
1
+ require 'spec_helper'
2
+ require 'startback/websocket'
3
+
4
+ module Startback
5
+ module Websocket
6
+ module Hub
7
+ describe Builder do
8
+
9
+ class TestMiddleware
10
+
11
+ def initialize(app, opts = {})
12
+ @app = app
13
+ @@init = true
14
+ @@opts = opts
15
+ end
16
+
17
+ def call(data, socket)
18
+ @@calls ||= []
19
+ @@calls << data
20
+ @app.call(data, socket)
21
+ end
22
+
23
+ def self.reset
24
+ @@init = false
25
+ @@calls = []
26
+ end
27
+
28
+ def self.init
29
+ @@init
30
+ end
31
+
32
+ def self.calls
33
+ @@calls
34
+ end
35
+
36
+ def self.opts
37
+ @@opts
38
+ end
39
+ end
40
+
41
+ before(:each) do
42
+ TestMiddleware.reset
43
+ end
44
+
45
+ it 'calls the block given at initialization' do
46
+ called = false
47
+ Builder.new(SpecHelpers::SubContext.new) { called = true }
48
+ expect(called).to eql(true)
49
+ end
50
+
51
+ context 'to_websocket_app' do
52
+ it 'returns an App instance' do
53
+ builder = Builder.new(SpecHelpers::SubContext.new) do
54
+ end
55
+ app = builder.to_websocket_app
56
+ expect(app).to be_a(App)
57
+ end
58
+ end
59
+
60
+ context 'to_handler' do
61
+
62
+ it 'instantiates middleware classes' do
63
+ handler = Builder.new(SpecHelpers::SubContext.new) do
64
+ use TestMiddleware
65
+ end.to_handler
66
+
67
+ expect(TestMiddleware.init).to eql(true)
68
+ end
69
+
70
+ it 'allows options to be passed to middleware classes' do
71
+ handler = Builder.new(SpecHelpers::SubContext.new) do
72
+ use TestMiddleware, { some: 'option' }
73
+ end.to_handler
74
+
75
+ expect(TestMiddleware.init).to eql(true)
76
+ expect(TestMiddleware.opts).to eql({ some: 'option' })
77
+ end
78
+
79
+ it 'creates the correct chain of handlers' do
80
+ handler = Builder.new(SpecHelpers::SubContext.new) do
81
+ use TestMiddleware
82
+ use TestMiddleware
83
+ end.to_handler
84
+
85
+ handler.call({test: 42}, SpecHelpers::MockSocket.new)
86
+ expect(TestMiddleware.calls.size).to eql(2)
87
+ end
88
+
89
+ it 'supports commands' do
90
+ handler = Builder.new(SpecHelpers::SubContext.new) do
91
+ command :hello do |command, socket|
92
+ socket.send('from hello')
93
+ end
94
+
95
+ command :foo do |command, socket|
96
+ socket.send('from foo')
97
+ end
98
+ end.to_handler
99
+
100
+ socket = SpecHelpers::MockSocket.new
101
+
102
+ msg = SpecHelpers::MockFayeEvent.new({ :headers => { :command => 'hello' } })
103
+ handler.call(msg, socket, {})
104
+ expect(socket.last_message).to eql('from hello')
105
+
106
+ msg = SpecHelpers::MockFayeEvent.new({ :headers => { :command => 'foo' } })
107
+ handler.call(msg, socket, {})
108
+ expect(socket.last_message).to eql('from foo')
109
+ end
110
+
111
+ it 'supports rooms' do
112
+ handler = Builder.new(SpecHelpers::SubContext.new) do
113
+ room 'a' do |room|
114
+ command :hello do |command, socket|
115
+ socket.send("hi from #{room.name}!")
116
+ end
117
+ end
118
+
119
+ room 'b' do
120
+ command :hello do |command, socket|
121
+ socket.send(command)
122
+ end
123
+ end
124
+ end.to_handler
125
+
126
+ socket = SpecHelpers::MockSocket.new
127
+
128
+ msg = SpecHelpers::MockFayeEvent.new({ :headers => { command: 'hello', room: 'a' } })
129
+ handler.call(msg, socket, {})
130
+ expect(socket.last_message).to eql('hi from a!')
131
+
132
+ msg = SpecHelpers::MockFayeEvent.new({ :headers => { command: 'hello', room: 'b' } })
133
+ handler.call(msg, socket, {})
134
+ expect(socket.last_message).to eql(msg)
135
+ end
136
+
137
+ end
138
+ end # describe
139
+ end # module Hub
140
+ end # module Websocket
141
+ end # module Startback
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+ require 'startback/websocket'
3
+
4
+ module Startback
5
+ module Websocket
6
+ module Hub
7
+ describe Room do
8
+
9
+ context 'add' do
10
+
11
+ room = Room.new('room-name')
12
+
13
+ it 'expects participant instances' do
14
+ expect { room.add SpecHelpers.MockSocket.new }.to raise_error
15
+ end
16
+
17
+ it 'allows adding participants to the room' do
18
+ room.add Participant.new(SpecHelpers::MockSocket.new, SpecHelpers::SubContext.new)
19
+ expect(room.participants.size).to eql(1)
20
+ end
21
+
22
+ end
23
+
24
+ end # describe
25
+ end # module Hub
26
+ end # module Websocket
27
+ end # module Startback
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+ require 'startback/websocket'
3
+
4
+ module Startback
5
+ module Websocket
6
+ describe App do
7
+ include Rack::Test::Methods
8
+
9
+ def app
10
+ App.new(SpecHelpers::SubContext.new)
11
+ end
12
+
13
+ it 'returns a 400 when not used with proper websocket handshake' do
14
+ get '/'
15
+ expect(last_response.status).to eql(400)
16
+ expect(last_response.body).to eql('Websocket only!')
17
+ end
18
+
19
+ it 'does respond with proper handshake in the context of websocket connections' do
20
+ header 'connection', 'upgrade'
21
+ header 'upgrade', 'websocket'
22
+ get '/'
23
+ # https://github.com/faye/faye-websocket-ruby/blob/main/lib/faye/websocket.rb#L93
24
+ expect(last_response.status).to eql(-1)
25
+ end
26
+
27
+ it 'serves the javascript client properly' do
28
+ get '/client.js'
29
+ expect(last_response.status).to eql(200)
30
+ expect(last_response['Content-Type']).to eql('application/javascript')
31
+ end
32
+
33
+ end # describe
34
+ end # module Web
35
+ end # module Startback
data/tasks/test.rake CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'rspec/core/rake_task'
2
- require 'path'
3
2
 
4
3
  namespace :test do
5
4
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: startback-websocket
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.0
4
+ version: 0.14.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernard Lambeau
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-06-07 00:00:00.000000000 Z
11
+ date: 2022-06-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: startback
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 0.14.0
19
+ version: 0.14.3
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 0.14.0
26
+ version: 0.14.3
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: faye-websocket
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -121,95 +121,25 @@ files:
121
121
  - Gemfile
122
122
  - README.md
123
123
  - Rakefile
124
- - lib/startback.rb
125
- - lib/startback/audit.rb
126
- - lib/startback/audit/prometheus.rb
127
- - lib/startback/audit/shared.rb
128
- - lib/startback/audit/trailer.rb
129
- - lib/startback/caching/entity_cache.rb
130
- - lib/startback/caching/no_store.rb
131
- - lib/startback/caching/store.rb
132
- - lib/startback/context.rb
133
- - lib/startback/context/h_factory.rb
134
- - lib/startback/context/middleware.rb
135
- - lib/startback/errors.rb
136
- - lib/startback/event.rb
137
- - lib/startback/event/agent.rb
138
- - lib/startback/event/bus.rb
139
- - lib/startback/event/bus/bunny.rb
140
- - lib/startback/event/bus/bunny/async.rb
141
- - lib/startback/event/bus/memory.rb
142
- - lib/startback/event/bus/memory/async.rb
143
- - lib/startback/event/bus/memory/sync.rb
144
- - lib/startback/event/engine.rb
145
- - lib/startback/event/ext/context.rb
146
- - lib/startback/event/ext/operation.rb
124
+ - dist/client.js
147
125
  - lib/startback/ext.rb
148
- - lib/startback/ext/date_time.rb
149
- - lib/startback/ext/time.rb
150
- - lib/startback/model.rb
151
- - lib/startback/operation.rb
152
- - lib/startback/operation/error_operation.rb
153
- - lib/startback/operation/multi_operation.rb
154
- - lib/startback/services.rb
155
- - lib/startback/support.rb
156
- - lib/startback/support/data_object.rb
157
- - lib/startback/support/env.rb
158
- - lib/startback/support/fake_logger.rb
159
- - lib/startback/support/hooks.rb
160
- - lib/startback/support/log_formatter.rb
161
- - lib/startback/support/logger.rb
162
- - lib/startback/support/operation_runner.rb
163
- - lib/startback/support/robustness.rb
164
- - lib/startback/support/transaction_manager.rb
165
- - lib/startback/support/transaction_policy.rb
166
- - lib/startback/support/world.rb
167
- - lib/startback/version.rb
168
- - lib/startback/web/api.rb
169
- - lib/startback/web/auto_caching.rb
170
- - lib/startback/web/catch_all.rb
171
- - lib/startback/web/cors_headers.rb
172
- - lib/startback/web/health_check.rb
173
- - lib/startback/web/magic_assets.rb
174
- - lib/startback/web/magic_assets/ng_html_transformer.rb
175
- - lib/startback/web/magic_assets/rake_tasks.rb
176
- - lib/startback/web/middleware.rb
177
- - lib/startback/web/prometheus.rb
178
- - lib/startback/web/shield.rb
126
+ - lib/startback/ext/context.rb
127
+ - lib/startback/websocket.rb
128
+ - lib/startback/websocket/app.rb
129
+ - lib/startback/websocket/hub.rb
130
+ - lib/startback/websocket/hub/app.rb
131
+ - lib/startback/websocket/hub/builder.rb
132
+ - lib/startback/websocket/hub/errors.rb
133
+ - lib/startback/websocket/hub/message.rb
134
+ - lib/startback/websocket/hub/middleware.rb
135
+ - lib/startback/websocket/hub/middleware/command_handler.rb
136
+ - lib/startback/websocket/hub/middleware/room_handler.rb
137
+ - lib/startback/websocket/hub/participant.rb
138
+ - lib/startback/websocket/hub/room.rb
179
139
  - spec/spec_helper.rb
180
- - spec/unit/audit/test_prometheus.rb
181
- - spec/unit/audit/test_trailer.rb
182
- - spec/unit/caching/test_entity_cache.rb
183
- - spec/unit/context/test_abstraction_factory.rb
184
- - spec/unit/context/test_dup.rb
185
- - spec/unit/context/test_fork.rb
186
- - spec/unit/context/test_h_factory.rb
187
- - spec/unit/context/test_middleware.rb
188
- - spec/unit/context/test_with_world.rb
189
- - spec/unit/context/test_world.rb
190
- - spec/unit/event/bus/memory/test_async.rb
191
- - spec/unit/event/bus/memory/test_sync.rb
192
- - spec/unit/support/hooks/test_after_hook.rb
193
- - spec/unit/support/hooks/test_before_hook.rb
194
- - spec/unit/support/operation_runner/test_around_run.rb
195
- - spec/unit/support/operation_runner/test_before_after_call.rb
196
- - spec/unit/support/test_data_object.rb
197
- - spec/unit/support/test_env.rb
198
- - spec/unit/support/test_robusteness.rb
199
- - spec/unit/support/test_transaction_manager.rb
200
- - spec/unit/support/test_world.rb
201
- - spec/unit/test_event.rb
202
- - spec/unit/test_operation.rb
203
- - spec/unit/test_support.rb
204
- - spec/unit/web/fixtures/assets/app/hello.es6
205
- - spec/unit/web/fixtures/assets/app/hello.html
206
- - spec/unit/web/fixtures/assets/index.es6
207
- - spec/unit/web/test_api.rb
208
- - spec/unit/web/test_auto_caching.rb
209
- - spec/unit/web/test_catch_all.rb
210
- - spec/unit/web/test_cors_headers.rb
211
- - spec/unit/web/test_healthcheck.rb
212
- - spec/unit/web/test_magic_assets.rb
140
+ - spec/unit/hub/test_builder.rb
141
+ - spec/unit/hub/test_room.rb
142
+ - spec/unit/test_app.rb
213
143
  - tasks/test.rake
214
144
  homepage: https://www.enspirit.be
215
145
  licenses:
@@ -1,87 +0,0 @@
1
- require_relative 'shared'
2
- require 'prometheus/client'
3
-
4
- module Startback
5
- module Audit
6
- #
7
- # Prometheus exporter abstraction, that can be registered as an around
8
- # hook on OperationRunner and as a prometheus client on Context instances.
9
- #
10
- # The exporter uses the ruby client for prometheus to expose metrics regarding Operation runs.
11
- #
12
- # The following metrics are exported:
13
- #
14
- # A counter 'operation_errors' (failed runs)
15
- # A histogram 'operation_calls'
16
- #
17
- # All these metrics use the following labels
18
- # - operation : class name of the operation executed
19
- #
20
- # Given that this Exporter is intended to be used as around hook on an
21
- # `OperationRunner`, operations that fail at construction time will not be
22
- # exported at all, since they can't be ran in the first place. This may lead
23
- # to metrics not containing important errors cases if operations check their
24
- # input at construction time.
25
- #
26
- class Prometheus
27
- include Shared
28
-
29
- def initialize(options = {})
30
- @prefix = options[:prefix] || "startback"
31
- @options = options
32
- @registry = ::Prometheus::Client.registry
33
- all_labels = [:operation, :startback_version] + option_labels.keys
34
- @errors = @registry.counter(
35
- :"#{prefix}_operation_errors",
36
- docstring: 'A counter of operation errors',
37
- labels: all_labels)
38
- @calls = @registry.histogram(
39
- :"#{prefix}_operation_calls",
40
- docstring: 'A histogram of operation latency',
41
- labels: all_labels)
42
- end
43
- attr_reader :registry, :calls, :errors, :options, :prefix
44
-
45
- def call(runner, op)
46
- name = op_name(op)
47
- result = nil
48
- time = Benchmark.realtime{
49
- result = yield
50
- }
51
- ignore_safely {
52
- @calls.observe(time, labels: get_labels(name))
53
- }
54
- result
55
- rescue => ex
56
- ignore_safely {
57
- @errors.increment(labels: get_labels(name))
58
- }
59
- raise
60
- end
61
-
62
- protected
63
-
64
- def ignore_safely
65
- yield
66
- rescue => ex
67
- nil
68
- end
69
-
70
- def get_labels(op_name)
71
- option_labels.merge({
72
- operation: op_name,
73
- startback_version: version
74
- })
75
- end
76
-
77
- def option_labels
78
- @options[:labels] || {}
79
- end
80
-
81
- def version
82
- Startback::VERSION
83
- end
84
-
85
- end # class Prometheus
86
- end # module Audit
87
- end # module Startback
@@ -1,17 +0,0 @@
1
- module Startback
2
- module Audit
3
- module Shared
4
-
5
- def op_name(op)
6
- return op.op_name if op.respond_to?(:op_name)
7
-
8
- case op
9
- when String then op
10
- when Class then op.name
11
- else op.class.name
12
- end
13
- end
14
-
15
- end # module Shared
16
- end # module Audit
17
- end # module Startback
@@ -1,129 +0,0 @@
1
- require_relative 'shared'
2
- require 'forwardable'
3
- module Startback
4
- module Audit
5
- #
6
- # Log & Audit trail abstraction, that can be registered as an around
7
- # hook on OperationRunner and as an actual logger on Context instances.
8
- #
9
- # The trail is outputted as JSON lines, using a Logger on the "device"
10
- # passed at construction. The following JSON entries are dumped:
11
- #
12
- # - severity : INFO or ERROR
13
- # - time : ISO8601 Datetime of operation execution
14
- # - op : class name of the operation executed
15
- # - op_took : Execution duration of the operation
16
- # - op_data : Dump of operation input data
17
- # - context : Execution context, through its `h` information contract (IC)
18
- #
19
- # Dumping of operation data follows the following duck typing conventions:
20
- #
21
- # - If the operation instance responds to `to_trail`, this data is taken
22
- # - If the operation instance responds to `input`, this data is taken
23
- # - If the operation instance responds to `request`, this data is taken
24
- # - Otherwise op_data is a JSON null
25
- #
26
- # By contributing to the Context's `h` IC, users can easily dump information that
27
- # makes sense (such as the operation execution requester).
28
- #
29
- # The class implements a sanitization process when dumping the context and
30
- # operation data. Blacklisted words taken in construction options are used to
31
- # prevent dumping hash keys that match them (insentively). Default stop words
32
- # are equivalent to:
33
- #
34
- # Trailer.new("/var/log/trail.log", {
35
- # blacklist: "token password secret credential"
36
- # })
37
- #
38
- # Please note that the sanitization process does not apply recursively if
39
- # the operation data is hierarchic. It only applies to the top object of
40
- # Hash and [Hash]. Use `Operation#to_trail` to fine-tune your audit trail.
41
- #
42
- # Given that this Trailer is intended to be used as around hook on an
43
- # `OperationRunner`, operations that fail at construction time will not be
44
- # trailed at all, since they can't be ran in the first place. This may lead
45
- # to trails not containing important errors cases if operations check their
46
- # input at construction time.
47
- #
48
- class Trailer
49
- include Shared
50
- extend Forwardable
51
- def_delegators :@logger, :debug, :info, :warn, :error, :fatal
52
-
53
- DEFAULT_OPTIONS = {
54
-
55
- # Words used to stop dumping for, e.g., security reasons
56
- blacklist: "token password secret credential"
57
-
58
- }
59
-
60
- def initialize(device, options = {})
61
- @options = DEFAULT_OPTIONS.merge(options)
62
- @logger = ::Logger.new(device, 'daily')
63
- @logger.formatter = Support::LogFormatter.new
64
- end
65
- attr_reader :logger, :options
66
-
67
- def call(runner, op)
68
- result = nil
69
- time = Benchmark.realtime{ result = yield }
70
- logger.info(op_to_trail(op, time))
71
- result
72
- rescue => ex
73
- logger.error(op_to_trail(op, time, ex))
74
- raise
75
- end
76
-
77
- protected
78
-
79
- def op_to_trail(op, time = nil, ex = nil)
80
- log_msg = {
81
- op_took: time ? time.round(8) : nil,
82
- op: op_name(op),
83
- context: op_context(op),
84
- op_data: op_data(op)
85
- }.compact
86
- log_msg[:error] = ex if ex
87
- log_msg
88
- end
89
-
90
- def op_context(op)
91
- sanitize(op.respond_to?(:context, false) ? op.context.to_h : {})
92
- end
93
-
94
- def op_data(op)
95
- data = if op.respond_to?(:op_data, false)
96
- op.op_data
97
- elsif op.respond_to?(:to_trail, false)
98
- op.to_trail
99
- elsif op.respond_to?(:input, false)
100
- op.input
101
- elsif op.respond_to?(:request, false)
102
- op.request
103
- elsif op.is_a?(Operation::MultiOperation)
104
- op.ops.map{ |sub_op| op_to_trail(sub_op) }
105
- end
106
- sanitize(data)
107
- end
108
-
109
- def sanitize(data)
110
- case data
111
- when Hash, OpenStruct
112
- data.dup.delete_if{|k| k.to_s =~ blacklist_rx }
113
- when Enumerable
114
- data.map{|elm| sanitize(elm) }.compact
115
- else
116
- data
117
- end
118
- end
119
-
120
- def blacklist_rx
121
- @blacklist_rx ||= Regexp.new(
122
- options[:blacklist].split(/\s+/).join("|"),
123
- Regexp::IGNORECASE
124
- )
125
- end
126
-
127
- end # class Trailer
128
- end # module Audit
129
- end # module Startback
@@ -1,3 +0,0 @@
1
- require_relative 'audit/shared'
2
- require_relative 'audit/trailer'
3
- require_relative 'audit/prometheus'