ld-celluloid-eventsource 0.5.0 → 0.8.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 436ffbb975c4f324a9f3589984e6bc9344884319
4
- data.tar.gz: 4396b0535c22dadff98bc1760642318157630451
3
+ metadata.gz: 8be57755b8e9109f162424b0bfc717494646820b
4
+ data.tar.gz: 4e99b0dfcca684ffc8b7f5404834c76dbf2bbc60
5
5
  SHA512:
6
- metadata.gz: 22c0dc786d05848a98ec0633c9c866a0d1375c33314c6b55664fac478e88f1c49bf8de53d5611f8ec17a0477b4f60aa2216b98b8085859ca0b48be547b5855d2
7
- data.tar.gz: b1de7d025ded3b794ad2a866dce4362b82b631708b0ddfa06c27ea48950973fdb02ab7fc4d64f2928cda4941f8e800a56ede50f54963c315893b6a63d073c372
6
+ metadata.gz: 7ba0c333067e2bcb0eda60c5df2d73bf75112bbc80f776f09cc33febd7700d977c034552c3fafad7daa4f7fb35b8277d8ffaf3f4f5238dc7b5644d6fc5d093dc
7
+ data.tar.gz: 3066e8834456d81e6f3a8191d922331e313f18f21522b9a0bfc39560eeb372734b1f518aa13a641edacf0d3ace029649139cf55f611ddd3b11fecc06067ad7b3
@@ -1,7 +1,7 @@
1
1
  # coding: utf-8
2
2
  lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'celluloid/eventsource/version'
4
+ require 'ld_celluloid_eventsource/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "ld-celluloid-eventsource"
@@ -20,8 +20,9 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_dependency 'celluloid-io', '~> 0.17.3'
22
22
  spec.add_dependency 'http_parser.rb', '~> 0.6.0'
23
+ spec.add_dependency 'concurrent-ruby', '~> 1.0.4'
24
+ spec.add_dependency 'retries', '~> 0.0.5'
23
25
 
24
- spec.add_development_dependency 'atomic', '~> 1.1'
25
26
  spec.add_development_dependency "rspec", '~> 3.0'
26
27
  spec.add_development_dependency "bundler", "~> 1.7"
27
28
  spec.add_development_dependency "rake", '~> 10.1'
@@ -2,19 +2,26 @@ require 'celluloid/current'
2
2
  require "celluloid/eventsource/version"
3
3
  require 'celluloid/io'
4
4
  require 'celluloid/eventsource/response_parser'
5
+ require 'concurrent'
6
+ require 'logger'
7
+ require 'retries'
5
8
  require 'uri'
6
9
 
7
10
  module Celluloid
8
11
  class EventSource
9
12
  include Celluloid::IO
10
13
 
11
- attr_reader :url, :with_credentials
14
+ attr_reader :url, :with_credentials, :heartbeat_timeout, :logger
12
15
  attr_reader :ready_state
13
16
 
14
17
  CONNECTING = 0
15
18
  OPEN = 1
16
19
  CLOSED = 2
17
20
 
21
+ # 2^31 since our retries library doesn't allow for unlimited retries.
22
+ # At an average of 1 second per retry, we'll still be retrying in 68 years.
23
+ MAX_RETRIES = 2147483648
24
+
18
25
  execute_block_on_receiver :initialize
19
26
 
20
27
  def initialize(uri, options = {})
@@ -22,6 +29,9 @@ module Celluloid
22
29
  options = options.dup
23
30
  @ready_state = CONNECTING
24
31
  @with_credentials = options.delete(:with_credentials) { false }
32
+ @heartbeat_timeout = options.delete(:heartbeat_timeout) { 300 }
33
+ @logger = options.delete(:logger) { default_logger }
34
+ @logger.info("[EventSource] Starting client connecting to url: #{self.url} with heartbeat timeout: #{@heartbeat_timeout} seconds")
25
35
  @headers = default_request_headers.merge(options.fetch(:headers, {}))
26
36
 
27
37
  @event_type_buffer = ""
@@ -31,7 +41,7 @@ module Celluloid
31
41
  @last_event_id = String.new
32
42
 
33
43
  @reconnect_timeout = 1
34
- @on = { open: ->{}, message: ->(_) {}, error: ->(_) {} }
44
+ @on = { open: ->{}, message: ->(_) {}}
35
45
  @parser = ResponseParser.new
36
46
 
37
47
  @chunked = false
@@ -58,14 +68,25 @@ module Celluloid
58
68
  begin
59
69
  establish_connection
60
70
  chunked? ? process_chunked_stream : process_stream
61
- rescue
62
- # Just reconnect
71
+ rescue Exception => e
72
+ logger.debug("[EventSource] Reconnecting after exception: #{e}")
63
73
  end
64
- sleep @reconnect_timeout
74
+ sleep @reconnect_timeout
65
75
  end
66
76
  end
67
77
 
78
+ def listen_for_heartbeats
79
+ @logger.debug("[EventSource] Starting listening for heartbeats. Reconnecting after #{@heartbeat_timeout} seconds if no comments are received")
80
+ @heartbeat_task.cancel if @heartbeat_task
81
+ @heartbeat_task = Concurrent::ScheduledTask.new(@heartbeat_timeout){
82
+ @logger.warn("[EventSource] Didn't get heartbeat after #{@heartbeat_timeout} seconds. Reconnecting.")
83
+ @socket.close if @socket
84
+ }.execute
85
+ end
86
+
68
87
  def close
88
+ @logger.info("[EventSource] Closing client")
89
+ @heartbeat_task.cancel if @heartbeat_task
69
90
  @socket.close if @socket
70
91
  @ready_state = CLOSED
71
92
  end
@@ -82,10 +103,6 @@ module Celluloid
82
103
  @on[:message] = action
83
104
  end
84
105
 
85
- def on_error(&action)
86
- @on[:error] = action
87
- end
88
-
89
106
  private
90
107
 
91
108
  MessageEvent = Struct.new(:type, :data, :last_event_id)
@@ -95,31 +112,38 @@ module Celluloid
95
112
  end
96
113
 
97
114
  def establish_connection
98
- @socket = Celluloid::IO::TCPSocket.new(@url.host, @url.port)
99
-
100
- if ssl?
101
- @socket = Celluloid::IO::SSLSocket.new(@socket)
102
- @socket.connect
115
+ handler = Proc.new do |exception, attempt_number, total_delay|
116
+ logger.warn("[EventSource] Could not connect with exception: #{exception.class} #{exception.message}; retry attempt #{attempt_number}; #{total_delay} seconds have passed.")
103
117
  end
104
118
 
105
- @socket.write(request_string)
119
+ with_retries(:max_tries => MAX_RETRIES,
120
+ :base_sleep_seconds => 1.0,
121
+ :max_sleep_seconds => 30.0,
122
+ :handler => handler,
123
+ :rescue => Exception) do
124
+ if !closed?
125
+ @logger.info("[EventSource] Connecting to url: #{@url}")
126
+ @socket = Celluloid::IO::TCPSocket.new(@url.host, @url.port)
106
127
 
107
- until @parser.headers?
108
- @parser << @socket.readline
109
- end
128
+ if ssl?
129
+ @socket = Celluloid::IO::SSLSocket.new(@socket)
130
+ @socket.connect
131
+ end
132
+
133
+ @socket.write(request_string)
134
+
135
+ until @parser.headers?
136
+ @parser << @socket.readline
137
+ end
110
138
 
111
- if @parser.status_code != 200
112
- until @socket.eof?
113
- @parser << @socket.readline
139
+ if @parser.status_code != 200
140
+ @socket.close if @socket
141
+ raise "[EventSource] Could not connect to stream. Got status code: #{@parser.status_code}"
142
+ end
143
+
144
+ handle_headers(@parser.headers)
114
145
  end
115
- # If the server returns a non-200, we don't want to close-- we just want to
116
- # report an error
117
- # close
118
- @on[:error].call({status_code: @parser.status_code, body: @parser.chunk})
119
- return
120
146
  end
121
-
122
- handle_headers(@parser.headers)
123
147
  end
124
148
 
125
149
  def default_request_headers
@@ -176,14 +200,16 @@ module Celluloid
176
200
 
177
201
  def parse_line(line)
178
202
  case line
179
- when /^:.*$/
180
- when /^(\w+): ?(.*)$/
181
- process_field($1, $2)
182
- else
183
- if chunked? && !@data_buffer.empty?
184
- @data_buffer.rstrip!
185
- process_field("data", line.rstrip)
186
- end
203
+ when /^: ?(.*)$/
204
+ @logger.debug("[EventSource] Got comment: #{$1}")
205
+ listen_for_heartbeats
206
+ when /^(\w+): ?(.*)$/
207
+ process_field($1, $2)
208
+ else
209
+ if chunked? && !@data_buffer.empty?
210
+ @data_buffer.rstrip!
211
+ process_field("data", line.rstrip)
212
+ end
187
213
  end
188
214
  end
189
215
 
@@ -196,6 +222,7 @@ module Celluloid
196
222
  event = MessageEvent.new(:message, @data_buffer, @last_event_id)
197
223
  event.type = @event_type_buffer.to_sym unless @event_type_buffer.empty?
198
224
 
225
+ @logger.debug("[EventSource] Dispatching event: #{event}")
199
226
  dispatch_event(event)
200
227
  ensure
201
228
  clear_buffers!
@@ -221,9 +248,11 @@ module Celluloid
221
248
  @chunked = !headers["Transfer-Encoding"].nil? && headers["Transfer-Encoding"].include?("chunked")
222
249
  @ready_state = OPEN
223
250
  @on[:open].call
251
+ @logger.info("[EventSource] Connected ok!")
252
+ listen_for_heartbeats
224
253
  else
225
- close
226
- @on[:error].call({status_code: @parser.status_code, body: "Invalid Content-Type #{headers['Content-Type']}. Expected text/event-stream"})
254
+ @socket.close if @socket
255
+ raise "Got invalid Content-Type header: #{headers['Content-Type']}. Expected text/event-stream"
227
256
  end
228
257
  end
229
258
 
@@ -233,6 +262,16 @@ module Celluloid
233
262
  ["GET #{url.request_uri} HTTP/1.1", headers].flatten.join("\r\n").concat("\r\n\r\n")
234
263
  end
235
264
 
265
+ def default_logger
266
+ if defined?(Rails) && Rails.respond_to?(:logger)
267
+ Rails.logger
268
+ else
269
+ log = ::Logger.new($stdout)
270
+ log.level = ::Logger::INFO
271
+ log
272
+ end
273
+ end
274
+
236
275
  end
237
276
 
238
277
  end
@@ -1,5 +1,5 @@
1
1
  module Celluloid
2
2
  class EventSource
3
- VERSION = "0.5.0"
3
+ VERSION = "0.8.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,111 +1,125 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ld-celluloid-eventsource
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Leo Correa
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-04 00:00:00.000000000 Z
11
+ date: 2017-01-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: celluloid-io
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: 0.17.3
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: 0.17.3
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: http_parser.rb
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: 0.6.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: 0.6.0
41
41
  - !ruby/object:Gem::Dependency
42
- name: atomic
42
+ name: concurrent-ruby
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '1.1'
48
- type: :development
47
+ version: 1.0.4
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.0.4
55
+ - !ruby/object:Gem::Dependency
56
+ name: retries
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.0.5
62
+ type: :runtime
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
- - - ~>
66
+ - - "~>"
53
67
  - !ruby/object:Gem::Version
54
- version: '1.1'
68
+ version: 0.0.5
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rspec
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
- - - ~>
73
+ - - "~>"
60
74
  - !ruby/object:Gem::Version
61
75
  version: '3.0'
62
76
  type: :development
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
- - - ~>
80
+ - - "~>"
67
81
  - !ruby/object:Gem::Version
68
82
  version: '3.0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: bundler
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
- - - ~>
87
+ - - "~>"
74
88
  - !ruby/object:Gem::Version
75
89
  version: '1.7'
76
90
  type: :development
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
- - - ~>
94
+ - - "~>"
81
95
  - !ruby/object:Gem::Version
82
96
  version: '1.7'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: rake
85
99
  requirement: !ruby/object:Gem::Requirement
86
100
  requirements:
87
- - - ~>
101
+ - - "~>"
88
102
  - !ruby/object:Gem::Version
89
103
  version: '10.1'
90
104
  type: :development
91
105
  prerelease: false
92
106
  version_requirements: !ruby/object:Gem::Requirement
93
107
  requirements:
94
- - - ~>
108
+ - - "~>"
95
109
  - !ruby/object:Gem::Version
96
110
  version: '10.1'
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: pry
99
113
  requirement: !ruby/object:Gem::Requirement
100
114
  requirements:
101
- - - ~>
115
+ - - "~>"
102
116
  - !ruby/object:Gem::Version
103
117
  version: '0.9'
104
118
  type: :development
105
119
  prerelease: false
106
120
  version_requirements: !ruby/object:Gem::Requirement
107
121
  requirements:
108
- - - ~>
122
+ - - "~>"
109
123
  - !ruby/object:Gem::Version
110
124
  version: '0.9'
111
125
  description: Celluloid::IO based library to consume Server-Sent Events. This library
@@ -116,17 +130,17 @@ executables: []
116
130
  extensions: []
117
131
  extra_rdoc_files: []
118
132
  files:
119
- - .gitignore
120
- - .rspec
121
- - .travis.yml
133
+ - ".gitignore"
134
+ - ".rspec"
135
+ - ".travis.yml"
122
136
  - Gemfile
123
137
  - LICENSE
124
138
  - README.md
125
139
  - Rakefile
126
140
  - ld-celluloid-eventsource.gemspec
127
- - lib/celluloid/eventsource.rb
128
- - lib/celluloid/eventsource/response_parser.rb
129
- - lib/celluloid/eventsource/version.rb
141
+ - lib/ld_celluloid_eventsource/eventsource.rb
142
+ - lib/ld_celluloid_eventsource/response_parser.rb
143
+ - lib/ld_celluloid_eventsource/version.rb
130
144
  - log/.gitignore
131
145
  - spec/celluloid/eventsource/response_parser_spec.rb
132
146
  - spec/celluloid/eventsource_spec.rb
@@ -143,17 +157,17 @@ require_paths:
143
157
  - lib
144
158
  required_ruby_version: !ruby/object:Gem::Requirement
145
159
  requirements:
146
- - - '>='
160
+ - - ">="
147
161
  - !ruby/object:Gem::Version
148
162
  version: '0'
149
163
  required_rubygems_version: !ruby/object:Gem::Requirement
150
164
  requirements:
151
- - - '>='
165
+ - - ">="
152
166
  - !ruby/object:Gem::Version
153
167
  version: '0'
154
168
  requirements: []
155
169
  rubyforge_project:
156
- rubygems_version: 2.5.0
170
+ rubygems_version: 2.5.1
157
171
  signing_key:
158
172
  specification_version: 4
159
173
  summary: ld-celluloid-eventsource is a gem to consume SSE streaming API.