ld-em-eventsource 0.2.2
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 +7 -0
- data/Gemfile +3 -0
- data/README.md +117 -0
- data/lib/ld-em-eventsource.rb +200 -0
- metadata +135 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e70e7f5b596b87a63a40c4015f57a19d0a45dd74
|
4
|
+
data.tar.gz: ab883c4378308c756df9df58c25d2db3ce1f9f3b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9eaff22a08d79c06719e432808a67cc9b81e3d502ecc6e301f33e25e84fff2b5defbcccbe7855d8a8d9ac8a459029a46901a89b5569e3e1bfa62f7aaa87f1e1c
|
7
|
+
data.tar.gz: 3675e0816e4d2658d89cf35ea1f754b16839d1015f8e15c5e8699dc50a11d9e096c1b8bffe56415bf5e06b06492e7ea7dfb3fd0e85d218280e8c13ce02daae7e
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
# EventSource client for EventMachine
|
2
|
+
|
3
|
+
See the specification: http://dev.w3.org/html5/eventsource/
|
4
|
+
|
5
|
+
## Install
|
6
|
+
|
7
|
+
Install with Rubygems:
|
8
|
+
|
9
|
+
gem install ld-em-eventsource
|
10
|
+
|
11
|
+
If you use bundler, add it to your Gemfile:
|
12
|
+
|
13
|
+
gem "ld-em-eventsource", "~> 0.2.2"
|
14
|
+
|
15
|
+
## Usage
|
16
|
+
|
17
|
+
Basic usage:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
require "ld-em-eventsource"
|
21
|
+
EM.run do
|
22
|
+
source = EventMachine::EventSource.new("http://example.com/streaming")
|
23
|
+
source.message do |message|
|
24
|
+
puts "new message #{message}"
|
25
|
+
end
|
26
|
+
source.start # Start listening
|
27
|
+
end
|
28
|
+
```
|
29
|
+
|
30
|
+
Listening specific event name:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
source.on "eventname" do |message|
|
34
|
+
puts "eventname #{message}"
|
35
|
+
end
|
36
|
+
```
|
37
|
+
|
38
|
+
Handle error:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
source.error do |error|
|
42
|
+
puts "error #{error}"
|
43
|
+
end
|
44
|
+
```
|
45
|
+
|
46
|
+
Handle open stream:
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
source.open do
|
50
|
+
puts "opened"
|
51
|
+
end
|
52
|
+
```
|
53
|
+
|
54
|
+
Close the stream:
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
source.close
|
58
|
+
```
|
59
|
+
|
60
|
+
Current status of the connection:
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
# Can be:
|
64
|
+
# - EM::EventSource::CLOSED
|
65
|
+
# - EM::EventSource::CONNECTING
|
66
|
+
# - EM::EventSource::OPEN
|
67
|
+
source.ready_state
|
68
|
+
```
|
69
|
+
|
70
|
+
Override the default retry value (if the connection is lost):
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
source.retry = 5 # in seconds (default 3)
|
74
|
+
```
|
75
|
+
|
76
|
+
Get Last-Event-Id value:
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
source.last_event_id
|
80
|
+
```
|
81
|
+
|
82
|
+
Attach middleware:
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
source.use EM::Middleware::JSONResponse
|
86
|
+
```
|
87
|
+
|
88
|
+
Set the inactivity timeout. Set to 0 to disable the timeout.
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
source.inactivity_timeout = 120 # in seconds (default: 60).
|
92
|
+
```
|
93
|
+
|
94
|
+
## Licence
|
95
|
+
|
96
|
+
MIT License
|
97
|
+
|
98
|
+
Copyright (C) 2012 by François de Metz
|
99
|
+
Copyright (C) 2011 by af83
|
100
|
+
|
101
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
102
|
+
of this software and associated documentation files (the "Software"), to deal
|
103
|
+
in the Software without restriction, including without limitation the rights
|
104
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
105
|
+
copies of the Software, and to permit persons to whom the Software is
|
106
|
+
furnished to do so, subject to the following conditions:
|
107
|
+
|
108
|
+
The above copyright notice and this permission notice shall be included in
|
109
|
+
all copies or substantial portions of the Software.
|
110
|
+
|
111
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
112
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
113
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
114
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
115
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
116
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
117
|
+
THE SOFTWARE.
|
@@ -0,0 +1,200 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "eventmachine"
|
4
|
+
require "em-http-request"
|
5
|
+
|
6
|
+
module EventMachine
|
7
|
+
# EventSource
|
8
|
+
# dev.w3.org/html5/eventsource/
|
9
|
+
class EventSource
|
10
|
+
# Get API url
|
11
|
+
attr_reader :url
|
12
|
+
# Get ready state
|
13
|
+
attr_reader :ready_state
|
14
|
+
# Get current retry value (in seconds)
|
15
|
+
attr_reader :retry
|
16
|
+
# Override retry value (in seconds)
|
17
|
+
attr_writer :retry
|
18
|
+
# Get value of last event id
|
19
|
+
attr_reader :last_event_id
|
20
|
+
# Get the inactivity timeout
|
21
|
+
attr_reader :inactivity_timeout
|
22
|
+
# Set the inactivity timeout
|
23
|
+
attr_writer :inactivity_timeout
|
24
|
+
# Ready state
|
25
|
+
# The connection has not yet been established, or it was closed and the user agent is reconnecting.
|
26
|
+
CONNECTING = 0
|
27
|
+
# The user agent has an open connection and is dispatching events as it receives them.
|
28
|
+
OPEN = 1
|
29
|
+
# The connection is not open, and the user agent is not trying to reconnect. Either there was a fatal error or the close() method was invoked.
|
30
|
+
CLOSED = 2
|
31
|
+
|
32
|
+
# Create a new stream
|
33
|
+
#
|
34
|
+
# url - the url as string
|
35
|
+
# query - the query string as hash
|
36
|
+
# headers - the headers for the request as hash
|
37
|
+
def initialize(url, query={}, headers={})
|
38
|
+
@url = url
|
39
|
+
@query = query
|
40
|
+
@headers = headers
|
41
|
+
@ready_state = CLOSED
|
42
|
+
|
43
|
+
@last_event_id = nil
|
44
|
+
@retry = 3 # seconds
|
45
|
+
@inactivity_timeout = 60 # seconds
|
46
|
+
|
47
|
+
@opens = []
|
48
|
+
@errors = []
|
49
|
+
@messages = []
|
50
|
+
@on = {}
|
51
|
+
@middlewares = []
|
52
|
+
end
|
53
|
+
|
54
|
+
# Add open event handler
|
55
|
+
#
|
56
|
+
# Returns nothing
|
57
|
+
def open(&block)
|
58
|
+
@opens << block
|
59
|
+
end
|
60
|
+
|
61
|
+
# Add a specific event handler
|
62
|
+
#
|
63
|
+
# name - name of event
|
64
|
+
#
|
65
|
+
# Returns nothing
|
66
|
+
def on(name, &block)
|
67
|
+
@on[name] ||= []
|
68
|
+
@on[name] << block
|
69
|
+
end
|
70
|
+
|
71
|
+
# Add message event handler
|
72
|
+
#
|
73
|
+
# Returns nothing
|
74
|
+
def message(&block)
|
75
|
+
@messages << block
|
76
|
+
end
|
77
|
+
|
78
|
+
# Add error event handler
|
79
|
+
#
|
80
|
+
# Returns nothing
|
81
|
+
def error(&block)
|
82
|
+
@errors << block
|
83
|
+
end
|
84
|
+
|
85
|
+
# Add a middleware
|
86
|
+
#
|
87
|
+
# *args - the middleware class
|
88
|
+
#
|
89
|
+
# Returns nothing
|
90
|
+
def use(*args, &block)
|
91
|
+
@middlewares << (args << block)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Start subscription
|
95
|
+
#
|
96
|
+
# Returns nothing
|
97
|
+
def start
|
98
|
+
@ready_state = CONNECTING
|
99
|
+
listen
|
100
|
+
end
|
101
|
+
|
102
|
+
# Cancel subscription
|
103
|
+
#
|
104
|
+
# Returns nothing
|
105
|
+
def close
|
106
|
+
@ready_state = CLOSED
|
107
|
+
@conn.close('requested') if @conn
|
108
|
+
end
|
109
|
+
|
110
|
+
# Gracefully reconnect
|
111
|
+
def reconnect
|
112
|
+
close
|
113
|
+
EM.add_timer(@retry) do
|
114
|
+
start
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
protected
|
119
|
+
|
120
|
+
def listen
|
121
|
+
@conn, @req = prepare_request
|
122
|
+
@req.headers(&method(:handle_headers))
|
123
|
+
@req.errback(&method(:handle_reconnect))
|
124
|
+
@req.callback(&method(:handle_reconnect))
|
125
|
+
buffer = ""
|
126
|
+
@req.stream do |chunk|
|
127
|
+
buffer += chunk
|
128
|
+
while index = buffer.index(/\r\n\r\n|\n\n/)
|
129
|
+
stream = buffer.slice!(0..index)
|
130
|
+
handle_stream(stream)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def handle_reconnect(*args)
|
136
|
+
return if @ready_state == CLOSED
|
137
|
+
@ready_state = CONNECTING
|
138
|
+
@errors.each { |error| error.call("Connection lost. Reconnecting.") }
|
139
|
+
EM.add_timer(@retry) do
|
140
|
+
listen
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def handle_headers(headers)
|
145
|
+
if headers.status != 200
|
146
|
+
reconnect
|
147
|
+
@errors.each { |error| error.call("Unexpected response status #{headers.status}") }
|
148
|
+
return
|
149
|
+
end
|
150
|
+
if /^text\/event-stream/.match headers['CONTENT_TYPE']
|
151
|
+
@ready_state = OPEN
|
152
|
+
@opens.each { |open| open.call }
|
153
|
+
else
|
154
|
+
close
|
155
|
+
@errors.each { |error| error.call("The content-type '#{headers['CONTENT_TYPE']}' is not text/event-stream") }
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def handle_stream(stream)
|
160
|
+
data = ""
|
161
|
+
name = nil
|
162
|
+
stream.split(/\r?\n/).each do |part|
|
163
|
+
/^data:(.+)$/.match(part) do |m|
|
164
|
+
data += m[1].strip
|
165
|
+
data += "\n"
|
166
|
+
end
|
167
|
+
/^id:(.+)$/.match(part) do |m|
|
168
|
+
@last_event_id = m[1].strip
|
169
|
+
end
|
170
|
+
/^event:(.+)$/.match(part) do |m|
|
171
|
+
name = m[1].strip
|
172
|
+
end
|
173
|
+
/^retry:(.+)$/.match(part) do |m|
|
174
|
+
if m[1].strip! =~ /^[0-9]+$/
|
175
|
+
@retry = m[1].to_i
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
return if data.empty?
|
180
|
+
data.chomp!
|
181
|
+
if name.nil?
|
182
|
+
@messages.each { |message| message.call(data) }
|
183
|
+
else
|
184
|
+
@on[name].each { |message| message.call(data) } if not @on[name].nil?
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def prepare_request
|
189
|
+
conn = EM::HttpRequest.new(@url, :inactivity_timeout => @inactivity_timeout)
|
190
|
+
@middlewares.each { |middleware|
|
191
|
+
block = middleware.pop
|
192
|
+
conn.use(*middleware, &block)
|
193
|
+
}
|
194
|
+
headers = @headers.merge({'Cache-Control' => 'no-cache', 'Accept' => 'text/event-stream'})
|
195
|
+
headers.merge!({'Last-Event-Id' => @last_event_id }) if not @last_event_id.nil?
|
196
|
+
[conn, conn.get({ :query => @query,
|
197
|
+
:head => headers})]
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
metadata
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ld-em-eventsource
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- François de Metz
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-09-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: eventmachine
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: em-http-request
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest-spec-context
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: bundler
|
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'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: |2
|
98
|
+
ld-em-eventsource is an eventmachine library to consume Server-Sent Events streaming API.
|
99
|
+
You can find the specification here: http://dev.w3.org/html5/eventsource/
|
100
|
+
This library was forked from https://github.com/AF83/em-eventsource
|
101
|
+
email: francois@2metz.fr
|
102
|
+
executables: []
|
103
|
+
extensions: []
|
104
|
+
extra_rdoc_files:
|
105
|
+
- README.md
|
106
|
+
files:
|
107
|
+
- Gemfile
|
108
|
+
- README.md
|
109
|
+
- lib/ld-em-eventsource.rb
|
110
|
+
homepage: http://github.com/launchdarkly/em-eventsource
|
111
|
+
licenses: []
|
112
|
+
metadata: {}
|
113
|
+
post_install_message:
|
114
|
+
rdoc_options: []
|
115
|
+
require_paths:
|
116
|
+
- lib
|
117
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - ">="
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
requirements: []
|
128
|
+
rubyforge_project:
|
129
|
+
rubygems_version: 2.2.2
|
130
|
+
signing_key:
|
131
|
+
specification_version: 4
|
132
|
+
summary: ld-em-eventsource is an eventmachine library to consume Server-Sent Events
|
133
|
+
streaming API.
|
134
|
+
test_files: []
|
135
|
+
has_rdoc:
|