event_store_client 1.4.9 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 +74 -83
- 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 -92
- 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,92 +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
|
-
logger&.info("Subscription #{subscription.name} received event #{event_data.inspect}")
|
39
|
-
subscription.subscriber.call(event)
|
40
|
-
|
41
|
-
if Thread.current.thread_variable_get(:terminate)
|
42
|
-
msg =
|
43
|
-
"CatchUpSubscriptions: Terminating subscription listener for #{subscription.subscriber}"
|
44
|
-
logger&.info(msg)
|
45
|
-
break
|
46
|
-
end
|
47
|
-
rescue StandardError => e
|
48
|
-
subscription.position = old_position
|
49
|
-
subscription_store.update_position(subscription)
|
50
|
-
config.error_handler&.call(e)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def clean_unused
|
55
|
-
subscription_store.clean_unused(subscriptions.map(&:name))
|
56
|
-
end
|
57
|
-
|
58
|
-
def reset
|
59
|
-
subscription_store.reset(subscriptions)
|
60
|
-
end
|
61
|
-
|
62
|
-
private
|
63
|
-
|
64
|
-
attr_reader :connection, :subscriptions, :subscription_store, :logger
|
65
|
-
|
66
|
-
def initialize(connection:, subscription_store:)
|
67
|
-
@connection = connection
|
68
|
-
@subscription_store = subscription_store
|
69
|
-
@subscriptions = []
|
70
|
-
@logger = EventStoreClient.config.logger
|
71
|
-
end
|
72
|
-
|
73
|
-
def confirmation?(event_data)
|
74
|
-
event_data.is_a? EventStore::Client::Streams::ReadResp::SubscriptionConfirmation
|
75
|
-
end
|
76
|
-
|
77
|
-
def recorded_event?(event_data)
|
78
|
-
event_data.is_a? EventStore::Client::Streams::ReadResp::ReadEvent::RecordedEvent
|
79
|
-
end
|
80
|
-
|
81
|
-
def prepare_filter_options(filter)
|
82
|
-
return if filter.nil? || filter.empty?
|
83
|
-
|
84
|
-
{
|
85
|
-
event_type: filter[:event_type],
|
86
|
-
stream_identifier: filter[:stream_identifier],
|
87
|
-
max: FILTER_DEFAULT_MAX,
|
88
|
-
checkpointIntervalMultiplier: FILTER_DEFAULT_CHECKPOINT_INTERVAL_MULTIPLIER
|
89
|
-
}.compact
|
90
|
-
end
|
91
|
-
end
|
92
|
-
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
|