evt-messaging 0.7.1.0
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 +7 -0
- data/lib/loader.rb +1 -0
- data/lib/messaging.rb +19 -0
- data/lib/messaging/controls.rb +12 -0
- data/lib/messaging/controls/batch.rb +29 -0
- data/lib/messaging/controls/event_data.rb +5 -0
- data/lib/messaging/controls/handler.rb +47 -0
- data/lib/messaging/controls/message.rb +67 -0
- data/lib/messaging/controls/metadata.rb +100 -0
- data/lib/messaging/controls/stream.rb +5 -0
- data/lib/messaging/controls/stream_name.rb +19 -0
- data/lib/messaging/controls/time.rb +5 -0
- data/lib/messaging/controls/write.rb +15 -0
- data/lib/messaging/handle.rb +174 -0
- data/lib/messaging/log.rb +9 -0
- data/lib/messaging/message.rb +82 -0
- data/lib/messaging/message/copy.rb +38 -0
- data/lib/messaging/message/export.rb +9 -0
- data/lib/messaging/message/follow.rb +37 -0
- data/lib/messaging/message/import.rb +9 -0
- data/lib/messaging/message/metadata.rb +58 -0
- data/lib/messaging/message/transformer.rb +54 -0
- data/lib/messaging/message_registry.rb +40 -0
- data/lib/messaging/stream_name.rb +58 -0
- data/lib/messaging/write.rb +138 -0
- data/lib/messaging/write/substitute.rb +64 -0
- metadata +96 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9395b1e320f5ac8d62251b28f6bb03d24e2c9d76
|
4
|
+
data.tar.gz: 0afc6dd4852ba62cd022e99f4604a9b84eeeeaed
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2561a6d77b386d0ee6728fd970e767cdc2859e8abd456922a2750d8b19f4897ba95c695e48b7e2745ff71f5a7c46f5fa289f5cbc89ea83d57214ed2b970ea0a1
|
7
|
+
data.tar.gz: 3669488d065b94042d98e4945a6ba0865f76da4ac1739c6bbde29a9a15c86ca18a3ed198c386d264c919fa0bd492489c45267c995bf9781979692b5ee25d1e7e
|
data/lib/loader.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
messaging.rb
|
data/lib/messaging.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'event_source'
|
2
|
+
|
3
|
+
require 'messaging/stream_name'
|
4
|
+
|
5
|
+
require 'messaging/message'
|
6
|
+
require 'messaging/message/metadata'
|
7
|
+
require 'messaging/message/copy'
|
8
|
+
require 'messaging/message/follow'
|
9
|
+
|
10
|
+
require 'messaging/message/transformer'
|
11
|
+
require 'messaging/message/import'
|
12
|
+
require 'messaging/message/export'
|
13
|
+
|
14
|
+
require 'messaging/log'
|
15
|
+
require 'messaging/write'
|
16
|
+
require 'messaging/write/substitute'
|
17
|
+
|
18
|
+
require 'messaging/message_registry'
|
19
|
+
require 'messaging/handle'
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'clock/controls'
|
2
|
+
require 'event_source/controls'
|
3
|
+
|
4
|
+
require 'messaging/controls/time'
|
5
|
+
require 'messaging/controls/stream'
|
6
|
+
require 'messaging/controls/stream_name'
|
7
|
+
require 'messaging/controls/event_data'
|
8
|
+
require 'messaging/controls/message'
|
9
|
+
require 'messaging/controls/metadata'
|
10
|
+
require 'messaging/controls/batch'
|
11
|
+
require 'messaging/controls/write'
|
12
|
+
require 'messaging/controls/handler'
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Messaging
|
2
|
+
module Controls
|
3
|
+
module Batch
|
4
|
+
def self.example
|
5
|
+
values = [
|
6
|
+
EventSource::Controls::RandomValue.example,
|
7
|
+
EventSource::Controls::RandomValue.example
|
8
|
+
]
|
9
|
+
|
10
|
+
batch = Messages.example
|
11
|
+
|
12
|
+
2.times do |i|
|
13
|
+
batch[i].some_attribute = values[i]
|
14
|
+
end
|
15
|
+
|
16
|
+
return batch, values
|
17
|
+
end
|
18
|
+
|
19
|
+
module Messages
|
20
|
+
def self.example
|
21
|
+
[
|
22
|
+
Controls::Message.example,
|
23
|
+
Controls::Message.example
|
24
|
+
]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Messaging
|
2
|
+
module Controls
|
3
|
+
module Handler
|
4
|
+
class Example
|
5
|
+
include Messaging::Handle
|
6
|
+
include Controls::Message
|
7
|
+
|
8
|
+
handle SomeMessage do |some_message|
|
9
|
+
some_message.some_attribute = 'some value set by handler'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module HandleMethod
|
14
|
+
class Example
|
15
|
+
include Messaging::Handle
|
16
|
+
|
17
|
+
def handle(event_data)
|
18
|
+
event_data.data = 'some value set by handle method'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module BlockAndHandleMethod
|
24
|
+
class Example
|
25
|
+
include Messaging::Handle
|
26
|
+
include Controls::Message
|
27
|
+
|
28
|
+
handle SomeMessage do |some_message|
|
29
|
+
some_message.some_attribute = 'some attribute value set by handler'
|
30
|
+
end
|
31
|
+
|
32
|
+
def handle(event_data)
|
33
|
+
event_data.data = 'some data value set by handler'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module Anomaly
|
39
|
+
module NoHandle
|
40
|
+
class Example
|
41
|
+
include Messaging::Handle
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Messaging
|
2
|
+
module Controls
|
3
|
+
module Message
|
4
|
+
def self.example(some_attribute: nil, metadata: nil)
|
5
|
+
some_attribute ||= attribute
|
6
|
+
metadata ||= Controls::Metadata.example
|
7
|
+
|
8
|
+
message = SomeMessage.new
|
9
|
+
message.some_attribute = some_attribute
|
10
|
+
message.other_attribute = other_attribute
|
11
|
+
|
12
|
+
message.metadata = metadata
|
13
|
+
|
14
|
+
message
|
15
|
+
end
|
16
|
+
|
17
|
+
module New
|
18
|
+
def self.example
|
19
|
+
Message::SomeMessage.new
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class SomeMessage
|
24
|
+
include Messaging::Message
|
25
|
+
|
26
|
+
attribute :some_attribute
|
27
|
+
attribute :other_attribute
|
28
|
+
end
|
29
|
+
|
30
|
+
class OtherMessage
|
31
|
+
include Messaging::Message
|
32
|
+
|
33
|
+
attribute :an_attribute
|
34
|
+
attribute :other_attribute
|
35
|
+
end
|
36
|
+
|
37
|
+
class SingleAttribute
|
38
|
+
include Messaging::Message
|
39
|
+
|
40
|
+
attribute :some_attribute
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.message_class
|
44
|
+
SomeMessage
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.type
|
48
|
+
'SomeMessage'
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.attribute
|
52
|
+
'some value'
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.other_attribute
|
56
|
+
'other value'
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.data
|
60
|
+
{
|
61
|
+
some_attribute: attribute,
|
62
|
+
other_attribute: other_attribute
|
63
|
+
}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module Messaging
|
2
|
+
module Controls
|
3
|
+
module Metadata
|
4
|
+
def self.example
|
5
|
+
Messaging::Message::Metadata.build(data)
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.source_event_stream_name
|
9
|
+
'someSource'
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.source_event_position
|
13
|
+
1
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.causation_event_stream_name
|
17
|
+
"someCausation"
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.causation_event_position
|
21
|
+
11
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.correlation_stream_name
|
25
|
+
"someCorrelation"
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.reply_stream_name
|
29
|
+
"someReply"
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.schema_version
|
33
|
+
11
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.source_event_identifier
|
37
|
+
"#{source_event_stream_name}/#{source_event_position}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.causation_event_identifier
|
41
|
+
"#{causation_event_stream_name}/#{causation_event_position}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.global_position
|
45
|
+
111
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.time
|
49
|
+
Time::Raw.example
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.data
|
53
|
+
{
|
54
|
+
source_event_stream_name: source_event_stream_name,
|
55
|
+
source_event_position: source_event_position,
|
56
|
+
|
57
|
+
causation_event_stream_name: causation_event_stream_name,
|
58
|
+
causation_event_position: causation_event_position,
|
59
|
+
|
60
|
+
correlation_stream_name: correlation_stream_name,
|
61
|
+
|
62
|
+
reply_stream_name: reply_stream_name,
|
63
|
+
|
64
|
+
global_position: global_position,
|
65
|
+
time: time,
|
66
|
+
|
67
|
+
schema_version: schema_version
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
module New
|
72
|
+
def self.example
|
73
|
+
::Messaging::Message::Metadata.new
|
74
|
+
end
|
75
|
+
end
|
76
|
+
Empty = New
|
77
|
+
|
78
|
+
module Written
|
79
|
+
def self.example
|
80
|
+
Messaging::Message::Metadata.build(data)
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.data
|
84
|
+
data = Metadata.data
|
85
|
+
|
86
|
+
[
|
87
|
+
:source_event_stream_name,
|
88
|
+
:source_event_position,
|
89
|
+
:global_position,
|
90
|
+
:time
|
91
|
+
].each do |not_written_attribute|
|
92
|
+
data.delete(not_written_attribute)
|
93
|
+
end
|
94
|
+
|
95
|
+
data
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Messaging
|
2
|
+
module Controls
|
3
|
+
StreamName = EventSource::Controls::StreamName
|
4
|
+
|
5
|
+
module StreamName
|
6
|
+
module Named
|
7
|
+
def self.example
|
8
|
+
Example.new
|
9
|
+
end
|
10
|
+
|
11
|
+
class Example
|
12
|
+
include Messaging::StreamName
|
13
|
+
|
14
|
+
category :some_category
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
module Messaging
|
2
|
+
module Handle
|
3
|
+
class Error < RuntimeError; end
|
4
|
+
|
5
|
+
def self.included(cls)
|
6
|
+
cls.class_exec do
|
7
|
+
include Log::Dependency
|
8
|
+
|
9
|
+
cls.extend Build
|
10
|
+
cls.extend Call
|
11
|
+
cls.extend Info
|
12
|
+
cls.extend HandleMacro
|
13
|
+
cls.extend MessageRegistry
|
14
|
+
|
15
|
+
virtual :configure
|
16
|
+
|
17
|
+
attr_writer :strict
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def strict
|
22
|
+
@strict ||= false
|
23
|
+
end
|
24
|
+
|
25
|
+
module Build
|
26
|
+
def build(strict: nil)
|
27
|
+
instance = new
|
28
|
+
instance.strict = strict
|
29
|
+
instance.configure
|
30
|
+
instance
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module Call
|
35
|
+
def call(message_or_event_data, strict: nil)
|
36
|
+
instance = build(strict: strict)
|
37
|
+
instance.(message_or_event_data)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module Info
|
42
|
+
extend self
|
43
|
+
|
44
|
+
def handler(message_or_event_data)
|
45
|
+
name = handler_name(message_or_event_data)
|
46
|
+
|
47
|
+
if method_defined?(name)
|
48
|
+
return name
|
49
|
+
else
|
50
|
+
return nil
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def handles?(message_or_event_data)
|
55
|
+
method_defined? handler_name(message_or_event_data)
|
56
|
+
end
|
57
|
+
|
58
|
+
def handler_name(message_or_event_data)
|
59
|
+
name = nil
|
60
|
+
|
61
|
+
if message_or_event_data.is_a? EventSource::EventData::Read
|
62
|
+
name = Messaging::Message::Info.canonize_name(message_or_event_data.type)
|
63
|
+
else
|
64
|
+
name = message_or_event_data.message_name
|
65
|
+
end
|
66
|
+
|
67
|
+
"handle_#{name}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
module HandleMacro
|
72
|
+
class Error < RuntimeError; end
|
73
|
+
|
74
|
+
def logger
|
75
|
+
@logger ||= Log.get(self)
|
76
|
+
end
|
77
|
+
|
78
|
+
def handle_macro(message_class, &blk)
|
79
|
+
define_handler_method(message_class, &blk)
|
80
|
+
message_registry.register(message_class)
|
81
|
+
end
|
82
|
+
alias :handle :handle_macro
|
83
|
+
|
84
|
+
def define_handler_method(message_class, &blk)
|
85
|
+
handler_method_name = handler_name(message_class)
|
86
|
+
|
87
|
+
if blk.nil?
|
88
|
+
error_msg = "Handler for #{message_class.name} is not correctly defined. It must have a block."
|
89
|
+
logger.error { error_msg }
|
90
|
+
raise Error, error_msg
|
91
|
+
end
|
92
|
+
|
93
|
+
send(:define_method, handler_method_name, &blk)
|
94
|
+
|
95
|
+
handler_method = instance_method(handler_method_name)
|
96
|
+
|
97
|
+
unless handler_method.arity == 1
|
98
|
+
error_msg = "Handler for #{message_class.name} is not correctly defined. It can only have a single parameter."
|
99
|
+
logger.error { error_msg }
|
100
|
+
raise Error, error_msg
|
101
|
+
end
|
102
|
+
|
103
|
+
handler_method_name
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
module MessageRegistry
|
108
|
+
def message_registry
|
109
|
+
@message_registry ||= Messaging::MessageRegistry.new
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def call(message_or_event_data)
|
114
|
+
if message_or_event_data.is_a? Message
|
115
|
+
handle_message(message_or_event_data)
|
116
|
+
else
|
117
|
+
handle_event_data(message_or_event_data)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def handle_message(message)
|
122
|
+
logger.trace(tags: [:handle, :message]) { "Handling message (Message class: #{message.class.name})" }
|
123
|
+
logger.trace(tags: [:data, :message, :handle]) { message.pretty_inspect }
|
124
|
+
|
125
|
+
handler = self.class.handler(message)
|
126
|
+
|
127
|
+
unless handler.nil?
|
128
|
+
public_send(handler, message)
|
129
|
+
else
|
130
|
+
if strict
|
131
|
+
error_msg = "#{self.class.name} does not implement a handler for #{message.message_type}. Cannot handle the message."
|
132
|
+
logger.error { error_msg }
|
133
|
+
raise Error, error_msg
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
logger.info(tags: [:handle, :message]) { "Handled message (Message class: #{message.class.name})" }
|
138
|
+
logger.trace(tags: [:data, :message, :handle]) { message.pretty_inspect }
|
139
|
+
|
140
|
+
message
|
141
|
+
end
|
142
|
+
|
143
|
+
def handle_event_data(event_data)
|
144
|
+
logger.trace(tags: [:handle, :event_data]) { "Handling event data (Type: #{event_data.type})" }
|
145
|
+
logger.trace(tags: [:data, :event_data, :handle]) { event_data.pretty_inspect }
|
146
|
+
|
147
|
+
res = nil
|
148
|
+
|
149
|
+
handler = self.class.handler(event_data)
|
150
|
+
|
151
|
+
unless handler.nil?
|
152
|
+
message_name = Messaging::Message::Info.canonize_name(event_data.type)
|
153
|
+
message_class = self.class.message_registry.get(message_name)
|
154
|
+
res = Message::Import.(event_data, message_class)
|
155
|
+
public_send(handler, res)
|
156
|
+
else
|
157
|
+
if respond_to?(:handle)
|
158
|
+
res = handle(event_data)
|
159
|
+
else
|
160
|
+
if strict
|
161
|
+
error_msg = "#{self.class.name} does not implement `handle'. Cannot handle event data."
|
162
|
+
logger.error { error_msg }
|
163
|
+
raise Error, error_msg
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
logger.info(tags: [:handle, :event_data]) { "Handled event data (Type: #{event_data.type})" }
|
169
|
+
logger.info(tags: [:data, :event_data, :handle]) { event_data.pretty_inspect }
|
170
|
+
|
171
|
+
res
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Messaging
|
2
|
+
module Message
|
3
|
+
def self.included(cls)
|
4
|
+
cls.class_exec do
|
5
|
+
include Schema::DataStructure
|
6
|
+
end
|
7
|
+
|
8
|
+
cls.extend Info
|
9
|
+
cls.extend Build
|
10
|
+
cls.extend Copy
|
11
|
+
cls.extend Follow
|
12
|
+
cls.extend Transformer
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_writer :metadata
|
16
|
+
def metadata
|
17
|
+
@metadata ||= Metadata.new
|
18
|
+
end
|
19
|
+
|
20
|
+
def message_type
|
21
|
+
self.class.message_type
|
22
|
+
end
|
23
|
+
|
24
|
+
def message_name
|
25
|
+
self.class.message_name
|
26
|
+
end
|
27
|
+
|
28
|
+
def follows?(other_message)
|
29
|
+
metadata.follows?(other_message.metadata)
|
30
|
+
end
|
31
|
+
|
32
|
+
module Info
|
33
|
+
extend self
|
34
|
+
|
35
|
+
def message_type(msg=self)
|
36
|
+
class_name(msg).split('::').last
|
37
|
+
end
|
38
|
+
|
39
|
+
def message_name(msg=self)
|
40
|
+
Info.canonize_name(message_type(msg))
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.canonize_name(name)
|
44
|
+
name.gsub(/([^\^])([A-Z])/,'\1_\2').downcase
|
45
|
+
end
|
46
|
+
|
47
|
+
def class_name(message)
|
48
|
+
class_name = nil
|
49
|
+
class_name = message if message.instance_of? String
|
50
|
+
class_name ||= message.name if message.instance_of? Class
|
51
|
+
class_name ||= message.class.name
|
52
|
+
class_name
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
module Build
|
57
|
+
def build(data=nil, metadata=nil)
|
58
|
+
data ||= {}
|
59
|
+
metadata ||= {}
|
60
|
+
|
61
|
+
metadata = build_metadata(metadata)
|
62
|
+
|
63
|
+
new.tap do |instance|
|
64
|
+
set_attributes(instance, data)
|
65
|
+
instance.metadata = metadata
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def set_attributes(instance, data)
|
70
|
+
SetAttributes.(instance, data)
|
71
|
+
end
|
72
|
+
|
73
|
+
def build_metadata(metadata)
|
74
|
+
if metadata.nil?
|
75
|
+
Metadata.new
|
76
|
+
else
|
77
|
+
Metadata.build(metadata.to_h)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Messaging
|
2
|
+
module Message
|
3
|
+
module Copy
|
4
|
+
class Error < RuntimeError; end
|
5
|
+
|
6
|
+
extend self
|
7
|
+
|
8
|
+
def self.call(source, receiver=nil, copy: nil, include: nil, exclude: nil, metadata: nil, strict: nil)
|
9
|
+
copy(source, receiver, copy: copy, include: include, exclude: exclude, metadata: metadata, strict: strict)
|
10
|
+
end
|
11
|
+
|
12
|
+
def copy(source, receiver=nil, copy: nil, include: nil, exclude: nil, metadata: nil, strict: nil)
|
13
|
+
metadata ||= false
|
14
|
+
strict = true if strict.nil?
|
15
|
+
|
16
|
+
if receiver.nil?
|
17
|
+
receiver = self
|
18
|
+
end
|
19
|
+
|
20
|
+
if receiver.class == Class
|
21
|
+
receiver = receiver.build
|
22
|
+
end
|
23
|
+
|
24
|
+
begin
|
25
|
+
SetAttributes.(receiver, source, copy: copy, include: include, exclude: exclude, strict: strict)
|
26
|
+
rescue SetAttributes::Attribute::Error => e
|
27
|
+
raise Error, e.message, e.backtrace
|
28
|
+
end
|
29
|
+
|
30
|
+
if metadata
|
31
|
+
SetAttributes.(receiver.metadata, source.metadata)
|
32
|
+
end
|
33
|
+
|
34
|
+
receiver
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Messaging
|
2
|
+
module Message
|
3
|
+
module Follow
|
4
|
+
class Error < RuntimeError; end
|
5
|
+
|
6
|
+
extend self
|
7
|
+
|
8
|
+
def self.call(source, receiver=nil, copy: nil, include: nil, exclude: nil, strict: nil)
|
9
|
+
follow(source, receiver, copy: copy, include: include, exclude: exclude, strict: strict)
|
10
|
+
end
|
11
|
+
|
12
|
+
def follow(source, receiver=nil, copy: nil, include: nil, exclude: nil, strict: nil)
|
13
|
+
if receiver.nil?
|
14
|
+
receiver = self
|
15
|
+
end
|
16
|
+
|
17
|
+
if receiver.class == Class
|
18
|
+
receiver = receiver.build
|
19
|
+
end
|
20
|
+
|
21
|
+
unchanged_source_event_stream_name = receiver.metadata.source_event_stream_name
|
22
|
+
unchanged_source_event_position = receiver.metadata.source_event_position
|
23
|
+
unchanged_schema_version = receiver.metadata.schema_version
|
24
|
+
|
25
|
+
Copy.(source, receiver, copy: copy, include: include, exclude: exclude, strict: strict, metadata: true)
|
26
|
+
|
27
|
+
receiver.metadata.source_event_stream_name = unchanged_source_event_stream_name
|
28
|
+
receiver.metadata.source_event_position = unchanged_source_event_position
|
29
|
+
receiver.metadata.schema_version = unchanged_schema_version
|
30
|
+
|
31
|
+
receiver.metadata.follow(source.metadata)
|
32
|
+
|
33
|
+
receiver
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Messaging
|
2
|
+
module Message
|
3
|
+
class Metadata
|
4
|
+
class Error < RuntimeError; end
|
5
|
+
|
6
|
+
include Schema::DataStructure
|
7
|
+
|
8
|
+
attribute :source_event_stream_name
|
9
|
+
alias :stream_name :source_event_stream_name
|
10
|
+
attribute :source_event_position
|
11
|
+
alias :sequence :source_event_position
|
12
|
+
alias :position :source_event_position
|
13
|
+
alias :position= :source_event_position=
|
14
|
+
|
15
|
+
attribute :causation_event_stream_name
|
16
|
+
attribute :causation_event_position
|
17
|
+
|
18
|
+
attribute :correlation_stream_name
|
19
|
+
|
20
|
+
attribute :reply_stream_name
|
21
|
+
|
22
|
+
attribute :global_position
|
23
|
+
attribute :time
|
24
|
+
|
25
|
+
attribute :schema_version
|
26
|
+
|
27
|
+
def source_event_identifier
|
28
|
+
return nil if source_event_stream_name.nil? || source_event_position.nil?
|
29
|
+
"#{source_event_stream_name}/#{source_event_position}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def causation_event_identifier
|
33
|
+
return nil if causation_event_stream_name.nil? || causation_event_position.nil?
|
34
|
+
"#{causation_event_stream_name}/#{causation_event_position}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def follow(other_metadata)
|
38
|
+
self.causation_event_stream_name = other_metadata.source_event_stream_name
|
39
|
+
self.causation_event_position = other_metadata.source_event_position
|
40
|
+
|
41
|
+
unless follows?(other_metadata)
|
42
|
+
raise Error, "Metadata doesn't have precedence (Metadata: #{self.inspect}, Other Metadata #{other_metadata.inspect})"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def follows?(other_metadata)
|
47
|
+
causation_event_identifier == other_metadata.source_event_identifier &&
|
48
|
+
|
49
|
+
correlation_stream_name == other_metadata.correlation_stream_name &&
|
50
|
+
reply_stream_name == other_metadata.reply_stream_name
|
51
|
+
end
|
52
|
+
|
53
|
+
def clear_reply_stream_name
|
54
|
+
self.reply_stream_name = nil
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Messaging
|
2
|
+
module Message
|
3
|
+
module Transformer
|
4
|
+
def self.event_data
|
5
|
+
EventData
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.raw_data(message)
|
9
|
+
message
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.instance(event_data_data, cls)
|
13
|
+
cls.build(event_data_data[:data], event_data_data[:metadata])
|
14
|
+
end
|
15
|
+
|
16
|
+
module EventData
|
17
|
+
def self.write(message)
|
18
|
+
event_data = EventSource::EventData::Write.build
|
19
|
+
|
20
|
+
event_data.type = message.message_type
|
21
|
+
|
22
|
+
event_data.data = message.to_h
|
23
|
+
|
24
|
+
metadata = message.metadata.to_h
|
25
|
+
metadata.delete_if { |k, v| v.nil? || k == :source_event_stream_name || k == :source_event_position}
|
26
|
+
|
27
|
+
event_data.metadata = metadata
|
28
|
+
|
29
|
+
event_data
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.read(event_data)
|
33
|
+
data = event_data.to_h
|
34
|
+
|
35
|
+
unless data[:metadata].nil?
|
36
|
+
data[:metadata] = data[:metadata].clone
|
37
|
+
else
|
38
|
+
data[:metadata] = {}
|
39
|
+
end
|
40
|
+
|
41
|
+
metadata = data[:metadata]
|
42
|
+
|
43
|
+
metadata[:source_event_stream_name] = data[:stream_name]
|
44
|
+
metadata[:source_event_position] = data[:position]
|
45
|
+
|
46
|
+
metadata[:global_position] = data[:global_position]
|
47
|
+
metadata[:time] = data[:time]
|
48
|
+
|
49
|
+
data
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Messaging
|
2
|
+
class MessageRegistry
|
3
|
+
class Error < RuntimeError; end
|
4
|
+
|
5
|
+
include Log::Dependency
|
6
|
+
|
7
|
+
def entries
|
8
|
+
@entries ||= []
|
9
|
+
end
|
10
|
+
|
11
|
+
def get(message_name)
|
12
|
+
entries.find do |message_class|
|
13
|
+
message_class.message_name == message_name
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def register(message_class)
|
18
|
+
logger.trace { "Registering #{message_class}"}
|
19
|
+
if registered?(message_class)
|
20
|
+
error_msg = "#{message_class} is already registered"
|
21
|
+
logger.error { error_msg }
|
22
|
+
raise Error, error_msg
|
23
|
+
end
|
24
|
+
|
25
|
+
entries << message_class
|
26
|
+
|
27
|
+
logger.debug { "Registered #{message_class}"}
|
28
|
+
|
29
|
+
entries
|
30
|
+
end
|
31
|
+
|
32
|
+
def registered?(message_class)
|
33
|
+
entries.include?(message_class)
|
34
|
+
end
|
35
|
+
|
36
|
+
def length
|
37
|
+
entries.length
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Messaging
|
2
|
+
module StreamName
|
3
|
+
extend self
|
4
|
+
|
5
|
+
include EventSource::StreamName
|
6
|
+
|
7
|
+
def self.included(cls)
|
8
|
+
cls.extend Macro
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.activate
|
12
|
+
target_class ||= Object
|
13
|
+
macro_module = Macro
|
14
|
+
return if target_class.is_a? macro_module
|
15
|
+
target_class.extend(macro_module)
|
16
|
+
end
|
17
|
+
|
18
|
+
module Macro
|
19
|
+
def category_macro(category)
|
20
|
+
category = Casing::Camel.(category, symbol_to_string: true)
|
21
|
+
self.send :define_method, :category do
|
22
|
+
@category || category
|
23
|
+
end
|
24
|
+
end
|
25
|
+
alias :category :category_macro
|
26
|
+
end
|
27
|
+
|
28
|
+
def stream_name(id, category=nil)
|
29
|
+
category ||= self.category
|
30
|
+
EventSource::StreamName.stream_name category, id
|
31
|
+
end
|
32
|
+
|
33
|
+
def command_stream_name(id, category=nil)
|
34
|
+
category ||= self.category
|
35
|
+
EventSource::StreamName.stream_name "#{category}:command", id
|
36
|
+
end
|
37
|
+
|
38
|
+
def category_stream_name(category=nil)
|
39
|
+
category ||= self.category
|
40
|
+
category
|
41
|
+
end
|
42
|
+
|
43
|
+
def command_category_stream_name(category=nil)
|
44
|
+
category ||= self.category
|
45
|
+
category_stream_name = category_stream_name(category)
|
46
|
+
|
47
|
+
"#{category_stream_name}:command"
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.get_category(stream_name)
|
51
|
+
EventSource::StreamName.get_category(stream_name)
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.get_id(stream_name)
|
55
|
+
EventSource::StreamName.get_id stream_name
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
module Messaging
|
2
|
+
module Write
|
3
|
+
class Error < RuntimeError; end
|
4
|
+
|
5
|
+
def self.included(cls)
|
6
|
+
cls.class_exec do
|
7
|
+
include Log::Dependency
|
8
|
+
|
9
|
+
dependency :event_writer
|
10
|
+
dependency :telemetry, ::Telemetry
|
11
|
+
|
12
|
+
cls.extend Build
|
13
|
+
cls.extend Call
|
14
|
+
cls.extend Configure
|
15
|
+
|
16
|
+
abstract :configure
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module Build
|
21
|
+
def build(session: nil)
|
22
|
+
instance = new
|
23
|
+
instance.configure(session: session)
|
24
|
+
::Telemetry.configure instance
|
25
|
+
instance
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module Configure
|
30
|
+
def configure(receiver, session: nil, attr_name: nil)
|
31
|
+
attr_name ||= :write
|
32
|
+
instance = build(session: session)
|
33
|
+
receiver.public_send "#{attr_name}=", instance
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
module Call
|
38
|
+
def call(message, stream_name, expected_version: nil, reply_stream_name: nil, session: nil)
|
39
|
+
instance = build(session: session)
|
40
|
+
instance.(message, stream_name, expected_version: expected_version, reply_stream_name: reply_stream_name)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def call(message_or_batch, stream_name, expected_version: nil, reply_stream_name: nil)
|
45
|
+
unless message_or_batch.is_a? Array
|
46
|
+
logger.trace { "Writing message (Stream Name: #{stream_name}, Type: #{message_or_batch.class.message_type}, Expected Version: #{expected_version.inspect}, Reply Stream Name: #{reply_stream_name.inspect})" }
|
47
|
+
else
|
48
|
+
logger.trace { "Writing batch (Stream Name: #{stream_name}, Expected Version: #{expected_version.inspect}, Reply Stream Name: #{reply_stream_name.inspect})" }
|
49
|
+
end
|
50
|
+
logger.trace(tags: [:data, :message]) { message_or_batch.pretty_inspect }
|
51
|
+
|
52
|
+
message_batch = Array(message_or_batch)
|
53
|
+
|
54
|
+
event_data_batch = event_data_batch(message_batch, reply_stream_name)
|
55
|
+
last_position = event_writer.(event_data_batch, stream_name, expected_version: expected_version)
|
56
|
+
|
57
|
+
unless message_or_batch.is_a? Array
|
58
|
+
logger.info { "Wrote message (Position: #{last_position}, Stream Name: #{stream_name}, Type: #{message_or_batch.class.message_type}, Expected Version: #{expected_version.inspect}, Reply Stream Name: #{reply_stream_name.inspect})" }
|
59
|
+
else
|
60
|
+
logger.info { "Wrote batch (Position: #{last_position}, Stream Name: #{stream_name}, Expected Version: #{expected_version.inspect}, Reply Stream Name: #{reply_stream_name.inspect})" }
|
61
|
+
end
|
62
|
+
logger.info(tags: [:data, :message]) { event_data_batch.pretty_inspect }
|
63
|
+
|
64
|
+
message_batch.each do |message|
|
65
|
+
telemetry.record :written, Telemetry::Data.new(message, stream_name, expected_version, reply_stream_name)
|
66
|
+
end
|
67
|
+
|
68
|
+
last_position
|
69
|
+
end
|
70
|
+
alias :write :call
|
71
|
+
|
72
|
+
def event_data_batch(message_batch, reply_stream_name=nil)
|
73
|
+
event_data_batch = []
|
74
|
+
message_batch.each do |message|
|
75
|
+
unless reply_stream_name.nil?
|
76
|
+
message.metadata.reply_stream_name = reply_stream_name
|
77
|
+
end
|
78
|
+
|
79
|
+
event_data_batch << Message::Export.(message)
|
80
|
+
end
|
81
|
+
|
82
|
+
event_data_batch
|
83
|
+
end
|
84
|
+
|
85
|
+
def reply(message)
|
86
|
+
if message.is_a? Array
|
87
|
+
error_msg = "Cannot reply with a batch"
|
88
|
+
logger.error { error_msg }
|
89
|
+
raise Error, error_msg
|
90
|
+
end
|
91
|
+
|
92
|
+
metadata = message.metadata
|
93
|
+
reply_stream_name = metadata.reply_stream_name
|
94
|
+
|
95
|
+
logger.trace { "Replying (Message Type: #{message.message_type}, Stream Name: #{reply_stream_name.inspect})" }
|
96
|
+
|
97
|
+
if reply_stream_name.nil?
|
98
|
+
error_msg = "Message has no reply stream name. Cannot reply. (Message Type: #{message.message_type})"
|
99
|
+
logger.error { error_msg }
|
100
|
+
logger.error(tags: [:data, :message]) { message.pretty_inspect }
|
101
|
+
raise Error, error_msg
|
102
|
+
end
|
103
|
+
|
104
|
+
metadata.clear_reply_stream_name
|
105
|
+
|
106
|
+
write(message, reply_stream_name).tap do
|
107
|
+
logger.info { "Replied (Message Type: #{message.message_type}, Stream Name: #{reply_stream_name})" }
|
108
|
+
telemetry.record :replied, Telemetry::Data.new(message, reply_stream_name)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def initial(message, stream_name)
|
113
|
+
write(message, stream_name, expected_version: :no_stream)
|
114
|
+
end
|
115
|
+
alias :write_initial :initial
|
116
|
+
|
117
|
+
def self.register_telemetry_sink(writer)
|
118
|
+
sink = Telemetry.sink
|
119
|
+
writer.telemetry.register sink
|
120
|
+
sink
|
121
|
+
end
|
122
|
+
|
123
|
+
module Telemetry
|
124
|
+
class Sink
|
125
|
+
include ::Telemetry::Sink
|
126
|
+
|
127
|
+
record :written
|
128
|
+
record :replied
|
129
|
+
end
|
130
|
+
|
131
|
+
Data = Struct.new :message, :stream_name, :expected_version, :reply_stream_name
|
132
|
+
|
133
|
+
def self.sink
|
134
|
+
Sink.new
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Messaging
|
2
|
+
module Write
|
3
|
+
module Substitute
|
4
|
+
def self.build
|
5
|
+
Substitute::Write.build.tap do |substitute_writer|
|
6
|
+
sink = Messaging::Write.register_telemetry_sink(substitute_writer)
|
7
|
+
substitute_writer.sink = sink
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Write
|
12
|
+
include Messaging::Write
|
13
|
+
|
14
|
+
attr_accessor :sink
|
15
|
+
|
16
|
+
def self.build(session: nil)
|
17
|
+
new.tap do |instance|
|
18
|
+
::Telemetry.configure instance
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def writes(&blk)
|
23
|
+
if blk.nil?
|
24
|
+
return sink.written_records
|
25
|
+
end
|
26
|
+
|
27
|
+
sink.written_records.select do |record|
|
28
|
+
blk.call(record.data.message, record.data.stream_name, record.data.expected_version, record.data.reply_stream_name)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def written?(&blk)
|
33
|
+
if blk.nil?
|
34
|
+
return sink.recorded_written?
|
35
|
+
end
|
36
|
+
|
37
|
+
sink.recorded_written? do |record|
|
38
|
+
blk.call(record.data.message, record.data.stream_name, record.data.expected_version, record.data.reply_stream_name)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def replies(&blk)
|
43
|
+
if blk.nil?
|
44
|
+
return sink.replied_records
|
45
|
+
end
|
46
|
+
|
47
|
+
sink.replied_records.select do |record|
|
48
|
+
blk.call(record.data.message, record.data.stream_name)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def replied?(&blk)
|
53
|
+
if blk.nil?
|
54
|
+
return sink.recorded_replied?
|
55
|
+
end
|
56
|
+
|
57
|
+
sink.recorded_replied? do |record|
|
58
|
+
blk.call(record.data.message, record.data.stream_name)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
metadata
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: evt-messaging
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.7.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- The Eventide Project
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-12-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: evt-event_source
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: ntl-test_bench
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: " "
|
42
|
+
email: opensource@eventide-project.org
|
43
|
+
executables: []
|
44
|
+
extensions: []
|
45
|
+
extra_rdoc_files: []
|
46
|
+
files:
|
47
|
+
- lib/loader.rb
|
48
|
+
- lib/messaging.rb
|
49
|
+
- lib/messaging/controls.rb
|
50
|
+
- lib/messaging/controls/batch.rb
|
51
|
+
- lib/messaging/controls/event_data.rb
|
52
|
+
- lib/messaging/controls/handler.rb
|
53
|
+
- lib/messaging/controls/message.rb
|
54
|
+
- lib/messaging/controls/metadata.rb
|
55
|
+
- lib/messaging/controls/stream.rb
|
56
|
+
- lib/messaging/controls/stream_name.rb
|
57
|
+
- lib/messaging/controls/time.rb
|
58
|
+
- lib/messaging/controls/write.rb
|
59
|
+
- lib/messaging/handle.rb
|
60
|
+
- lib/messaging/log.rb
|
61
|
+
- lib/messaging/message.rb
|
62
|
+
- lib/messaging/message/copy.rb
|
63
|
+
- lib/messaging/message/export.rb
|
64
|
+
- lib/messaging/message/follow.rb
|
65
|
+
- lib/messaging/message/import.rb
|
66
|
+
- lib/messaging/message/metadata.rb
|
67
|
+
- lib/messaging/message/transformer.rb
|
68
|
+
- lib/messaging/message_registry.rb
|
69
|
+
- lib/messaging/stream_name.rb
|
70
|
+
- lib/messaging/write.rb
|
71
|
+
- lib/messaging/write/substitute.rb
|
72
|
+
homepage: https://github.com/eventide-project/messaging
|
73
|
+
licenses:
|
74
|
+
- MIT
|
75
|
+
metadata: {}
|
76
|
+
post_install_message:
|
77
|
+
rdoc_options: []
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: 2.3.3
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
requirements: []
|
91
|
+
rubyforge_project:
|
92
|
+
rubygems_version: 2.5.2
|
93
|
+
signing_key:
|
94
|
+
specification_version: 4
|
95
|
+
summary: Messaging primitives for Eventide
|
96
|
+
test_files: []
|