event_store_client 1.4.8 → 2.0.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 +4 -4
- data/README.md +30 -145
- data/docs/appending_events.md +155 -0
- data/docs/catch_up_subscriptions.md +253 -0
- data/docs/configuration.md +83 -0
- data/docs/deleting_streams.md +25 -0
- data/docs/encrypting_events.md +84 -0
- data/docs/linking_events.md +149 -0
- data/docs/reading_events.md +200 -0
- data/lib/event_store_client/adapters/grpc/client.rb +244 -105
- data/lib/event_store_client/adapters/grpc/cluster/gossip_discover.rb +131 -0
- data/lib/event_store_client/adapters/grpc/cluster/insecure_connection.rb +21 -0
- data/lib/event_store_client/adapters/grpc/cluster/member.rb +18 -0
- data/lib/event_store_client/adapters/grpc/cluster/queryless_discover.rb +25 -0
- data/lib/event_store_client/adapters/grpc/cluster/secure_connection.rb +71 -0
- data/lib/event_store_client/adapters/grpc/command_registrar.rb +7 -7
- data/lib/event_store_client/adapters/grpc/commands/command.rb +63 -25
- data/lib/event_store_client/adapters/grpc/commands/gossip/cluster_info.rb +24 -0
- data/lib/event_store_client/adapters/grpc/commands/streams/append.rb +43 -68
- data/lib/event_store_client/adapters/grpc/commands/streams/append_multiple.rb +44 -0
- data/lib/event_store_client/adapters/grpc/commands/streams/delete.rb +21 -17
- data/lib/event_store_client/adapters/grpc/commands/streams/hard_delete.rb +39 -0
- data/lib/event_store_client/adapters/grpc/commands/streams/link_to.rb +7 -52
- data/lib/event_store_client/adapters/grpc/commands/streams/link_to_multiple.rb +44 -0
- data/lib/event_store_client/adapters/grpc/commands/streams/read.rb +20 -85
- data/lib/event_store_client/adapters/grpc/commands/streams/read_paginated.rb +174 -0
- data/lib/event_store_client/adapters/grpc/commands/streams/subscribe.rb +31 -106
- data/lib/event_store_client/adapters/grpc/connection.rb +56 -36
- data/lib/event_store_client/adapters/grpc/discover.rb +75 -0
- data/lib/event_store_client/adapters/grpc/generated/cluster_pb.rb +106 -18
- data/lib/event_store_client/adapters/grpc/generated/cluster_services_pb.rb +12 -12
- data/lib/event_store_client/adapters/grpc/generated/code_pb.rb +34 -0
- data/lib/event_store_client/adapters/grpc/generated/gossip_pb.rb +3 -2
- data/lib/event_store_client/adapters/grpc/generated/gossip_services_pb.rb +3 -3
- data/lib/event_store_client/adapters/grpc/generated/monitoring_pb.rb +25 -0
- data/lib/event_store_client/adapters/grpc/generated/monitoring_services_pb.rb +26 -0
- data/lib/event_store_client/adapters/grpc/generated/operations_pb.rb +2 -1
- data/lib/event_store_client/adapters/grpc/generated/operations_services_pb.rb +8 -7
- data/lib/event_store_client/adapters/grpc/generated/persistent_pb.rb +199 -38
- data/lib/event_store_client/adapters/grpc/generated/persistent_services_pb.rb +7 -3
- data/lib/event_store_client/adapters/grpc/generated/projections_pb.rb +9 -26
- data/lib/event_store_client/adapters/grpc/generated/projections_services_pb.rb +4 -3
- data/lib/event_store_client/adapters/grpc/generated/serverfeatures_pb.rb +29 -0
- data/lib/event_store_client/adapters/grpc/generated/serverfeatures_services_pb.rb +26 -0
- data/lib/event_store_client/adapters/grpc/generated/shared_pb.rb +54 -12
- data/lib/event_store_client/adapters/grpc/generated/status_pb.rb +23 -0
- data/lib/event_store_client/adapters/grpc/generated/streams_pb.rb +104 -64
- data/lib/event_store_client/adapters/grpc/generated/streams_services_pb.rb +3 -2
- data/lib/event_store_client/adapters/grpc/generated/users_services_pb.rb +2 -2
- data/lib/event_store_client/adapters/grpc/options/streams/read_options.rb +78 -0
- data/lib/event_store_client/adapters/grpc/options/streams/write_options.rb +39 -0
- data/lib/event_store_client/adapters/grpc/shared/event_deserializer.rb +52 -0
- data/lib/event_store_client/adapters/grpc/shared/options/filter_options.rb +76 -0
- data/lib/event_store_client/adapters/grpc/shared/options/stream_options.rb +91 -0
- data/lib/event_store_client/adapters/grpc/shared/streams/process_response.rb +28 -0
- data/lib/event_store_client/adapters/grpc/shared/streams/process_responses.rb +33 -0
- data/lib/event_store_client/adapters/grpc.rb +28 -12
- data/lib/event_store_client/configuration.rb +39 -54
- data/lib/event_store_client/connection/url.rb +57 -0
- data/lib/event_store_client/connection/url_parser.rb +144 -0
- data/lib/event_store_client/data_decryptor.rb +2 -9
- data/lib/event_store_client/deserialized_event.rb +35 -10
- data/lib/event_store_client/encryption_metadata.rb +0 -1
- data/lib/event_store_client/event.rb +4 -2
- data/lib/event_store_client/extensions/options_extension.rb +87 -0
- data/lib/event_store_client/mapper/default.rb +12 -9
- data/lib/event_store_client/mapper/encrypted.rb +18 -17
- data/lib/event_store_client/types.rb +1 -1
- data/lib/event_store_client/utils.rb +30 -0
- data/lib/event_store_client/version.rb +1 -1
- data/lib/event_store_client.rb +8 -7
- metadata +72 -81
- data/lib/event_store_client/adapters/grpc/Protos/cluster.proto +0 -149
- data/lib/event_store_client/adapters/grpc/Protos/gossip.proto +0 -44
- data/lib/event_store_client/adapters/grpc/Protos/operations.proto +0 -45
- data/lib/event_store_client/adapters/grpc/Protos/persistent.proto +0 -180
- data/lib/event_store_client/adapters/grpc/Protos/projections.proto +0 -174
- data/lib/event_store_client/adapters/grpc/Protos/shared.proto +0 -22
- data/lib/event_store_client/adapters/grpc/Protos/streams.proto +0 -242
- data/lib/event_store_client/adapters/grpc/Protos/users.proto +0 -119
- data/lib/event_store_client/adapters/grpc/README.md +0 -16
- data/lib/event_store_client/adapters/grpc/commands/persistent_subscriptions/create.rb +0 -46
- data/lib/event_store_client/adapters/grpc/commands/persistent_subscriptions/delete.rb +0 -34
- data/lib/event_store_client/adapters/grpc/commands/persistent_subscriptions/read.rb +0 -77
- data/lib/event_store_client/adapters/grpc/commands/persistent_subscriptions/settings_schema.rb +0 -38
- data/lib/event_store_client/adapters/grpc/commands/persistent_subscriptions/update.rb +0 -48
- data/lib/event_store_client/adapters/grpc/commands/projections/create.rb +0 -48
- data/lib/event_store_client/adapters/grpc/commands/projections/delete.rb +0 -34
- data/lib/event_store_client/adapters/grpc/commands/projections/update.rb +0 -44
- data/lib/event_store_client/adapters/grpc/commands/streams/read_all.rb +0 -43
- data/lib/event_store_client/adapters/grpc/commands/streams/tombstone.rb +0 -35
- data/lib/event_store_client/adapters/http/README.md +0 -16
- data/lib/event_store_client/adapters/http/client.rb +0 -161
- data/lib/event_store_client/adapters/http/commands/command.rb +0 -27
- data/lib/event_store_client/adapters/http/commands/persistent_subscriptions/ack.rb +0 -15
- data/lib/event_store_client/adapters/http/commands/persistent_subscriptions/create.rb +0 -35
- data/lib/event_store_client/adapters/http/commands/persistent_subscriptions/read.rb +0 -60
- data/lib/event_store_client/adapters/http/commands/projections/create.rb +0 -33
- data/lib/event_store_client/adapters/http/commands/projections/update.rb +0 -31
- data/lib/event_store_client/adapters/http/commands/streams/append.rb +0 -49
- data/lib/event_store_client/adapters/http/commands/streams/delete.rb +0 -16
- data/lib/event_store_client/adapters/http/commands/streams/link_to.rb +0 -49
- data/lib/event_store_client/adapters/http/commands/streams/read.rb +0 -52
- data/lib/event_store_client/adapters/http/commands/streams/tombstone.rb +0 -17
- data/lib/event_store_client/adapters/http/connection.rb +0 -46
- data/lib/event_store_client/adapters/http/request_method.rb +0 -28
- data/lib/event_store_client/adapters/http.rb +0 -17
- data/lib/event_store_client/adapters/in_memory.rb +0 -144
- data/lib/event_store_client/broker.rb +0 -40
- data/lib/event_store_client/catch_up_subscription.rb +0 -42
- data/lib/event_store_client/catch_up_subscriptions.rb +0 -91
- data/lib/event_store_client/client.rb +0 -73
- data/lib/event_store_client/error_handler.rb +0 -10
- data/lib/event_store_client/subscription.rb +0 -23
- data/lib/event_store_client/subscriptions.rb +0 -38
- data/lib/event_store_client/value_objects/read_direction.rb +0 -43
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module EventStoreClient
|
4
|
-
module HTTP
|
5
|
-
module Commands
|
6
|
-
module Streams
|
7
|
-
class Tombstone < Command
|
8
|
-
def call(stream_name, options: {}) # rubocop:disable Lint/UnusedMethodArgument
|
9
|
-
headers = { 'ES-HardDelete' => 'true' }
|
10
|
-
connection.call(:delete, "/streams/#{stream_name}", body: {}, headers: headers)
|
11
|
-
Success()
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'faraday'
|
4
|
-
require 'event_store_client/adapters/http/request_method'
|
5
|
-
|
6
|
-
module EventStoreClient
|
7
|
-
module HTTP
|
8
|
-
class Connection
|
9
|
-
include Configuration
|
10
|
-
|
11
|
-
def call(method_name, path, body: {}, headers: {})
|
12
|
-
method = RequestMethod.new(method_name)
|
13
|
-
connection.send(method.to_s, path) do |req|
|
14
|
-
req.headers = req.headers.merge(headers)
|
15
|
-
req.body = body.is_a?(String) ? body : body.to_json
|
16
|
-
req.params['embed'] = 'body' if method == :get
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
21
|
-
|
22
|
-
def initialize(uri, options = {})
|
23
|
-
@connection = set_connection(uri, options)
|
24
|
-
end
|
25
|
-
|
26
|
-
attr_reader :options, :connection
|
27
|
-
|
28
|
-
DEFAULT_HEADERS = {
|
29
|
-
'Content-Type' => 'application/vnd.eventstore.events+json'
|
30
|
-
# 'Accept' => 'application/vnd.eventstore.atom+json',
|
31
|
-
}.freeze
|
32
|
-
|
33
|
-
def set_connection(uri, connection_options)
|
34
|
-
Faraday.new(
|
35
|
-
{
|
36
|
-
url: uri.to_s,
|
37
|
-
headers: DEFAULT_HEADERS
|
38
|
-
}.merge(connection_options)
|
39
|
-
) do |conn|
|
40
|
-
conn.basic_auth(config.eventstore_user, config.eventstore_password)
|
41
|
-
conn.adapter Faraday.default_adapter
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module EventStoreClient
|
4
|
-
module HTTP
|
5
|
-
class RequestMethod
|
6
|
-
InvalidMethodError = Class.new(StandardError)
|
7
|
-
def ==(other)
|
8
|
-
name == other.to_s
|
9
|
-
end
|
10
|
-
|
11
|
-
def to_s
|
12
|
-
name
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
attr_reader :name
|
18
|
-
|
19
|
-
SUPPORTED_METHODS = %w[get post put delete].freeze
|
20
|
-
|
21
|
-
def initialize(name)
|
22
|
-
raise InvalidMethodError unless SUPPORTED_METHODS.include?(name.to_s)
|
23
|
-
|
24
|
-
@name = name.to_s
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'event_store_client/adapters/http/commands/command'
|
4
|
-
|
5
|
-
require 'event_store_client/adapters/http/commands/persistent_subscriptions/create'
|
6
|
-
require 'event_store_client/adapters/http/commands/persistent_subscriptions/read'
|
7
|
-
|
8
|
-
require 'event_store_client/adapters/http/commands/projections/create'
|
9
|
-
require 'event_store_client/adapters/http/commands/projections/update'
|
10
|
-
|
11
|
-
require 'event_store_client/adapters/http/commands/streams/append'
|
12
|
-
require 'event_store_client/adapters/http/commands/streams/delete'
|
13
|
-
require 'event_store_client/adapters/http/commands/streams/link_to'
|
14
|
-
require 'event_store_client/adapters/http/commands/streams/read'
|
15
|
-
require 'event_store_client/adapters/http/commands/streams/tombstone'
|
16
|
-
|
17
|
-
require 'event_store_client/adapters/http/client'
|
@@ -1,144 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'dry/monads'
|
4
|
-
|
5
|
-
module EventStoreClient
|
6
|
-
class InMemory
|
7
|
-
Response = Struct.new(:body, :status) do
|
8
|
-
def success?
|
9
|
-
status == 200
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
attr_reader :event_store
|
14
|
-
|
15
|
-
def append_to_stream(stream_name, events, options: {}) # rubocop:disable Lint/UnusedMethodArgument,Metrics/LineLength
|
16
|
-
event_store[stream_name] = [] unless event_store.key?(stream_name)
|
17
|
-
[events].flatten.each do |event|
|
18
|
-
event_store[stream_name].unshift(
|
19
|
-
'eventId' => event.id,
|
20
|
-
'data' => event.data,
|
21
|
-
'eventType' => event.type,
|
22
|
-
'metaData' => event.metadata,
|
23
|
-
'positionEventNumber' => event_store[stream_name].length
|
24
|
-
)
|
25
|
-
end
|
26
|
-
Dry::Monads::Success(events)
|
27
|
-
end
|
28
|
-
|
29
|
-
def delete_stream(stream_name, options: {}) # rubocop:disable Lint/UnusedMethodArgument
|
30
|
-
event_store.delete(stream_name)
|
31
|
-
end
|
32
|
-
|
33
|
-
def tombstone_stream(stream_name, options: {}) # rubocop:disable Lint/UnusedMethodArgument
|
34
|
-
event_store.delete(stream_name)
|
35
|
-
end
|
36
|
-
|
37
|
-
def read(stream_name, options: {})
|
38
|
-
start = options[:start] == 'head' ? options[:start] : options[:start].to_i
|
39
|
-
direction = options[:direction] || 'forward'
|
40
|
-
response =
|
41
|
-
if %w[forward forwards].include?(direction)
|
42
|
-
read_stream_forward(stream_name, start: start)
|
43
|
-
else
|
44
|
-
read_stream_backward(stream_name, start: start)
|
45
|
-
end
|
46
|
-
|
47
|
-
res = Response.new(response.to_json, 200)
|
48
|
-
|
49
|
-
return [] if res.body.nil? || res.body.empty?
|
50
|
-
skip_decryption = options[:skip_decryption] || false
|
51
|
-
events = JSON.parse(res.body)['entries'].map do |entry|
|
52
|
-
deserialize_event(entry, skip_decryption: skip_decryption)
|
53
|
-
end.reverse
|
54
|
-
Dry::Monads::Success(events)
|
55
|
-
end
|
56
|
-
|
57
|
-
def read_all_from_stream(stream_name, options: {})
|
58
|
-
read(stream_name, options: options)
|
59
|
-
end
|
60
|
-
|
61
|
-
def subscribe_to_stream(subscription, **)
|
62
|
-
# TODO: implement method body
|
63
|
-
end
|
64
|
-
|
65
|
-
def link_to(stream_name, events, **)
|
66
|
-
append_to_stream(stream_name, events)
|
67
|
-
end
|
68
|
-
|
69
|
-
def listen(subscription, options: {})
|
70
|
-
# TODO: implement method body
|
71
|
-
end
|
72
|
-
|
73
|
-
private
|
74
|
-
|
75
|
-
attr_reader :per_page, :mapper
|
76
|
-
|
77
|
-
def initialize(mapper:, per_page: 20)
|
78
|
-
@per_page = per_page
|
79
|
-
@mapper = mapper
|
80
|
-
@event_store = {}
|
81
|
-
end
|
82
|
-
|
83
|
-
def read_stream_backward(stream_name, start: 0)
|
84
|
-
response = {
|
85
|
-
'entries' => [],
|
86
|
-
'links' => []
|
87
|
-
}
|
88
|
-
return response unless event_store.key?(stream_name)
|
89
|
-
|
90
|
-
start = start == 'head' ? event_store[stream_name].length - 1 : start
|
91
|
-
last_index = (start - per_page)
|
92
|
-
response['entries'] = event_store[stream_name].select do |event|
|
93
|
-
event['positionEventNumber'] > last_index &&
|
94
|
-
event['positionEventNumber'] <= start
|
95
|
-
end
|
96
|
-
response['links'] = links(stream_name, last_index, 'next', response['entries'], per_page)
|
97
|
-
|
98
|
-
response
|
99
|
-
end
|
100
|
-
|
101
|
-
def read_stream_forward(stream_name, start: 0)
|
102
|
-
response = {
|
103
|
-
'entries' => [],
|
104
|
-
'links' => []
|
105
|
-
}
|
106
|
-
|
107
|
-
return response unless event_store.key?(stream_name)
|
108
|
-
|
109
|
-
last_index = start + per_page
|
110
|
-
response['entries'] = event_store[stream_name].select do |event|
|
111
|
-
event['positionEventNumber'] < last_index &&
|
112
|
-
event['positionEventNumber'] >= start
|
113
|
-
end
|
114
|
-
response['links'] =
|
115
|
-
links(stream_name, last_index, 'previous', response['entries'], per_page)
|
116
|
-
|
117
|
-
response
|
118
|
-
end
|
119
|
-
|
120
|
-
def links(stream_name, batch_size, direction, entries, count)
|
121
|
-
if entries.empty? || batch_size.negative?
|
122
|
-
[]
|
123
|
-
else
|
124
|
-
[{
|
125
|
-
'uri' =>
|
126
|
-
"/streams/#{stream_name}/#{batch_size}/#{direction}/#{count}",
|
127
|
-
'relation' => direction
|
128
|
-
}]
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
def deserialize_event(entry, skip_decryption: false)
|
133
|
-
event = EventStoreClient::Event.new(
|
134
|
-
id: entry['eventId'],
|
135
|
-
title: entry['title'],
|
136
|
-
type: entry['eventType'],
|
137
|
-
data: entry['data'].to_json || '{}',
|
138
|
-
metadata: entry['isMetaData'] ? entry['metaData'] : '{}'
|
139
|
-
)
|
140
|
-
|
141
|
-
mapper.deserialize(event, skip_decryption: skip_decryption)
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module EventStoreClient
|
4
|
-
class Broker
|
5
|
-
include Configuration
|
6
|
-
|
7
|
-
# Distributes known subscriptions to multiple threads
|
8
|
-
# @param [EventStoreClient::Subscriptions]
|
9
|
-
# @param wait [Boolean] (Optional) Controls if broker should block
|
10
|
-
# main app process (useful for debugging)
|
11
|
-
#
|
12
|
-
def call(subscriptions, wait: false)
|
13
|
-
Signal.trap('TERM') do
|
14
|
-
Thread.new { logger&.info('Broker: TERM Signal has been received') }
|
15
|
-
threads.each do |thread|
|
16
|
-
thread.thread_variable_set(:terminate, true)
|
17
|
-
end
|
18
|
-
Thread.new { logger&.info('Broker: Terminate variable for subscription threads set') }
|
19
|
-
end
|
20
|
-
|
21
|
-
subscriptions.each do |subscription|
|
22
|
-
threads << Thread.new do
|
23
|
-
subscriptions.listen(subscription)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
threads.each(&:join) if wait
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
attr_reader :connection, :logger
|
32
|
-
attr_accessor :threads
|
33
|
-
|
34
|
-
def initialize(connection:)
|
35
|
-
@connection = connection
|
36
|
-
@threads = []
|
37
|
-
@logger = EventStoreClient.config.logger
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
@@ -1,42 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module EventStoreClient
|
4
|
-
class CatchUpSubscription
|
5
|
-
attr_reader :subscriber, :filter
|
6
|
-
attr_accessor :position
|
7
|
-
|
8
|
-
def options
|
9
|
-
{
|
10
|
-
filter: @filter,
|
11
|
-
without_system_events: @without_system_events,
|
12
|
-
all: {
|
13
|
-
position: {
|
14
|
-
commit_position: position[:commit_position],
|
15
|
-
prepare_position: position[:prepare_position]
|
16
|
-
}
|
17
|
-
}
|
18
|
-
}.compact
|
19
|
-
end
|
20
|
-
|
21
|
-
def name
|
22
|
-
self.class.name(subscriber)
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.name(subscriber)
|
26
|
-
subscriber.class.to_s
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
def initialize(subscriber, filter: nil, position: nil)
|
32
|
-
@filter = filter
|
33
|
-
@subscriber = subscriber
|
34
|
-
@position = position
|
35
|
-
@position ||= {
|
36
|
-
commit_position: 0,
|
37
|
-
prepare_position: 0
|
38
|
-
}
|
39
|
-
@without_system_events = true
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
@@ -1,91 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module EventStoreClient
|
4
|
-
class CatchUpSubscriptions
|
5
|
-
FILTER_DEFAULT_MAX = 32
|
6
|
-
FILTER_DEFAULT_CHECKPOINT_INTERVAL_MULTIPLIER = 10000
|
7
|
-
|
8
|
-
include Configuration
|
9
|
-
|
10
|
-
def create_or_load(subscriber, filter: {})
|
11
|
-
filter_options = prepare_filter_options(filter)
|
12
|
-
position = subscription_store.load_all_position(CatchUpSubscription.name(subscriber))
|
13
|
-
|
14
|
-
subscription = CatchUpSubscription.new(subscriber, position: position, filter: filter_options)
|
15
|
-
subscription_store.add(subscription) unless position
|
16
|
-
|
17
|
-
subscriptions << subscription unless @subscriptions.find { |s| s.name == subscription.name }
|
18
|
-
subscription
|
19
|
-
end
|
20
|
-
|
21
|
-
def each
|
22
|
-
subscriptions.each { |subscription| yield(subscription) }
|
23
|
-
end
|
24
|
-
|
25
|
-
def listen(subscription)
|
26
|
-
connection.subscribe(subscription.options) do |event_data|
|
27
|
-
next if recorded_event?(event_data)
|
28
|
-
next if confirmation?(event_data)
|
29
|
-
|
30
|
-
new_position = event_data[0]
|
31
|
-
event = event_data[1]
|
32
|
-
|
33
|
-
old_position = subscription.position
|
34
|
-
subscription.position = new_position
|
35
|
-
subscription_store.update_position(subscription)
|
36
|
-
next unless event
|
37
|
-
|
38
|
-
subscription.subscriber.call(event)
|
39
|
-
|
40
|
-
if Thread.current.thread_variable_get(:terminate)
|
41
|
-
msg =
|
42
|
-
"CatchUpSubscriptions: Terminating subscription listener for #{subscription.subscriber}"
|
43
|
-
logger&.info(msg)
|
44
|
-
break
|
45
|
-
end
|
46
|
-
rescue StandardError => e
|
47
|
-
subscription.position = old_position
|
48
|
-
subscription_store.update_position(subscription)
|
49
|
-
config.error_handler&.call(e)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def clean_unused
|
54
|
-
subscription_store.clean_unused(subscriptions.map(&:name))
|
55
|
-
end
|
56
|
-
|
57
|
-
def reset
|
58
|
-
subscription_store.reset(subscriptions)
|
59
|
-
end
|
60
|
-
|
61
|
-
private
|
62
|
-
|
63
|
-
attr_reader :connection, :subscriptions, :subscription_store, :logger
|
64
|
-
|
65
|
-
def initialize(connection:, subscription_store:)
|
66
|
-
@connection = connection
|
67
|
-
@subscription_store = subscription_store
|
68
|
-
@subscriptions = []
|
69
|
-
@logger = EventStoreClient.config.logger
|
70
|
-
end
|
71
|
-
|
72
|
-
def confirmation?(event_data)
|
73
|
-
event_data.is_a? EventStore::Client::Streams::ReadResp::SubscriptionConfirmation
|
74
|
-
end
|
75
|
-
|
76
|
-
def recorded_event?(event_data)
|
77
|
-
event_data.is_a? EventStore::Client::Streams::ReadResp::ReadEvent::RecordedEvent
|
78
|
-
end
|
79
|
-
|
80
|
-
def prepare_filter_options(filter)
|
81
|
-
return if filter.nil? || filter.empty?
|
82
|
-
|
83
|
-
{
|
84
|
-
event_type: filter[:event_type],
|
85
|
-
stream_identifier: filter[:stream_identifier],
|
86
|
-
max: FILTER_DEFAULT_MAX,
|
87
|
-
checkpointIntervalMultiplier: FILTER_DEFAULT_CHECKPOINT_INTERVAL_MULTIPLIER
|
88
|
-
}.compact
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
@@ -1,73 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'dry-struct'
|
4
|
-
|
5
|
-
module EventStoreClient
|
6
|
-
class Client
|
7
|
-
include Configuration
|
8
|
-
|
9
|
-
NoCallMethodOnSubscriber = Class.new(StandardError)
|
10
|
-
WrongExpectedEventVersion = Class.new(StandardError)
|
11
|
-
|
12
|
-
def publish(stream:, events:, options: {})
|
13
|
-
res = connection.append_to_stream(stream, events, options: options)
|
14
|
-
raise WrongExpectedEventVersion.new(res.failure) if res.failure?
|
15
|
-
res
|
16
|
-
end
|
17
|
-
|
18
|
-
def read(stream, options: {})
|
19
|
-
if options[:all]
|
20
|
-
connection.read_all_from_stream(stream, options: options)
|
21
|
-
else
|
22
|
-
connection.read(stream, options: options)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def subscribe(subscriber, to: [], options: {})
|
27
|
-
raise NoCallMethodOnSubscriber unless subscriber.respond_to?(:call)
|
28
|
-
@subscriptions.create(subscriber, to, options: options)
|
29
|
-
end
|
30
|
-
|
31
|
-
def subscribe_to_all(subscriber, filter=nil)
|
32
|
-
raise NoCallMethodOnSubscriber unless subscriber.respond_to?(:call)
|
33
|
-
|
34
|
-
@subscriptions.create_or_load(subscriber, filter: filter)
|
35
|
-
end
|
36
|
-
|
37
|
-
def reset_subscriptions
|
38
|
-
return unless @subscriptions.respond_to?(:reset)
|
39
|
-
|
40
|
-
@subscriptions.reset
|
41
|
-
end
|
42
|
-
|
43
|
-
def listen(wait: false)
|
44
|
-
broker.call(@subscriptions, wait: wait)
|
45
|
-
end
|
46
|
-
|
47
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
48
|
-
def link_to(stream:, events:, options: {})
|
49
|
-
raise ArgumentError if !stream || stream == ''
|
50
|
-
raise ArgumentError if events.nil? || (events.is_a?(Array) && events.empty?)
|
51
|
-
res = connection.link_to(stream, events, options: options)
|
52
|
-
raise WrongExpectedEventVersion.new(e.message) if res.failure?
|
53
|
-
|
54
|
-
res.success?
|
55
|
-
end
|
56
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
57
|
-
|
58
|
-
attr_accessor :connection
|
59
|
-
|
60
|
-
private
|
61
|
-
|
62
|
-
attr_reader :subscriptions, :broker, :error_handler
|
63
|
-
|
64
|
-
def initialize
|
65
|
-
@threads = []
|
66
|
-
@connection = EventStoreClient.adapter
|
67
|
-
@error_handler = config.error_handler
|
68
|
-
@broker = Broker.new(connection: connection)
|
69
|
-
@subscriptions = config.subscriptions_repo
|
70
|
-
@subscriptions ||= Subscriptions.new(connection: connection, service: config.service_name)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module EventStoreClient
|
4
|
-
class Subscription
|
5
|
-
attr_reader :stream, :subscriber, :name, :observed_streams
|
6
|
-
|
7
|
-
private
|
8
|
-
|
9
|
-
def initialize(subscriber, service:, event_types:)
|
10
|
-
subscriber_class =
|
11
|
-
if subscriber.class.name == 'Class'
|
12
|
-
subscriber.name
|
13
|
-
else
|
14
|
-
subscriber.class.name
|
15
|
-
end
|
16
|
-
@name = subscriber_class.to_s
|
17
|
-
@name = "#{service}-" + @name if service != ''
|
18
|
-
@subscriber = subscriber
|
19
|
-
@stream = name
|
20
|
-
@observed_streams = event_types.reduce([]) { |r, type| r << "$et-#{type}" }
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module EventStoreClient
|
4
|
-
class Subscriptions
|
5
|
-
def create(subscriber, event_types, options: {})
|
6
|
-
subscription = Subscription.new(subscriber, event_types: event_types, service: service)
|
7
|
-
|
8
|
-
unless @subscriptions.detect { |sub| sub.name == subscription.name }
|
9
|
-
connection.subscribe_to_stream(subscription, options: options)
|
10
|
-
subscriptions << subscription
|
11
|
-
end
|
12
|
-
|
13
|
-
subscription
|
14
|
-
end
|
15
|
-
|
16
|
-
def each
|
17
|
-
subscriptions.each do |subscription|
|
18
|
-
yield(subscription)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def listen(subscription)
|
23
|
-
connection.listen(subscription, options: { interval: 1, count: 10 }) do |event|
|
24
|
-
subscription.subscriber.call(event)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
attr_reader :connection, :subscriptions, :service
|
31
|
-
|
32
|
-
def initialize(connection:, service: 'default')
|
33
|
-
@connection = connection
|
34
|
-
@service = service
|
35
|
-
@subscriptions = []
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
@@ -1,43 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module EventStoreClient
|
4
|
-
class ReadDirection
|
5
|
-
Invalid = Class.new(StandardError)
|
6
|
-
|
7
|
-
def to_sym
|
8
|
-
value
|
9
|
-
end
|
10
|
-
|
11
|
-
def to_s
|
12
|
-
value.to_s
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
attr_reader :value
|
18
|
-
|
19
|
-
def initialize(str)
|
20
|
-
schema = Schema.new(direction: str)
|
21
|
-
|
22
|
-
unless %w[forwards backwards].include?(schema.direction)
|
23
|
-
raise Invalid.new('Allowed values: "forwards", "backwards"')
|
24
|
-
end
|
25
|
-
|
26
|
-
@value = schema.direction.capitalize.to_sym
|
27
|
-
end
|
28
|
-
|
29
|
-
|
30
|
-
class Schema < Dry::Struct
|
31
|
-
schema schema.strict
|
32
|
-
|
33
|
-
# resolve default types on nil
|
34
|
-
transform_types do |type|
|
35
|
-
type.constructor do |value|
|
36
|
-
value.is_a?(String) ? value.downcase : value
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
attribute :direction, Dry::Types['string']
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|