startback-websocket 0.14.0 → 0.14.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -1,84 +0,0 @@
|
|
1
|
-
module Startback
|
2
|
-
class Event
|
3
|
-
#
|
4
|
-
# An agent listen to specific events and react with its
|
5
|
-
# `call` method.
|
6
|
-
#
|
7
|
-
# This class is intended to be subclasses and the following
|
8
|
-
# methods overriden:
|
9
|
-
#
|
10
|
-
# - install_listeners that installs sync and async listeners
|
11
|
-
# - call to create a context and implement reaction behavior
|
12
|
-
#
|
13
|
-
class Agent
|
14
|
-
include Support::OperationRunner
|
15
|
-
include Support::Robustness
|
16
|
-
|
17
|
-
def initialize(engine)
|
18
|
-
@engine = engine
|
19
|
-
@context = nil
|
20
|
-
install_listeners
|
21
|
-
end
|
22
|
-
attr_reader :engine
|
23
|
-
attr_accessor :context
|
24
|
-
protected :context=
|
25
|
-
|
26
|
-
protected
|
27
|
-
|
28
|
-
# Installs the various event handlers by calling `sync`
|
29
|
-
# and `async` methods.
|
30
|
-
#
|
31
|
-
# This method is intended to be overriden.
|
32
|
-
def install_listeners
|
33
|
-
end
|
34
|
-
|
35
|
-
# Returns the underlying bus
|
36
|
-
def bus
|
37
|
-
engine.bus
|
38
|
-
end
|
39
|
-
|
40
|
-
# Asynchronously listen to a specific event.
|
41
|
-
#
|
42
|
-
# See Bus#listen
|
43
|
-
def async(exchange, queue)
|
44
|
-
bus.async.listen(exchange, queue) do |event_data|
|
45
|
-
event = engine.factor_event(event_data)
|
46
|
-
with_context(event.context).call(event)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
# Synchronously listen to a specific event.
|
51
|
-
#
|
52
|
-
# See Bus#listen
|
53
|
-
def sync(exchange, queue)
|
54
|
-
bus.listen(exchange, queue) do |event_data|
|
55
|
-
event = engine.factor_event(event_data)
|
56
|
-
with_context(event.context).call(event)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
# Reacts to a specific event.
|
61
|
-
#
|
62
|
-
# This method must be implemented by subclasses and raises
|
63
|
-
# an error by default.
|
64
|
-
def call(event = nil)
|
65
|
-
log(:fatal, {
|
66
|
-
op: self.class,
|
67
|
-
op_data: event,
|
68
|
-
error: %Q{Unexpected call to Startback::Event::Agent#call},
|
69
|
-
backtrace: caller
|
70
|
-
})
|
71
|
-
raise NotImplementedError
|
72
|
-
end
|
73
|
-
|
74
|
-
def with_context(context)
|
75
|
-
dup.tap{|a| a.send(:context=, context) }
|
76
|
-
end
|
77
|
-
|
78
|
-
def operation_world(op)
|
79
|
-
super(op).merge(context: context)
|
80
|
-
end
|
81
|
-
|
82
|
-
end # class Agent
|
83
|
-
end # class Event
|
84
|
-
end # module Starback
|
@@ -1,162 +0,0 @@
|
|
1
|
-
require 'bunny'
|
2
|
-
module Startback
|
3
|
-
class Event
|
4
|
-
class Bus
|
5
|
-
module Bunny
|
6
|
-
#
|
7
|
-
# Asynchronous implementation of the bus abstraction, on top of RabbitMQ
|
8
|
-
# and using the 'bunny' gem (you need to include it in your Gemfile
|
9
|
-
# yourself: it is NOT a startback official dependency).
|
10
|
-
#
|
11
|
-
# This bus implementation emits events by dumping them to RabbitMQ using
|
12
|
-
# the event type as exchange name. Listeners may use the `processor`
|
13
|
-
# parameter to specify the queue name ; otherwise a default "main" queue
|
14
|
-
# is used.
|
15
|
-
#
|
16
|
-
# Examples:
|
17
|
-
#
|
18
|
-
# # Connects to RabbitMQ using all default options
|
19
|
-
# #
|
20
|
-
# # Uses the STARTBACK_BUS_BUNNY_ASYNC_URL environment variable for
|
21
|
-
# # connection URL if present.
|
22
|
-
# Startback::Bus::Bunny::Async.new
|
23
|
-
#
|
24
|
-
# # Connects to RabbitMQ using a specific URL
|
25
|
-
# Startback::Bus::Bunny::Async.new("amqp://rabbituser:rabbitpass@192.168.17.17")
|
26
|
-
# Startback::Bus::Bunny::Async.new(url: "amqp://rabbituser:rabbitpass@192.168.17.17")
|
27
|
-
#
|
28
|
-
# # Connects to RabbitMQ using specific connection options. See Bunny's own
|
29
|
-
# # documentation
|
30
|
-
# Startback::Bus::Bunny::Async.new({
|
31
|
-
# connection_options: {
|
32
|
-
# host: "192.168.17.17"
|
33
|
-
# }
|
34
|
-
# })
|
35
|
-
#
|
36
|
-
class Async
|
37
|
-
include Support::Robustness
|
38
|
-
|
39
|
-
CHANNEL_KEY = 'Startback::Bus::Bunny::Async::ChannelKey'
|
40
|
-
|
41
|
-
DEFAULT_OPTIONS = {
|
42
|
-
# (optional) The URL to use for connecting to RabbitMQ.
|
43
|
-
url: ENV['STARTBACK_BUS_BUNNY_ASYNC_URL'],
|
44
|
-
|
45
|
-
# (optional) The options has to pass to ::Bunny constructor
|
46
|
-
connection_options: nil,
|
47
|
-
|
48
|
-
# (optional) The options to use for the emitter/listener fanout
|
49
|
-
fanout_options: {},
|
50
|
-
|
51
|
-
# (optional) The options to use for the listener queue
|
52
|
-
queue_options: {},
|
53
|
-
|
54
|
-
# (optional) Default event factory to use, if any
|
55
|
-
event_factory: nil,
|
56
|
-
|
57
|
-
# (optional) A default context to use for general logging
|
58
|
-
context: nil,
|
59
|
-
|
60
|
-
# (optional) Size of consumer pool
|
61
|
-
consumer_pool_size: 1,
|
62
|
-
|
63
|
-
# (optional) Whether the program must be aborted on consumption
|
64
|
-
# error
|
65
|
-
abort_on_exception: true,
|
66
|
-
|
67
|
-
# (optional) Whether connection occurs immediately,
|
68
|
-
# or on demand later
|
69
|
-
autoconnect: false
|
70
|
-
}
|
71
|
-
|
72
|
-
# Creates a bus instance, using the various options provided to
|
73
|
-
# fine-tune behavior.
|
74
|
-
def initialize(options = {})
|
75
|
-
options = { url: options } if options.is_a?(String)
|
76
|
-
@options = DEFAULT_OPTIONS.merge(options)
|
77
|
-
connect if @options[:autoconnect]
|
78
|
-
end
|
79
|
-
attr_reader :options
|
80
|
-
|
81
|
-
def connect
|
82
|
-
disconnect
|
83
|
-
conn = options[:connection_options] || options[:url]
|
84
|
-
try_max_times(10) do
|
85
|
-
@bunny = ::Bunny.new(conn)
|
86
|
-
@bunny.start
|
87
|
-
channel # make sure we already create the channel
|
88
|
-
log(:info, {op: "#{self.class.name}#connect", op_data: conn}, options[:context])
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
def disconnect
|
93
|
-
if channel = Thread.current[CHANNEL_KEY]
|
94
|
-
channel.close
|
95
|
-
Thread.current[CHANNEL_KEY] = nil
|
96
|
-
end
|
97
|
-
@bunny.close if @bunny
|
98
|
-
end
|
99
|
-
|
100
|
-
def channel
|
101
|
-
unless @bunny
|
102
|
-
raise Startback::Errors::Error, "Please connect your bus first, or use autoconnect: true"
|
103
|
-
end
|
104
|
-
|
105
|
-
Thread.current[CHANNEL_KEY] ||= @bunny.create_channel(
|
106
|
-
nil,
|
107
|
-
consumer_pool_size, # consumer_pool_size
|
108
|
-
abort_on_exception? # consumer_pool_abort_on_exception
|
109
|
-
)
|
110
|
-
end
|
111
|
-
|
112
|
-
def emit(event)
|
113
|
-
stop_errors(self, "emit", event.context) do
|
114
|
-
fanout = channel.fanout(event.type.to_s, fanout_options)
|
115
|
-
fanout.publish(event.to_json)
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
def listen(type, processor = nil, listener = nil, &bl)
|
120
|
-
raise ArgumentError, "A listener must be provided" unless listener || bl
|
121
|
-
|
122
|
-
fanout = channel.fanout(type.to_s, fanout_options)
|
123
|
-
queue = channel.queue((processor || "main").to_s, queue_options)
|
124
|
-
queue.bind(fanout)
|
125
|
-
queue.subscribe do |delivery_info, properties, body|
|
126
|
-
stop_errors(self, "listen") do
|
127
|
-
(listener || bl).call(body)
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
protected
|
133
|
-
|
134
|
-
def consumer_pool_size
|
135
|
-
options[:consumer_pool_size]
|
136
|
-
end
|
137
|
-
|
138
|
-
def abort_on_exception?
|
139
|
-
options[:abort_on_exception]
|
140
|
-
end
|
141
|
-
|
142
|
-
def fanout_options
|
143
|
-
options[:fanout_options]
|
144
|
-
end
|
145
|
-
|
146
|
-
def queue_options
|
147
|
-
options[:queue_options]
|
148
|
-
end
|
149
|
-
|
150
|
-
def factor_event(body)
|
151
|
-
if options[:event_factory]
|
152
|
-
options[:event_factory].call(body)
|
153
|
-
else
|
154
|
-
Event.json(body, options)
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
end # class Async
|
159
|
-
end # module Bunny
|
160
|
-
end # class Bus
|
161
|
-
end # class Event
|
162
|
-
end # module Startback
|
@@ -1 +0,0 @@
|
|
1
|
-
require_relative 'bunny/async'
|
@@ -1,45 +0,0 @@
|
|
1
|
-
module Startback
|
2
|
-
class Event
|
3
|
-
class Bus
|
4
|
-
module Memory
|
5
|
-
#
|
6
|
-
# Asynchronous implementation of the Bus abstraction, for use between
|
7
|
-
# components sharing the same process.
|
8
|
-
#
|
9
|
-
# This implementation actually calls listeners synchronously (it mays)
|
10
|
-
# but hides error raised by them. See Bus::Bunny::Async for another
|
11
|
-
# implementation that is truly asynchronous and relies on RabbitMQ.
|
12
|
-
#
|
13
|
-
class Async
|
14
|
-
include Support::Robustness
|
15
|
-
|
16
|
-
DEFAULT_OPTIONS = {
|
17
|
-
}
|
18
|
-
|
19
|
-
def initialize(options = {})
|
20
|
-
@options = DEFAULT_OPTIONS.merge(options)
|
21
|
-
@listeners = {}
|
22
|
-
end
|
23
|
-
|
24
|
-
def connect
|
25
|
-
end
|
26
|
-
|
27
|
-
def emit(event)
|
28
|
-
(@listeners[event.type.to_s] || []).each do |l|
|
29
|
-
stop_errors(self, "emit", event) {
|
30
|
-
l.call(event)
|
31
|
-
}
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def listen(type, processor = nil, listener = nil, &bl)
|
36
|
-
raise ArgumentError, "A listener must be provided" unless listener || bl
|
37
|
-
@listeners[type.to_s] ||= []
|
38
|
-
@listeners[type.to_s] << (listener || bl)
|
39
|
-
end
|
40
|
-
|
41
|
-
end # class Sync
|
42
|
-
end # module Memory
|
43
|
-
end # class Bus
|
44
|
-
end # class Event
|
45
|
-
end # module Startback
|
@@ -1,35 +0,0 @@
|
|
1
|
-
module Startback
|
2
|
-
class Event
|
3
|
-
class Bus
|
4
|
-
module Memory
|
5
|
-
#
|
6
|
-
# Synchronous implementation of the Bus abstraction, for use between
|
7
|
-
# components sharing the same process.
|
8
|
-
#
|
9
|
-
class Sync
|
10
|
-
include Support::Robustness
|
11
|
-
|
12
|
-
def initialize
|
13
|
-
@listeners = {}
|
14
|
-
end
|
15
|
-
|
16
|
-
def connect
|
17
|
-
end
|
18
|
-
|
19
|
-
def emit(event)
|
20
|
-
(@listeners[event.type.to_s] || []).each do |l|
|
21
|
-
l.call(event)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def listen(type, processor = nil, listener = nil, &bl)
|
26
|
-
raise ArgumentError, "A listener must be provided" unless listener || bl
|
27
|
-
@listeners[type.to_s] ||= []
|
28
|
-
@listeners[type.to_s] << (listener || bl)
|
29
|
-
end
|
30
|
-
|
31
|
-
end # class Sync
|
32
|
-
end # module Memory
|
33
|
-
end # class Bus
|
34
|
-
end # class Event
|
35
|
-
end # module Startback
|
data/lib/startback/event/bus.rb
DELETED
@@ -1,100 +0,0 @@
|
|
1
|
-
module Startback
|
2
|
-
class Event
|
3
|
-
#
|
4
|
-
# Sync and async bus abstraction allowing to register listeners and
|
5
|
-
# emitting events towards them.
|
6
|
-
#
|
7
|
-
# This bus actually decorates two busses, one in synchronous and the
|
8
|
-
# other one is asynchronous (optional).
|
9
|
-
#
|
10
|
-
# * A synchronous bus MUST call the listeners as part of emitting
|
11
|
-
# process, and MUST re-raise any error occuring during that process.
|
12
|
-
# See, e.g. Startback::Bus::Memory::Sync
|
13
|
-
#
|
14
|
-
# * An asynchronous bus MAY call the listeners later, but MUST hide
|
15
|
-
# errors to the emitter.
|
16
|
-
# See, e.g. Startback::Bus::Memory::Async
|
17
|
-
#
|
18
|
-
# This bus facade emits events to both sync and async busses (if any),
|
19
|
-
# and listen on the sync one by default.
|
20
|
-
#
|
21
|
-
# For emitters:
|
22
|
-
#
|
23
|
-
# # This will synchronously call every listeners who `listen`
|
24
|
-
# # on the synchronous bus (& reraise exceptions) then call
|
25
|
-
# # (possibly later) all listeners who `listen` on the
|
26
|
-
# # asynchronous bus if any (& hide exceptions).
|
27
|
-
# bus.emit(event)
|
28
|
-
#
|
29
|
-
# # This only reaches sync listeners
|
30
|
-
# bus.sync.emit(event)
|
31
|
-
#
|
32
|
-
# # This only reaches async listeners (an async bus must be set)
|
33
|
-
# bus.async.emit(event)
|
34
|
-
#
|
35
|
-
# Please note that there is currently no way to reach sync listeners
|
36
|
-
# without having to implement error handling on the emitter side.
|
37
|
-
#
|
38
|
-
# For listeners:
|
39
|
-
#
|
40
|
-
# # This will listen synchronously and make the emitter fail if
|
41
|
-
# # anything goes wrong with the callback:
|
42
|
-
# bus.listen(event_type) do |event|
|
43
|
-
# ...
|
44
|
-
# end
|
45
|
-
#
|
46
|
-
# # It is a shortcut for:
|
47
|
-
# bus.sync.listen(event_type) do |event| ... end
|
48
|
-
#
|
49
|
-
# This will listen asynchronously and could not make the emitter
|
50
|
-
# fail if something goes wrong with the callback.
|
51
|
-
# bus.async.listen(event_type) do |event|
|
52
|
-
# ...
|
53
|
-
# end
|
54
|
-
#
|
55
|
-
# Feel free to access the sync and async busses directly for specific
|
56
|
-
# cases though.
|
57
|
-
#
|
58
|
-
class Bus
|
59
|
-
include Support::Robustness
|
60
|
-
|
61
|
-
def initialize(sync = Memory::Sync.new, async = nil)
|
62
|
-
@sync = sync
|
63
|
-
@async = async
|
64
|
-
end
|
65
|
-
attr_reader :sync, :async
|
66
|
-
|
67
|
-
def connect
|
68
|
-
sync.connect if sync
|
69
|
-
async.connect if async
|
70
|
-
end
|
71
|
-
|
72
|
-
# Emits a particular event to the listeners.
|
73
|
-
#
|
74
|
-
# @arg event an event, should be an Event instance (through duck
|
75
|
-
# typing is allowed)
|
76
|
-
def emit(event)
|
77
|
-
monitor({
|
78
|
-
op: "Startback::Bus#emit",
|
79
|
-
op_data: {
|
80
|
-
event: { type: event.type }
|
81
|
-
}
|
82
|
-
}, event.context) do
|
83
|
-
sync.emit(event)
|
84
|
-
async.emit(event) if async
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
# Registers `listener` as being interested in receiving events of
|
89
|
-
# a specific type.
|
90
|
-
#
|
91
|
-
# @arg type: Symbol, the type of event the listener is interested in.
|
92
|
-
# @arg listener: Proc, the listener itself.
|
93
|
-
def listen(type, processor = nil, listener = nil, &bl)
|
94
|
-
sync.listen(type, processor, listener, &bl)
|
95
|
-
end
|
96
|
-
|
97
|
-
end # class Bus
|
98
|
-
end # class Event
|
99
|
-
end # module Startback
|
100
|
-
require_relative 'bus/memory'
|
@@ -1,94 +0,0 @@
|
|
1
|
-
require 'rack'
|
2
|
-
require 'startback'
|
3
|
-
module Startback
|
4
|
-
class Event
|
5
|
-
#
|
6
|
-
# This class is the starting point of event handling in
|
7
|
-
# Startback. It holds a Bus instance to which emitters
|
8
|
-
# and listeners can connect.
|
9
|
-
#
|
10
|
-
# The Engine exposes a rack app (.rack_app) with a /healthcheck webservice.
|
11
|
-
# It is supposed to be mounted to a webserver such as puma.
|
12
|
-
#
|
13
|
-
# This class goes hand in hand with the `startback:engine`
|
14
|
-
# docker image. It can be extended by subclasses to override
|
15
|
-
# the following methods:
|
16
|
-
#
|
17
|
-
# - bus to use something else than a simple memory bus
|
18
|
-
# - on_health_check to check specific health conditions
|
19
|
-
# - create_agents to instantiate all listening agents
|
20
|
-
# (unless auto_create_agents is used)
|
21
|
-
# - rack_app if you want to customize the API running
|
22
|
-
#
|
23
|
-
class Engine
|
24
|
-
include Support::Robustness
|
25
|
-
|
26
|
-
DEFAULT_OPTIONS = {
|
27
|
-
|
28
|
-
}
|
29
|
-
|
30
|
-
def initialize(options = {}, context = Context.new)
|
31
|
-
@options = DEFAULT_OPTIONS.merge(options)
|
32
|
-
@context = context
|
33
|
-
@context.engine = self
|
34
|
-
end
|
35
|
-
attr_reader :options, :context
|
36
|
-
|
37
|
-
class << self
|
38
|
-
def auto_create_agents?
|
39
|
-
!!@auto_create_agents
|
40
|
-
end
|
41
|
-
|
42
|
-
# Register a base class which will be used to discover
|
43
|
-
# the agents to start when the engine is ran.
|
44
|
-
def auto_create_agents(base_class = nil)
|
45
|
-
@auto_create_agents ||= base_class
|
46
|
-
@auto_create_agents
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
# This method is executed on health check and can be
|
51
|
-
# overriden by subclasses to perform specific checks.
|
52
|
-
def on_health_check
|
53
|
-
"Ok"
|
54
|
-
end
|
55
|
-
|
56
|
-
def bus
|
57
|
-
@bus ||= ::Startback::Event::Bus.new
|
58
|
-
end
|
59
|
-
|
60
|
-
def connect
|
61
|
-
log(:info, self, "Connecting to the bus now!")
|
62
|
-
bus.connect
|
63
|
-
end
|
64
|
-
|
65
|
-
def create_agents
|
66
|
-
return unless parent = self.class.auto_create_agents
|
67
|
-
|
68
|
-
ObjectSpace
|
69
|
-
.each_object(Class)
|
70
|
-
.select { |klass| klass <= parent }
|
71
|
-
.each { |klass| klass.new(self) }
|
72
|
-
end
|
73
|
-
|
74
|
-
def factor_event(event_data)
|
75
|
-
Event.json(event_data, context)
|
76
|
-
end
|
77
|
-
|
78
|
-
def rack_app
|
79
|
-
engine = self
|
80
|
-
Rack::Builder.new do
|
81
|
-
use Startback::Web::CatchAll
|
82
|
-
|
83
|
-
map '/health-check' do
|
84
|
-
health = Startback::Web::HealthCheck.new {
|
85
|
-
engine.on_health_check
|
86
|
-
}
|
87
|
-
run(health)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
end # class Engine
|
93
|
-
end # class Event
|
94
|
-
end # module Startback
|
@@ -1,13 +0,0 @@
|
|
1
|
-
module Startback
|
2
|
-
class Operation
|
3
|
-
|
4
|
-
def self.emits(type, &bl)
|
5
|
-
after_call do
|
6
|
-
event_data = instance_exec(&bl)
|
7
|
-
event = type.new(type.to_s, event_data, context)
|
8
|
-
context.engine.bus.emit(event)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
end # class Operation
|
13
|
-
end # module Startback
|
data/lib/startback/event.rb
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
module Startback
|
2
|
-
#
|
3
|
-
# An Event occuring a given context and having a type and attached data.
|
4
|
-
#
|
5
|
-
# Event instances have String types that are by default unrelated to ruby
|
6
|
-
# classes. Also, this Event class has a `json` information contract that
|
7
|
-
# allows dumping & reloading them easily. A context or context_factory may
|
8
|
-
# be provided in dress world to reload the event context from data, but
|
9
|
-
# that logic is opaque to this class.
|
10
|
-
#
|
11
|
-
# This class is intended to be subclassed if a more specific event protocol
|
12
|
-
# is wanted.
|
13
|
-
#
|
14
|
-
class Event
|
15
|
-
|
16
|
-
def initialize(type, data, context = nil)
|
17
|
-
@type = type.to_s
|
18
|
-
@data = OpenStruct.new(data)
|
19
|
-
@context = context
|
20
|
-
end
|
21
|
-
attr_reader :context, :type, :data
|
22
|
-
|
23
|
-
def self.json(src, context)
|
24
|
-
return src if src.is_a?(Event)
|
25
|
-
|
26
|
-
parsed = JSON.parse(src)
|
27
|
-
klass = Kernel.const_get(parsed['type'])
|
28
|
-
context = context.fork(parsed['context']) if context
|
29
|
-
klass.new(parsed['type'], parsed['data'], context)
|
30
|
-
end
|
31
|
-
|
32
|
-
def to_json(*args, &bl)
|
33
|
-
h = {
|
34
|
-
type: self.type,
|
35
|
-
data: data.to_h
|
36
|
-
}
|
37
|
-
h[:context] = context if context
|
38
|
-
h.to_json(*args, &bl)
|
39
|
-
end
|
40
|
-
|
41
|
-
end # class Event
|
42
|
-
end # module Startback
|
43
|
-
require_relative 'event/ext/context'
|
44
|
-
require_relative 'event/ext/operation'
|
45
|
-
require_relative 'event/agent'
|
46
|
-
require_relative 'event/bus'
|
47
|
-
require_relative 'event/engine'
|
data/lib/startback/ext/time.rb
DELETED
data/lib/startback/model.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
module Startback
|
2
|
-
class Operation
|
3
|
-
class ErrorOperation < Operation
|
4
|
-
|
5
|
-
def initialize(details)
|
6
|
-
@details = details
|
7
|
-
end
|
8
|
-
attr_reader :details
|
9
|
-
|
10
|
-
def call
|
11
|
-
end
|
12
|
-
|
13
|
-
def bind(world)
|
14
|
-
self
|
15
|
-
end
|
16
|
-
|
17
|
-
end # class ErrorOperation
|
18
|
-
end # class Operation
|
19
|
-
end # module Startback
|
@@ -1,28 +0,0 @@
|
|
1
|
-
module Startback
|
2
|
-
class Operation
|
3
|
-
class MultiOperation < Operation
|
4
|
-
|
5
|
-
def initialize(ops = [])
|
6
|
-
@ops = ops
|
7
|
-
end
|
8
|
-
attr_reader :ops
|
9
|
-
|
10
|
-
def size
|
11
|
-
ops.size
|
12
|
-
end
|
13
|
-
|
14
|
-
def +(other)
|
15
|
-
MultiOperation.new(@ops + Array(other))
|
16
|
-
end
|
17
|
-
|
18
|
-
def bind(world)
|
19
|
-
MultiOperation.new(ops.map{|op| op.bind(world) })
|
20
|
-
end
|
21
|
-
|
22
|
-
def call
|
23
|
-
ops.map{|op| op.call }
|
24
|
-
end
|
25
|
-
|
26
|
-
end # class MultiOperation
|
27
|
-
end # class Operation
|
28
|
-
end # module Startback
|