ld-celluloid-eventsource 0.5.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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.