event_store_client 0.1.0 → 0.1.1
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 +2 -4
- data/lib/event_store_client/client.rb +26 -26
- data/lib/event_store_client/configuration.rb +1 -1
- data/lib/event_store_client/connection.rb +1 -1
- data/lib/event_store_client/endpoint.rb +3 -5
- data/lib/event_store_client/store_adapter/api/client.rb +9 -7
- data/lib/event_store_client/store_adapter/api/request_method.rb +3 -3
- data/lib/event_store_client/store_adapter/in_memory.rb +24 -15
- data/lib/event_store_client/subscription.rb +1 -0
- data/lib/event_store_client/version.rb +1 -1
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 72306acfd8fecce9f4ed423a4f72421b553fb8892ec73d4c4da702505470eed1
|
4
|
+
data.tar.gz: 8c686d2ae4c1a4db9f55083b18cb24132c9187a8b47b1d6180064915adb5dd12
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50ea4daa3e0ae81deb0b85fc1cd5a3210f742b23c981d2d23d0708830714e2f2a1e94208b4a007303065fe2a9d3480ce1febc7f3c9072568db27c1948d54aafd
|
7
|
+
data.tar.gz: 4ef0826898e6ab83ffec67167d089ba023736771baf0a671eca0da371cbf6d9813ab3459c183795c3cf13fd3ed406885992f8a9f5f1db4a71eab1bc762b7d5fe
|
data/README.md
CHANGED
@@ -113,8 +113,6 @@ events = client.read('newstream', direction: 'backward') #default 'forward'
|
|
113
113
|
|
114
114
|
### Subscribing to events
|
115
115
|
|
116
|
-
# Using automatic pooling
|
117
|
-
|
118
116
|
```ruby
|
119
117
|
client.subscribe(DummyHandler, to: [SomethingHappened])
|
120
118
|
|
@@ -129,10 +127,10 @@ client.publish(stream: 'newstream', events: events)
|
|
129
127
|
# .... wait a little bit ... Your handler should be called for every single event you publish
|
130
128
|
```
|
131
129
|
|
132
|
-
### Stop
|
130
|
+
### Stop polling for new events
|
133
131
|
|
134
132
|
```ruby
|
135
|
-
client.
|
133
|
+
client.stop_polling
|
136
134
|
```
|
137
135
|
|
138
136
|
## Contributing
|
@@ -14,48 +14,48 @@ module EventStoreClient
|
|
14
14
|
connection.read(stream, direction: direction)
|
15
15
|
end
|
16
16
|
|
17
|
-
def subscribe(subscriber, to: [],
|
17
|
+
def subscribe(subscriber, to: [], polling: true)
|
18
18
|
raise NoCallMethodOnSubscriber unless subscriber.respond_to?(:call)
|
19
19
|
@subscriptions.create(subscriber, to)
|
20
|
-
|
20
|
+
poll if polling
|
21
21
|
end
|
22
22
|
|
23
|
-
def
|
24
|
-
return if @
|
25
|
-
@
|
23
|
+
def poll(interval: 5)
|
24
|
+
return if @polling_started
|
25
|
+
@polling_started = true
|
26
26
|
thread1 = Thread.new do
|
27
27
|
loop do
|
28
28
|
create_pid_file
|
29
|
-
Thread.handle_interrupt(Interrupt => :never)
|
30
|
-
|
31
|
-
|
32
|
-
broker.call(subscriptions)
|
33
|
-
}
|
34
|
-
rescue Exception => e
|
35
|
-
# When the thread had been interrupted or broker.call returned an error
|
36
|
-
sleep(interval) # wait for events to be processed
|
37
|
-
delete_pid_file
|
38
|
-
error_handler.call(e) if error_handler
|
39
|
-
ensure
|
40
|
-
# this code is run always
|
41
|
-
Thread.stop
|
29
|
+
Thread.handle_interrupt(Interrupt => :never) do
|
30
|
+
Thread.handle_interrupt(Interrupt => :immediate) do
|
31
|
+
broker.call(subscriptions)
|
42
32
|
end
|
43
|
-
|
33
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
34
|
+
# When the thread had been interrupted or broker.call returned an error
|
35
|
+
sleep(interval) # wait for events to be processed
|
36
|
+
delete_pid_file
|
37
|
+
error_handler&.call(e)
|
38
|
+
ensure
|
39
|
+
# this code is run always
|
40
|
+
Thread.stop
|
41
|
+
end
|
44
42
|
end
|
45
43
|
end
|
46
44
|
thread2 = Thread.new do
|
47
|
-
loop
|
45
|
+
loop do
|
46
|
+
sleep 1
|
47
|
+
break unless thread1.alive?
|
48
|
+
thread1.run
|
49
|
+
end
|
48
50
|
end
|
49
51
|
@threads = [thread1, thread2]
|
50
52
|
nil
|
51
53
|
end
|
52
54
|
|
53
|
-
def
|
55
|
+
def stop_polling
|
54
56
|
return if @threads.none?
|
55
|
-
@threads.each
|
56
|
-
|
57
|
-
end
|
58
|
-
@pooling_started = false
|
57
|
+
@threads.each(&:kill)
|
58
|
+
@polling_started = false
|
59
59
|
nil
|
60
60
|
end
|
61
61
|
|
@@ -79,7 +79,7 @@ module EventStoreClient
|
|
79
79
|
end
|
80
80
|
|
81
81
|
def create_pid_file
|
82
|
-
return unless File.
|
82
|
+
return unless File.exist?(config.pid_path)
|
83
83
|
File.open(config.pid_path, 'w') { |file| file.write(SecureRandom.uuid) }
|
84
84
|
end
|
85
85
|
|
@@ -13,7 +13,7 @@ module EventStoreClient
|
|
13
13
|
def read(stream, direction: 'forward')
|
14
14
|
response =
|
15
15
|
client.read(stream, start: 0, direction: direction)
|
16
|
-
return []
|
16
|
+
return [] if response.body&.empty?
|
17
17
|
JSON.parse(response.body)['entries'].map do |entry|
|
18
18
|
event = EventStoreClient::Event.new(
|
19
19
|
id: entry['eventId'],
|
@@ -4,13 +4,11 @@ require 'dry-struct'
|
|
4
4
|
|
5
5
|
module EventStoreClient
|
6
6
|
class Endpoint < Dry::Struct
|
7
|
+
attribute :host, Types::String
|
8
|
+
attribute :port, Types::Coercible::Integer
|
9
|
+
|
7
10
|
def url
|
8
11
|
"#{host}:#{port}"
|
9
12
|
end
|
10
|
-
|
11
|
-
private
|
12
|
-
|
13
|
-
attribute :host, Types::String
|
14
|
-
attribute :port, Types::Coercible::Integer
|
15
13
|
end
|
16
14
|
end
|
@@ -22,8 +22,11 @@ module EventStoreClient
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def delete_stream(stream_name, hard_delete)
|
25
|
-
headers =
|
26
|
-
|
25
|
+
headers = {
|
26
|
+
'ES-HardDelete' => hard_delete.to_s
|
27
|
+
}.reject { |_key, val| val.empty? }
|
28
|
+
|
29
|
+
make_request(:delete, "/streams/#{stream_name}", body: {}, headers: headers)
|
27
30
|
end
|
28
31
|
|
29
32
|
def read(stream_name, direction: 'forward', start: 0, count: per_page)
|
@@ -43,7 +46,7 @@ module EventStoreClient
|
|
43
46
|
resolveLinkTos: true
|
44
47
|
},
|
45
48
|
headers: {
|
46
|
-
|
49
|
+
'Content-Type' => 'application/json'
|
47
50
|
}
|
48
51
|
)
|
49
52
|
end
|
@@ -51,15 +54,14 @@ module EventStoreClient
|
|
51
54
|
def consume_feed(
|
52
55
|
stream_name,
|
53
56
|
subscription_name,
|
54
|
-
start: 0,
|
55
57
|
count: 1,
|
56
|
-
|
58
|
+
long_poll: 0
|
57
59
|
)
|
58
|
-
headers =
|
60
|
+
headers = long_poll.positive? ? { 'ES-LongPoll' => long_poll.to_s } : {}
|
59
61
|
headers['Content-Type'] = 'application/vnd.eventstore.competingatom+json'
|
60
62
|
headers['Accept'] = 'application/vnd.eventstore.competingatom+json'
|
61
63
|
make_request(
|
62
|
-
|
64
|
+
:get,
|
63
65
|
"/subscriptions/#{stream_name}/#{subscription_name}/#{count}",
|
64
66
|
headers: headers
|
65
67
|
)
|
@@ -17,13 +17,13 @@ module EventStoreClient
|
|
17
17
|
|
18
18
|
attr_reader :name
|
19
19
|
|
20
|
+
SUPPORTED_METHODS = %w[get post put delete].freeze
|
21
|
+
|
20
22
|
def initialize(name)
|
21
|
-
raise InvalidMethodError unless name.to_s
|
23
|
+
raise InvalidMethodError unless SUPPORTED_METHODS.include?(name.to_s)
|
22
24
|
|
23
25
|
@name = name.to_s
|
24
26
|
end
|
25
|
-
|
26
|
-
SUPPORTED_METHODS = %w[get post put].freeze
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
@@ -5,7 +5,7 @@ module EventStoreClient
|
|
5
5
|
class InMemory
|
6
6
|
attr_reader :event_store
|
7
7
|
|
8
|
-
def append_to_stream(stream_name, events, expected_version: nil)
|
8
|
+
def append_to_stream(stream_name, events, expected_version: nil) # rubocop:disable Lint/UnusedMethodArgument,Metrics/LineLength
|
9
9
|
event_store[stream_name] = [] unless event_store.key?(stream_name)
|
10
10
|
|
11
11
|
[events].flatten.each do |event|
|
@@ -19,14 +19,32 @@ module EventStoreClient
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
22
|
+
def read(stream_name, direction: 'forward', start: 0, count: per_page)
|
23
|
+
if direction == 'forward'
|
24
|
+
read_stream_forward(stream_name, start: start, count: per_page)
|
25
|
+
else
|
26
|
+
read_stream_backward(stream_name, start: start, count: per_page)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def delete_stream(stream_name, hard_delete: false) # rubocop:disable Lint/UnusedMethodArgument
|
23
31
|
event_store.delete(stream_name)
|
24
32
|
end
|
25
33
|
|
34
|
+
private
|
35
|
+
|
36
|
+
attr_reader :endpoint, :per_page
|
37
|
+
|
38
|
+
def initialize(host:, port:, per_page: 20)
|
39
|
+
@endpoint = Endpoint.new(host: host, port: port)
|
40
|
+
@per_page = per_page
|
41
|
+
@event_store = {}
|
42
|
+
end
|
43
|
+
|
26
44
|
def read_stream_backward(stream_name, start: 0, count: per_page)
|
27
45
|
return [] unless event_store.key?(stream_name)
|
28
46
|
|
29
|
-
start = start
|
47
|
+
start = start.zero? ? event_store[stream_name].length - 1 : start
|
30
48
|
last_index = start - count
|
31
49
|
entries = event_store[stream_name].select do |event|
|
32
50
|
event['positionEventNumber'] > last_index &&
|
@@ -52,22 +70,13 @@ module EventStoreClient
|
|
52
70
|
}
|
53
71
|
end
|
54
72
|
|
55
|
-
private
|
56
|
-
|
57
|
-
attr_reader :endpoint, :per_page
|
58
|
-
|
59
|
-
def initialize(host:, port:, per_page: 20)
|
60
|
-
@endpoint = Endpoint.new(host: host, port: port)
|
61
|
-
@per_page = per_page
|
62
|
-
@event_store = {}
|
63
|
-
end
|
64
|
-
|
65
73
|
def links(stream_name, batch_size, direction, entries, count)
|
66
|
-
if entries.empty? || batch_size
|
74
|
+
if entries.empty? || batch_size.negative?
|
67
75
|
[]
|
68
76
|
else
|
69
77
|
[{
|
70
|
-
'uri' =>
|
78
|
+
'uri' =>
|
79
|
+
"http://#{endpoint.url}/streams/#{stream_name}/#{batch_size}/#{direction}/#{count}",
|
71
80
|
'relation' => direction
|
72
81
|
}]
|
73
82
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: event_store_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sebastian Wilgosz
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-12-
|
11
|
+
date: 2019-12-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dry-struct
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: webmock
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
69
83
|
description: Easy to use client for event-sources applications written in ruby
|
70
84
|
email:
|
71
85
|
- sebastian@driggl.com
|
@@ -115,7 +129,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
115
129
|
- !ruby/object:Gem::Version
|
116
130
|
version: '0'
|
117
131
|
requirements: []
|
118
|
-
rubygems_version: 3.0.
|
132
|
+
rubygems_version: 3.0.6
|
119
133
|
signing_key:
|
120
134
|
specification_version: 4
|
121
135
|
summary: Ruby integration for https://eventstore.org
|