realm-core 0.7.1 → 0.7.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +40 -0
- data/Rakefile +19 -0
- metadata +25 -44
- data/lib/realm-core.rb +0 -6
- data/lib/realm.rb +0 -22
- data/lib/realm/action_handler.rb +0 -84
- data/lib/realm/action_handler/result.rb +0 -32
- data/lib/realm/builder.rb +0 -93
- data/lib/realm/command_handler.rb +0 -23
- data/lib/realm/config.rb +0 -57
- data/lib/realm/container.rb +0 -68
- data/lib/realm/context.rb +0 -37
- data/lib/realm/dependency.rb +0 -24
- data/lib/realm/dispatcher.rb +0 -74
- data/lib/realm/domain_resolver.rb +0 -59
- data/lib/realm/error.rb +0 -62
- data/lib/realm/event.rb +0 -56
- data/lib/realm/event_factory.rb +0 -53
- data/lib/realm/event_handler.rb +0 -102
- data/lib/realm/event_router.rb +0 -100
- data/lib/realm/event_router/gateway.rb +0 -50
- data/lib/realm/event_router/internal_loop_gateway.rb +0 -50
- data/lib/realm/health_status.rb +0 -46
- data/lib/realm/mixins/aggregate_member.rb +0 -25
- data/lib/realm/mixins/context_injection.rb +0 -49
- data/lib/realm/mixins/controller.rb +0 -53
- data/lib/realm/mixins/decorator.rb +0 -33
- data/lib/realm/mixins/dependency_injection.rb +0 -52
- data/lib/realm/mixins/reactive.rb +0 -32
- data/lib/realm/mixins/repository_helper.rb +0 -43
- data/lib/realm/multi_worker.rb +0 -30
- data/lib/realm/persistence.rb +0 -54
- data/lib/realm/persistence/repository_query_handler_adapter.rb +0 -24
- data/lib/realm/plugin.rb +0 -20
- data/lib/realm/query_handler.rb +0 -8
- data/lib/realm/runtime.rb +0 -61
- data/lib/realm/runtime/session.rb +0 -33
- data/lib/realm/types.rb +0 -9
data/lib/realm/event_factory.rb
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'realm/error'
|
4
|
-
require 'realm/event'
|
5
|
-
|
6
|
-
module Realm
|
7
|
-
class EventFactory
|
8
|
-
def initialize(events_module)
|
9
|
-
@events_module = events_module
|
10
|
-
@event_class_map = collect_event_classes(events_module)
|
11
|
-
end
|
12
|
-
|
13
|
-
def create_event(event_type, correlate: nil, cause: nil, **attributes)
|
14
|
-
head = enhance_head(attributes.fetch(:head, {}), correlate: correlate, cause: cause)
|
15
|
-
body = attributes.fetch(:body, attributes.except(:head))
|
16
|
-
|
17
|
-
event_class_for(event_type).new(head: head, body: body)
|
18
|
-
end
|
19
|
-
|
20
|
-
def event_class_for(event_type)
|
21
|
-
return event_type if event_type.respond_to?(:new)
|
22
|
-
|
23
|
-
@event_class_map.fetch(event_type.to_s) do
|
24
|
-
raise EventClassMissing.new(event_type, @events_module)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def collect_event_classes(root_module)
|
31
|
-
root_module_str = root_module.to_s
|
32
|
-
root_module.constants.each_with_object({}) do |const_sym, all|
|
33
|
-
const = root_module.const_get(const_sym)
|
34
|
-
if !(const < Event) && const.to_s.start_with?(root_module_str)
|
35
|
-
all.merge!(collect_event_classes(const))
|
36
|
-
elsif const < Event
|
37
|
-
all[const.type] = const
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def enhance_head(head, correlate:, cause:)
|
43
|
-
head[:correlation_id] = correlate.head.correlation_id if correlate
|
44
|
-
if cause.is_a?(Event)
|
45
|
-
head[:cause_event_id] = cause.head.id
|
46
|
-
head[:correlation_id] ||= cause.head.correlation_id
|
47
|
-
elsif cause
|
48
|
-
head[:cause] = cause
|
49
|
-
end
|
50
|
-
head
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
data/lib/realm/event_handler.rb
DELETED
@@ -1,102 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'active_support/core_ext/string'
|
4
|
-
require 'realm/persistence'
|
5
|
-
require 'realm/mixins/context_injection'
|
6
|
-
require 'realm/mixins/reactive'
|
7
|
-
require 'realm/mixins/repository_helper'
|
8
|
-
require 'realm/mixins/aggregate_member'
|
9
|
-
|
10
|
-
module Realm
|
11
|
-
class EventHandler
|
12
|
-
extend Mixins::ContextInjection::ClassMethods
|
13
|
-
include Mixins::AggregateMember
|
14
|
-
include Mixins::Reactive
|
15
|
-
include Mixins::RepositoryHelper
|
16
|
-
|
17
|
-
class RuntimeBound
|
18
|
-
delegate :identifier, :event_types, to: :@handler_class
|
19
|
-
|
20
|
-
def initialize(handler_class, runtime)
|
21
|
-
@handler_class = handler_class
|
22
|
-
@runtime = runtime
|
23
|
-
end
|
24
|
-
|
25
|
-
def call(event)
|
26
|
-
@handler_class.(event, runtime: @runtime.session(cause: event))
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
class << self
|
31
|
-
attr_reader :trigger_mapping, :event_namespace
|
32
|
-
|
33
|
-
def bind_runtime(runtime)
|
34
|
-
RuntimeBound.new(self, runtime)
|
35
|
-
end
|
36
|
-
|
37
|
-
def call(event, runtime:)
|
38
|
-
new(runtime: runtime).(event)
|
39
|
-
end
|
40
|
-
|
41
|
-
def identifier(value = :undefined)
|
42
|
-
if value == :undefined
|
43
|
-
defined?(@identifier) ? @identifier : name.gsub(/(Domain|(Event)?Handlers?)/, '').underscore.gsub(%r{/+}, '-')
|
44
|
-
else
|
45
|
-
@identifier = value
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def event_types
|
50
|
-
defined?(@trigger_mapping) ? @trigger_mapping.keys.uniq : []
|
51
|
-
end
|
52
|
-
|
53
|
-
protected
|
54
|
-
|
55
|
-
def namespace(value)
|
56
|
-
@event_namespace = value
|
57
|
-
end
|
58
|
-
|
59
|
-
def on(*triggers, run: nil, **options, &block)
|
60
|
-
@method_triggers = triggers
|
61
|
-
@method_trigger_options = options # TODO: store and pass to gateway
|
62
|
-
return unless run || block
|
63
|
-
|
64
|
-
block = ->(event) { self.run(run, event.body) } if run
|
65
|
-
define_method("handle_#{triggers.join('_or_')}", &block)
|
66
|
-
end
|
67
|
-
|
68
|
-
def method_added(method_name)
|
69
|
-
super
|
70
|
-
return unless defined?(@method_triggers)
|
71
|
-
|
72
|
-
@trigger_mapping ||= {}
|
73
|
-
@method_triggers.each do |trigger|
|
74
|
-
(@trigger_mapping[trigger.to_sym] ||= []) << method_name
|
75
|
-
end
|
76
|
-
remove_instance_variable(:@method_triggers)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def initialize(runtime: nil)
|
81
|
-
@runtime = runtime
|
82
|
-
end
|
83
|
-
|
84
|
-
def call(event)
|
85
|
-
event_to_methods(event).each do |method_name|
|
86
|
-
send(method_name, event)
|
87
|
-
rescue Realm::Persistence::Conflict => e
|
88
|
-
context[:logger]&.warn(e.full_message)
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
protected
|
93
|
-
|
94
|
-
delegate :context, to: :@runtime
|
95
|
-
|
96
|
-
private
|
97
|
-
|
98
|
-
def event_to_methods(event)
|
99
|
-
self.class.trigger_mapping.fetch_values(event.type.to_sym, :any) { [] }.flatten
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
data/lib/realm/event_router.rb
DELETED
@@ -1,100 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'active_support/core_ext/string'
|
4
|
-
require 'active_support/core_ext/hash'
|
5
|
-
require 'realm/error'
|
6
|
-
require 'realm/domain_resolver'
|
7
|
-
require 'realm/event_handler'
|
8
|
-
require 'realm/event_factory'
|
9
|
-
require 'realm/mixins/dependency_injection'
|
10
|
-
require_relative 'event_router/internal_loop_gateway'
|
11
|
-
|
12
|
-
module Realm
|
13
|
-
class EventRouter
|
14
|
-
include Mixins::DependencyInjection
|
15
|
-
inject DomainResolver
|
16
|
-
inject 'Realm::Runtime', lazy: true
|
17
|
-
|
18
|
-
def initialize(gateways_spec, prefix: nil)
|
19
|
-
@prefix = prefix
|
20
|
-
@auto_registered = false
|
21
|
-
@default_namespace = nil
|
22
|
-
init_gateways(gateways_spec)
|
23
|
-
end
|
24
|
-
|
25
|
-
def register(handler_class)
|
26
|
-
gateway_for(handler_class.try(:event_namespace)).register(handler_class)
|
27
|
-
end
|
28
|
-
|
29
|
-
def add_listener(event_type, listener, namespace: nil)
|
30
|
-
gateway_for(namespace).add_listener(event_type, listener)
|
31
|
-
end
|
32
|
-
|
33
|
-
def trigger(identifier, attributes = {})
|
34
|
-
namespace, event_type = identifier.to_s.include?('/') ? identifier.split('/') : [nil, identifier]
|
35
|
-
gateway_for(namespace).trigger(event_type, attributes)
|
36
|
-
end
|
37
|
-
|
38
|
-
def workers(*namespaces, **options)
|
39
|
-
auto_register_handlers
|
40
|
-
@gateways.filter_map do |(namespace, gateway)|
|
41
|
-
gateway.worker(**options) if namespaces.empty? || namespaces.include?(namespace)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def active_queues
|
46
|
-
auto_register_handlers
|
47
|
-
@gateways.values.reduce([]) do |queues, gateway|
|
48
|
-
queues + gateway.queues
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
private
|
53
|
-
|
54
|
-
def init_gateways(gateways_spec)
|
55
|
-
auto_register_on_init = false
|
56
|
-
@gateways = gateways_spec.each_with_object({}) do |(namespace, config), gateways|
|
57
|
-
gateway_class = gateway_class(config.fetch(:type))
|
58
|
-
auto_register_on_init ||= gateway_class.auto_register_on_init
|
59
|
-
gateways[namespace] = instantiate_gateway(namespace, gateway_class, config)
|
60
|
-
@default_namespace = namespace if config[:default]
|
61
|
-
end
|
62
|
-
auto_register_handlers if auto_register_on_init
|
63
|
-
end
|
64
|
-
|
65
|
-
def gateway_class(type)
|
66
|
-
return InternalLoopGateway if type.to_s == 'internal_loop'
|
67
|
-
|
68
|
-
runtime.container.resolve("event_router.gateway_classes.#{type}")
|
69
|
-
end
|
70
|
-
|
71
|
-
def instantiate_gateway(namespace, klass, config)
|
72
|
-
klass.new(
|
73
|
-
namespace: namespace,
|
74
|
-
queue_prefix: @prefix,
|
75
|
-
event_factory: EventFactory.new(config.fetch(:events_module)),
|
76
|
-
runtime: runtime,
|
77
|
-
**config.except(:type, :default, :events_module),
|
78
|
-
)
|
79
|
-
end
|
80
|
-
|
81
|
-
def auto_register_handlers
|
82
|
-
return if @auto_registered || !domain_resolver
|
83
|
-
|
84
|
-
@auto_registered = true
|
85
|
-
domain_resolver.all_event_handlers.each { |klass| register(klass) }
|
86
|
-
end
|
87
|
-
|
88
|
-
def gateway_for(namespace)
|
89
|
-
@gateways.fetch(namespace.try(:to_sym) || default_namespace) do
|
90
|
-
raise "No event gateway for #{namespace || 'default'} namespace" # TODO: extract error class
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
def default_namespace
|
95
|
-
return @default_namespace if @default_namespace
|
96
|
-
|
97
|
-
@gateways.keys[0] if @gateways.keys.size == 1
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
@@ -1,50 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Realm
|
4
|
-
class EventRouter
|
5
|
-
class Gateway
|
6
|
-
def self.auto_register_on_init
|
7
|
-
false
|
8
|
-
end
|
9
|
-
|
10
|
-
def initialize(event_factory:, namespace: :default, runtime: nil, **)
|
11
|
-
@namespace = namespace
|
12
|
-
@event_factory = event_factory
|
13
|
-
@runtime = runtime
|
14
|
-
end
|
15
|
-
|
16
|
-
def register(handler_class)
|
17
|
-
# TODO: validate event_types for existence of matching class
|
18
|
-
handler_class.event_types.each do |event_type|
|
19
|
-
add_listener(event_type, handler_class.bind_runtime(@runtime))
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def add_listener(event_type, listener)
|
24
|
-
raise NotImplementedError
|
25
|
-
end
|
26
|
-
|
27
|
-
def trigger(event_type, attributes = {})
|
28
|
-
raise NotImplementedError
|
29
|
-
end
|
30
|
-
|
31
|
-
def worker(*)
|
32
|
-
nil
|
33
|
-
end
|
34
|
-
|
35
|
-
def cleanup
|
36
|
-
# do nothing
|
37
|
-
end
|
38
|
-
|
39
|
-
def queues
|
40
|
-
[]
|
41
|
-
end
|
42
|
-
|
43
|
-
protected
|
44
|
-
|
45
|
-
def create_event(event_type, attributes = {})
|
46
|
-
@event_factory.create_event(event_type, **attributes)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
@@ -1,50 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative './gateway'
|
4
|
-
|
5
|
-
module Realm
|
6
|
-
class EventRouter
|
7
|
-
class InternalLoopGateway < Gateway
|
8
|
-
def self.auto_register_on_init
|
9
|
-
true
|
10
|
-
end
|
11
|
-
|
12
|
-
def initialize(isolated: false, **)
|
13
|
-
super
|
14
|
-
@listener_map = {}
|
15
|
-
@isolated = isolated
|
16
|
-
gateways << self
|
17
|
-
end
|
18
|
-
|
19
|
-
def add_listener(event_type, listener)
|
20
|
-
(@listener_map[event_type.to_sym] ||= []) << listener
|
21
|
-
end
|
22
|
-
|
23
|
-
def trigger(event_type, attributes = {})
|
24
|
-
create_event(event_type, attributes).tap do |event|
|
25
|
-
gateways.each { |gateway| gateway.handle(event_type, event) }
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def purge!
|
30
|
-
gateways.clear
|
31
|
-
end
|
32
|
-
|
33
|
-
protected
|
34
|
-
|
35
|
-
def handle(event_type, event)
|
36
|
-
find_listeners(event_type).each { |listener| listener.(event) }
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
def find_listeners(event_type)
|
42
|
-
@listener_map.fetch_values(event_type.to_sym, :any) { [] }.flatten
|
43
|
-
end
|
44
|
-
|
45
|
-
def gateways
|
46
|
-
@isolated ? (@gateways ||= []) : (@@gateways ||= []) # rubocop:disable Style/ClassVars
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
data/lib/realm/health_status.rb
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'active_support/core_ext/object/blank'
|
4
|
-
|
5
|
-
module Realm
|
6
|
-
class HealthStatus
|
7
|
-
CODES = %i[green yellow red].freeze
|
8
|
-
attr_reader :code, :issues
|
9
|
-
|
10
|
-
class << self
|
11
|
-
def [](code, *issues)
|
12
|
-
new(code, issues.flatten)
|
13
|
-
end
|
14
|
-
|
15
|
-
def from_issues(issues)
|
16
|
-
new(issues.blank? ? :green : :red, issues)
|
17
|
-
end
|
18
|
-
|
19
|
-
def combine(component_map)
|
20
|
-
code_index = component_map.values.map { |i| CODES.index(i.code) }.max
|
21
|
-
new(CODES[code_index || 0], [], component_map)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def for_component(*names)
|
26
|
-
@component_map.dig(*names)
|
27
|
-
end
|
28
|
-
|
29
|
-
def to_h
|
30
|
-
hash = { status: @code }
|
31
|
-
hash[:issues] = @issues if @issues.present?
|
32
|
-
hash[:components] = @component_map.transform_values(&:to_h) if @component_map.present?
|
33
|
-
hash
|
34
|
-
end
|
35
|
-
|
36
|
-
private
|
37
|
-
|
38
|
-
def initialize(code, issues = [], component_map = {})
|
39
|
-
raise ArgumentError, "Invalid status code #{code}" unless CODES.include?(code)
|
40
|
-
|
41
|
-
@code = code
|
42
|
-
@issues = issues.freeze
|
43
|
-
@component_map = component_map.freeze
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Realm
|
4
|
-
module Mixins
|
5
|
-
module AggregateMember
|
6
|
-
def self.included(base)
|
7
|
-
base.extend(ClassMethods)
|
8
|
-
end
|
9
|
-
|
10
|
-
def aggregate
|
11
|
-
self.class.aggregate
|
12
|
-
end
|
13
|
-
|
14
|
-
module ClassMethods
|
15
|
-
def aggregate
|
16
|
-
@aggregate ||= begin
|
17
|
-
module_chain = name.split('::')
|
18
|
-
domain_index = module_chain.index('Domain')
|
19
|
-
domain_index && module_chain[domain_index + 1].underscore.to_sym
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,49 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'realm/error'
|
4
|
-
|
5
|
-
module Realm
|
6
|
-
module Mixins
|
7
|
-
module ContextInjection
|
8
|
-
def self.included(base)
|
9
|
-
base.extend(ClassMethods)
|
10
|
-
base.prepend(Initializer)
|
11
|
-
end
|
12
|
-
|
13
|
-
module ClassMethods
|
14
|
-
def inject(*names, &block)
|
15
|
-
names.each do |name|
|
16
|
-
define_method(name) do
|
17
|
-
raise Realm::DependencyMissing, name unless context.key?(name)
|
18
|
-
|
19
|
-
return context[name] unless block
|
20
|
-
|
21
|
-
var = "@#{name}"
|
22
|
-
return instance_variable_get(var) if instance_variable_defined?(var)
|
23
|
-
|
24
|
-
instance_variable_set(var, block.(context[name]))
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
module Initializer
|
31
|
-
def initialize(*args, context: nil, **kwargs)
|
32
|
-
@context = context || context_from_root_module || {}
|
33
|
-
super(*args, **kwargs)
|
34
|
-
end
|
35
|
-
|
36
|
-
private
|
37
|
-
|
38
|
-
def context_from_root_module
|
39
|
-
root_module = self.class.module_parents[-2]
|
40
|
-
root_module.realm.context if root_module.respond_to?(:realm)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
protected
|
45
|
-
|
46
|
-
attr_reader :context
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|