firering 1.0.1 → 1.0.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.
- data/Rakefile +1 -0
- data/bin/campf-notify +1 -1
- data/firering.gemspec +2 -2
- data/lib/firering/connection.rb +46 -9
- data/lib/firering.rb +1 -1
- data/spec/firering/connection_spec.rb +36 -0
- data/spec/fixtures/load_server.rb +66 -7
- metadata +4 -4
data/Rakefile
CHANGED
data/bin/campf-notify
CHANGED
@@ -12,7 +12,7 @@ if subdomain.to_s =~ /^\s*$/ || token.to_s =~ /^\s*$/ || room_name.to_s =~ /^\s*
|
|
12
12
|
puts "Icon path #{icon_path} is incorrect" unless icon_path && File.exists?(icon_path)
|
13
13
|
puts "Room name #{room_name} is missing" unless room_name =~ /\S/
|
14
14
|
puts
|
15
|
-
puts "The following environment variables
|
15
|
+
puts "The following environment variables will be used: "
|
16
16
|
puts
|
17
17
|
puts "CAMPFIRE_SUBDOMAIN: #{subdomain || 'missing!'}"
|
18
18
|
puts "CAMPFIRE_TOKEN: #{token || 'missing!'}"
|
data/firering.gemspec
CHANGED
@@ -4,8 +4,8 @@ Gem::Specification.new do |s|
|
|
4
4
|
s.rubygems_version = '1.3.5'
|
5
5
|
|
6
6
|
s.name = 'firering'
|
7
|
-
s.version = '1.0.
|
8
|
-
s.date = '2010-
|
7
|
+
s.version = '1.0.2'
|
8
|
+
s.date = '2010-10-01'
|
9
9
|
s.rubyforge_project = 'firering'
|
10
10
|
|
11
11
|
s.summary = "Campfire API interface powered by EventMachine and Yajl."
|
data/lib/firering/connection.rb
CHANGED
@@ -12,8 +12,10 @@ module Firering
|
|
12
12
|
attr_accessor :token
|
13
13
|
attr_accessor :login
|
14
14
|
|
15
|
+
attr_reader :performed_retries
|
16
|
+
|
15
17
|
def initialize(host, streaming_host = "https://streaming.campfirenow.com")
|
16
|
-
@retry_delay, @redirects, @max_retries = 2, 1, 2
|
18
|
+
@retry_delay, @redirects, @max_retries, @performed_retries = 2, 1, 2, 0
|
17
19
|
self.host, self.streaming_host = host, streaming_host
|
18
20
|
yield self if block_given?
|
19
21
|
end
|
@@ -30,6 +32,10 @@ module Firering
|
|
30
32
|
@streaming_host = Addressable::URI.parse(host)
|
31
33
|
end
|
32
34
|
|
35
|
+
def subdomain
|
36
|
+
host.host.split(".").first
|
37
|
+
end
|
38
|
+
|
33
39
|
def auth_headers
|
34
40
|
token ? {'authorization' => [token, "X"] } : {'authorization' => [login, password] }
|
35
41
|
end
|
@@ -56,7 +62,7 @@ module Firering
|
|
56
62
|
end
|
57
63
|
|
58
64
|
http.callback {
|
59
|
-
|
65
|
+
reset_retries_counter
|
60
66
|
if callback
|
61
67
|
data = Yajl::Parser.parse(http.response, :symbolize_keys => true) rescue Hash.new
|
62
68
|
callback.call(data, http)
|
@@ -82,7 +88,15 @@ module Firering
|
|
82
88
|
logger.info("performing streaming request to #{uri.to_s}")
|
83
89
|
http = EventMachine::HttpRequest.new(uri).get(parameters)
|
84
90
|
|
85
|
-
http.stream
|
91
|
+
http.stream do |chunk|
|
92
|
+
begin
|
93
|
+
parser << chunk; reset_retries_counter
|
94
|
+
rescue Yajl::ParseError
|
95
|
+
perform_retry(http) do
|
96
|
+
stream(room_id, &callback)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
86
100
|
|
87
101
|
# Campfire servers will try to hold the streaming connections open indefinitely.
|
88
102
|
# However, API clients must be able to handle occasional timeouts or
|
@@ -97,19 +111,42 @@ module Firering
|
|
97
111
|
http
|
98
112
|
end
|
99
113
|
|
114
|
+
def max_retries_reached?
|
115
|
+
@performed_retries && @performed_retries >= @max_retries
|
116
|
+
end
|
117
|
+
|
100
118
|
def perform_retry(http, &callback)
|
101
|
-
if EventMachine.reactor_running?
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
119
|
+
if EventMachine.reactor_running?
|
120
|
+
|
121
|
+
if max_retries_reached?
|
122
|
+
logger.error("Firering performed #{performed_retries} but did not get any answer. Increase Firering::Connection.max_retries or check your internet connection.")
|
123
|
+
raise Firering::Connection::HTTPError.new(http)
|
124
|
+
else
|
125
|
+
logger.error("http error #{http.error}. Trying again in #{retry_delay} seconds...")
|
126
|
+
|
127
|
+
EventMachine::add_timer(retry_delay) do
|
128
|
+
logger.info("Reconnecting...")
|
129
|
+
increase_retries_counter
|
130
|
+
callback.call
|
131
|
+
end
|
107
132
|
end
|
133
|
+
|
108
134
|
else
|
109
135
|
logger.error("The event machine loop is not running")
|
110
136
|
raise Firering::Connection::HTTPError.new(http)
|
111
137
|
end
|
112
138
|
end
|
139
|
+
private :perform_retry
|
140
|
+
|
141
|
+
def reset_retries_counter
|
142
|
+
@performed_retries = 0
|
143
|
+
end
|
144
|
+
private :reset_retries_counter
|
145
|
+
|
146
|
+
def increase_retries_counter
|
147
|
+
@performed_retries = (@performed_retries || 0) + 1
|
148
|
+
end
|
149
|
+
private :increase_retries_counter
|
113
150
|
|
114
151
|
class HTTPError < RuntimeError
|
115
152
|
attr_reader :http
|
data/lib/firering.rb
CHANGED
@@ -16,10 +16,46 @@ describe Firering::Connection do
|
|
16
16
|
conn.stream(304355) do |message|
|
17
17
|
message.should be_an_instance_of(Firering::Message)
|
18
18
|
end
|
19
|
+
|
19
20
|
EM.add_timer(1) do
|
20
21
|
EM.stop
|
21
22
|
end
|
22
23
|
}
|
23
24
|
end
|
24
25
|
|
26
|
+
it "performs connection retries if the connection drops" do
|
27
|
+
conn.retry_delay = 1
|
28
|
+
make_fixture_server_fail_times(conn.max_retries)
|
29
|
+
messages = []
|
30
|
+
|
31
|
+
EM.run {
|
32
|
+
conn.stream(304355) do |message|
|
33
|
+
messages << message
|
34
|
+
end
|
35
|
+
EM.add_timer(conn.max_retries * conn.retry_delay + 1) do
|
36
|
+
EM.stop
|
37
|
+
end
|
38
|
+
}
|
39
|
+
|
40
|
+
messages.should_not be_empty
|
41
|
+
end
|
42
|
+
|
43
|
+
it "raises an exception if the connection drops and performed enough retries" do
|
44
|
+
conn.retry_delay = 1
|
45
|
+
make_fixture_server_fail_times(conn.max_retries + 1)
|
46
|
+
messages = []
|
47
|
+
|
48
|
+
begin
|
49
|
+
EM.run {
|
50
|
+
conn.stream(304355) { |message| messages << message }
|
51
|
+
|
52
|
+
EM.add_timer(conn.max_retries * conn.retry_delay + 1) { EM.stop }
|
53
|
+
}
|
54
|
+
rescue Firering::Connection::HTTPError
|
55
|
+
ensure
|
56
|
+
EM.stop if EventMachine.reactor_running?
|
57
|
+
end
|
58
|
+
|
59
|
+
messages.should be_empty
|
60
|
+
end
|
25
61
|
end
|
@@ -5,21 +5,72 @@ class MyLogger < Logger
|
|
5
5
|
end
|
6
6
|
|
7
7
|
class FixtureServer < Struct.new(:logger)
|
8
|
+
|
9
|
+
def initialize(*args)
|
10
|
+
super
|
11
|
+
@fails = 0
|
12
|
+
end
|
13
|
+
|
8
14
|
def call(env)
|
9
15
|
req = Rack::Request.new(env)
|
10
16
|
res = Rack::Response.new
|
11
|
-
|
17
|
+
|
18
|
+
if adjusted_fails?(req)
|
19
|
+
res.write("OK")
|
20
|
+
else
|
21
|
+
if @fails > 0
|
22
|
+
log_hi("I was requested to fail, fails left: #{ @fails }")
|
23
|
+
@fails -= 1
|
24
|
+
res.write("")
|
25
|
+
res.status = 404
|
26
|
+
else
|
27
|
+
log_hi("Trying to open fixture")
|
28
|
+
res.write read_fixture(req)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
12
32
|
res.finish
|
13
33
|
end
|
14
34
|
|
35
|
+
def adjusted_fails?(req)
|
36
|
+
if req.path =~ /fail\/(\d+)/
|
37
|
+
log_hi("I was requested to fail next #{ @fails = $1.to_i } requests")
|
38
|
+
true
|
39
|
+
elsif req.path =~ /fail\/reset/
|
40
|
+
@fails = 0
|
41
|
+
log_hi("Fail count reset, next requests should not fail (unless a fixture is missing)")
|
42
|
+
true
|
43
|
+
else
|
44
|
+
false
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def log(msg)
|
49
|
+
logger.info(" FIXTURES: #{msg}")
|
50
|
+
end
|
51
|
+
|
52
|
+
def log_hi(msg)
|
53
|
+
log("/" * 80) ; log(msg) ; log("/" * 80)
|
54
|
+
end
|
55
|
+
|
15
56
|
def read_fixture(req)
|
16
57
|
return "It Works!" if req.path == "" || req.path == "/"
|
17
|
-
|
18
|
-
path =
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
58
|
+
|
59
|
+
path = fixture_path(req)
|
60
|
+
|
61
|
+
if File.file?(path)
|
62
|
+
log("Fixture found: #{path}")
|
63
|
+
File.read(path).tap { |output| logger.info("\n\n#{output}\n") }
|
64
|
+
else
|
65
|
+
log("Fixture not found: #{path}")
|
66
|
+
"FIXTURE NOT FOUND #{path}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def fixture_path(req)
|
71
|
+
name_parts = [req.request_method.to_s.downcase] + req.path.split("/")
|
72
|
+
name = name_parts.join("_").squeeze("_").gsub(/\d+/, "ID")
|
73
|
+
File.expand_path(File.join(File.dirname(__FILE__), "json", name))
|
23
74
|
end
|
24
75
|
end
|
25
76
|
|
@@ -56,3 +107,11 @@ def start_fixtures_server(port)
|
|
56
107
|
|
57
108
|
pid
|
58
109
|
end
|
110
|
+
|
111
|
+
def make_fixture_server_fail_times(times)
|
112
|
+
open(URI("http://localhost:#{$specs_port}/fail/#{times}"))
|
113
|
+
end
|
114
|
+
|
115
|
+
def reset_fixture_server_fails
|
116
|
+
make_fixture_server_fail_times("reset")
|
117
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: firering
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 1.0.
|
9
|
+
- 2
|
10
|
+
version: 1.0.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Emmanuel Oga
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-
|
18
|
+
date: 2010-10-01 00:00:00 -03:00
|
19
19
|
default_executable: campf-notify
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|