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.
- checksums.yaml +4 -4
- data/Gemfile +3 -2
- data/README.md +64 -9
- data/dist/client.js +1 -0
- data/lib/startback/ext/context.rb +6 -0
- data/lib/startback/ext.rb +1 -2
- data/lib/startback/websocket/app.rb +82 -0
- data/lib/startback/websocket/hub/app.rb +28 -0
- data/lib/startback/websocket/hub/builder.rb +55 -0
- data/lib/startback/websocket/hub/errors.rb +9 -0
- data/lib/startback/websocket/hub/message.rb +29 -0
- data/lib/startback/websocket/hub/middleware/command_handler.rb +34 -0
- data/lib/startback/websocket/hub/middleware/room_handler.rb +30 -0
- data/lib/startback/websocket/hub/middleware.rb +12 -0
- data/lib/startback/websocket/hub/participant.rb +16 -0
- data/lib/startback/websocket/hub/room.rb +46 -0
- data/lib/startback/websocket/hub.rb +15 -0
- data/lib/startback/websocket.rb +8 -0
- data/spec/spec_helper.rb +21 -32
- data/spec/unit/hub/test_builder.rb +141 -0
- data/spec/unit/hub/test_room.rb +27 -0
- data/spec/unit/test_app.rb +35 -0
- data/tasks/test.rake +0 -1
- metadata +21 -91
- data/lib/startback/audit/prometheus.rb +0 -87
- data/lib/startback/audit/shared.rb +0 -17
- data/lib/startback/audit/trailer.rb +0 -129
- data/lib/startback/audit.rb +0 -3
- data/lib/startback/caching/entity_cache.rb +0 -157
- data/lib/startback/caching/no_store.rb +0 -28
- data/lib/startback/caching/store.rb +0 -34
- data/lib/startback/context/h_factory.rb +0 -43
- data/lib/startback/context/middleware.rb +0 -53
- data/lib/startback/context.rb +0 -122
- data/lib/startback/errors.rb +0 -197
- data/lib/startback/event/agent.rb +0 -84
- data/lib/startback/event/bus/bunny/async.rb +0 -162
- data/lib/startback/event/bus/bunny.rb +0 -1
- data/lib/startback/event/bus/memory/async.rb +0 -45
- data/lib/startback/event/bus/memory/sync.rb +0 -35
- data/lib/startback/event/bus/memory.rb +0 -2
- data/lib/startback/event/bus.rb +0 -100
- data/lib/startback/event/engine.rb +0 -94
- data/lib/startback/event/ext/context.rb +0 -5
- data/lib/startback/event/ext/operation.rb +0 -13
- data/lib/startback/event.rb +0 -47
- data/lib/startback/ext/date_time.rb +0 -9
- data/lib/startback/ext/time.rb +0 -9
- data/lib/startback/model.rb +0 -6
- data/lib/startback/operation/error_operation.rb +0 -19
- data/lib/startback/operation/multi_operation.rb +0 -28
- data/lib/startback/operation.rb +0 -78
- data/lib/startback/services.rb +0 -11
- data/lib/startback/support/data_object.rb +0 -71
- data/lib/startback/support/env.rb +0 -41
- data/lib/startback/support/fake_logger.rb +0 -18
- data/lib/startback/support/hooks.rb +0 -48
- data/lib/startback/support/log_formatter.rb +0 -34
- data/lib/startback/support/logger.rb +0 -34
- data/lib/startback/support/operation_runner.rb +0 -150
- data/lib/startback/support/robustness.rb +0 -157
- data/lib/startback/support/transaction_manager.rb +0 -25
- data/lib/startback/support/transaction_policy.rb +0 -33
- data/lib/startback/support/world.rb +0 -54
- data/lib/startback/support.rb +0 -26
- data/lib/startback/version.rb +0 -8
- data/lib/startback/web/api.rb +0 -99
- data/lib/startback/web/auto_caching.rb +0 -85
- data/lib/startback/web/catch_all.rb +0 -52
- data/lib/startback/web/cors_headers.rb +0 -80
- data/lib/startback/web/health_check.rb +0 -49
- data/lib/startback/web/magic_assets/ng_html_transformer.rb +0 -80
- data/lib/startback/web/magic_assets/rake_tasks.rb +0 -64
- data/lib/startback/web/magic_assets.rb +0 -98
- data/lib/startback/web/middleware.rb +0 -13
- data/lib/startback/web/prometheus.rb +0 -16
- data/lib/startback/web/shield.rb +0 -58
- data/lib/startback.rb +0 -43
- data/spec/unit/audit/test_prometheus.rb +0 -72
- data/spec/unit/audit/test_trailer.rb +0 -105
- data/spec/unit/caching/test_entity_cache.rb +0 -136
- data/spec/unit/context/test_abstraction_factory.rb +0 -64
- data/spec/unit/context/test_dup.rb +0 -42
- data/spec/unit/context/test_fork.rb +0 -37
- data/spec/unit/context/test_h_factory.rb +0 -31
- data/spec/unit/context/test_middleware.rb +0 -45
- data/spec/unit/context/test_with_world.rb +0 -20
- data/spec/unit/context/test_world.rb +0 -17
- data/spec/unit/event/bus/memory/test_async.rb +0 -43
- data/spec/unit/event/bus/memory/test_sync.rb +0 -43
- data/spec/unit/support/hooks/test_after_hook.rb +0 -54
- data/spec/unit/support/hooks/test_before_hook.rb +0 -54
- data/spec/unit/support/operation_runner/test_around_run.rb +0 -156
- data/spec/unit/support/operation_runner/test_before_after_call.rb +0 -48
- data/spec/unit/support/test_data_object.rb +0 -156
- data/spec/unit/support/test_env.rb +0 -75
- data/spec/unit/support/test_robusteness.rb +0 -229
- data/spec/unit/support/test_transaction_manager.rb +0 -64
- data/spec/unit/support/test_world.rb +0 -72
- data/spec/unit/test_event.rb +0 -62
- data/spec/unit/test_operation.rb +0 -55
- data/spec/unit/test_support.rb +0 -40
- data/spec/unit/web/fixtures/assets/app/hello.es6 +0 -4
- data/spec/unit/web/fixtures/assets/app/hello.html +0 -1
- data/spec/unit/web/fixtures/assets/index.es6 +0 -1
- data/spec/unit/web/test_api.rb +0 -82
- data/spec/unit/web/test_auto_caching.rb +0 -81
- data/spec/unit/web/test_catch_all.rb +0 -77
- data/spec/unit/web/test_cors_headers.rb +0 -88
- data/spec/unit/web/test_healthcheck.rb +0 -59
- 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
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.
|
|
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-
|
|
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.
|
|
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.
|
|
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
|
-
-
|
|
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/
|
|
149
|
-
- lib/startback/
|
|
150
|
-
- lib/startback/
|
|
151
|
-
- lib/startback/
|
|
152
|
-
- lib/startback/
|
|
153
|
-
- lib/startback/
|
|
154
|
-
- lib/startback/
|
|
155
|
-
- lib/startback/
|
|
156
|
-
- lib/startback/
|
|
157
|
-
- lib/startback/
|
|
158
|
-
- lib/startback/
|
|
159
|
-
- lib/startback/
|
|
160
|
-
- lib/startback/
|
|
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/
|
|
181
|
-
- spec/unit/
|
|
182
|
-
- spec/unit/
|
|
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
|
data/lib/startback/audit.rb
DELETED