twitter-stream 0.1.4 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of twitter-stream might be problematic. Click here for more details.

data/Rakefile CHANGED
@@ -7,6 +7,7 @@ Spec::Rake::SpecTask.new('spec') do |t|
7
7
  t.spec_files = FileList['spec/**/*.rb']
8
8
  t.spec_opts = %w(-fs --color)
9
9
  end
10
+ task :default => :spec
10
11
 
11
12
  begin
12
13
  require 'jeweler'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.4
1
+ 0.1.6
@@ -1,9 +1,10 @@
1
1
  require 'eventmachine'
2
2
  require 'em/buftok'
3
+ require 'uri'
3
4
 
4
5
  module Twitter
5
6
  class JSONStream < EventMachine::Connection
6
- MAX_LINE_LENGTH = 16*1024
7
+ MAX_LINE_LENGTH = 1024*1024
7
8
 
8
9
  # network failure reconnections
9
10
  NF_RECONNECT_START = 0.25
@@ -25,8 +26,11 @@ module Twitter
25
26
  :path => '/1/statuses/filter.json',
26
27
  :host => 'stream.twitter.com',
27
28
  :port => 80,
29
+ :ssl => false,
28
30
  :auth => 'test:test',
29
31
  :user_agent => 'TwitterStream',
32
+ :timeout => 0,
33
+ :proxy => ENV['HTTP_PROXY']
30
34
  }
31
35
 
32
36
  attr_accessor :code
@@ -34,10 +38,24 @@ module Twitter
34
38
  attr_accessor :nf_last_reconnect
35
39
  attr_accessor :af_last_reconnect
36
40
  attr_accessor :reconnect_retries
41
+ attr_accessor :proxy
37
42
 
38
43
  def self.connect options = {}
44
+ options[:port] = 443 if options[:ssl] && !options.has_key?(:port)
39
45
  options = DEFAULT_OPTIONS.merge(options)
40
- EventMachine.connect options[:host], options[:port], self, options
46
+
47
+ host = options[:host]
48
+ port = options[:port]
49
+
50
+ if options[:proxy]
51
+ proxy_uri = URI.parse(options[:proxy])
52
+ host = proxy_uri.host
53
+ port = proxy_uri.port
54
+ end
55
+
56
+ connection = EventMachine.connect host, port, self, options
57
+ connection.start_tls if options[:ssl]
58
+ connection
41
59
  end
42
60
 
43
61
  def initialize options = {}
@@ -46,6 +64,8 @@ module Twitter
46
64
  @nf_last_reconnect = nil
47
65
  @af_last_reconnect = nil
48
66
  @reconnect_retries = 0
67
+ @immediate_reconnect = false
68
+ @proxy = URI.parse(options[:proxy]) if options[:proxy]
49
69
  end
50
70
 
51
71
  def each_item &block
@@ -68,6 +88,12 @@ module Twitter
68
88
  @gracefully_closed = true
69
89
  close_connection
70
90
  end
91
+
92
+ def immediate_reconnect
93
+ @immediate_reconnect = true
94
+ @gracefully_closed = false
95
+ close_connection
96
+ end
71
97
 
72
98
  def unbind
73
99
  receive_line(@buffer.flush) unless @buffer.empty?
@@ -80,7 +106,7 @@ module Twitter
80
106
  receive_line(line)
81
107
  end
82
108
  rescue Exception => e
83
- receive_error(e.message)
109
+ receive_error("#{e.class}: " + [e.message, e.backtrace].flatten.join("\n\t"))
84
110
  close_connection
85
111
  return
86
112
  end
@@ -104,12 +130,22 @@ module Twitter
104
130
 
105
131
  def reconnect_after timeout
106
132
  @reconnect_callback.call(timeout, @reconnect_retries) if @reconnect_callback
107
- EventMachine.add_timer(timeout) do
133
+
134
+ if timeout == 0
108
135
  reconnect @options[:host], @options[:port]
136
+ else
137
+ EventMachine.add_timer(timeout) do
138
+ reconnect @options[:host], @options[:port]
139
+ end
109
140
  end
110
141
  end
111
142
 
112
143
  def reconnect_timeout
144
+ if @immediate_reconnect
145
+ @immediate_reconnect = false
146
+ return 0
147
+ end
148
+
113
149
  if (@code == 0) # network failure
114
150
  if @nf_last_reconnect
115
151
  @nf_last_reconnect += NF_RECONNECT_ADD
@@ -128,6 +164,7 @@ module Twitter
128
164
  end
129
165
 
130
166
  def reset_state
167
+ set_comm_inactivity_timeout @options[:timeout] if @options[:timeout] > 0
131
168
  @code = 0
132
169
  @headers = []
133
170
  @state = :init
@@ -136,10 +173,18 @@ module Twitter
136
173
 
137
174
  def send_request
138
175
  data = []
139
- data << "#{@options[:method]} #{@options[:path]} HTTP/1.1"
176
+ request_uri = @options[:path]
177
+ if @proxy
178
+ # proxies need the request to be for the full url
179
+ request_uri = "http#{'s' if @options[:ssl]}://#{@options[:host]}:#{@options[:port]}#{request_uri}"
180
+ end
181
+ data << "#{@options[:method]} #{request_uri} HTTP/1.1"
140
182
  data << "Host: #{@options[:host]}"
141
183
  data << "User-agent: #{@options[:user_agent]}" if @options[:user_agent]
142
184
  data << "Authorization: Basic " + [@options[:auth]].pack('m').delete("\r\n")
185
+ if @proxy && @proxy.user
186
+ data << "Proxy-Authorization: Basic " + ["#{@proxy.user}:#{@proxy.password}"].pack('m').delete("\r\n")
187
+ end
143
188
  if @options[:method] == 'POST'
144
189
  data << "Content-type: #{@options[:content_type]}"
145
190
  data << "Content-length: #{@options[:content].length}"
data/spec/spec_helper.rb CHANGED
@@ -12,4 +12,15 @@ end
12
12
 
13
13
  def read_fixture(path)
14
14
  File.read(fixture_path(path))
15
+ end
16
+
17
+ def connect_stream(opts={}, &blk)
18
+ EM.run {
19
+ opts.merge!(:host => Host, :port => Port)
20
+ stop_in = opts.delete(:stop_in) || 0.5
21
+ EM.start_server Host, Port, JSONServer
22
+ @stream = JSONStream.connect(opts)
23
+ blk.call if blk
24
+ EM.add_timer(stop_in){ EM.stop }
25
+ }
15
26
  end
@@ -1,3 +1,4 @@
1
+ $:.unshift "."
1
2
  require File.dirname(__FILE__) + '/../spec_helper.rb'
2
3
  require 'twitter/json_stream'
3
4
 
@@ -23,9 +24,18 @@ describe JSONStream do
23
24
  stream = JSONStream.connect {}
24
25
  end
25
26
 
27
+ it "should connect to the proxy if provided" do
28
+ EM.should_receive(:connect).with do |host, port, handler, opts|
29
+ host.should == 'my-proxy'
30
+ port.should == 8080
31
+ opts[:host].should == 'stream.twitter.com'
32
+ opts[:port].should == 80
33
+ opts[:proxy].should == 'http://my-proxy:8080'
34
+ end
35
+ stream = JSONStream.connect(:proxy => "http://my-proxy:8080") {}
36
+ end
26
37
  end
27
38
 
28
-
29
39
  Host = "127.0.0.1"
30
40
  Port = 9550
31
41
 
@@ -41,6 +51,7 @@ describe JSONStream do
41
51
  end
42
52
 
43
53
  context "on valid stream" do
54
+ attr_reader :stream
44
55
  before :each do
45
56
  $data_to_send = read_fixture('twitter/basic_http.txt')
46
57
  $recieved_data = ''
@@ -48,142 +59,104 @@ describe JSONStream do
48
59
  end
49
60
 
50
61
  it "should parse headers" do
51
- EM.run {
52
- EM.start_server Host, Port, JSONServer
53
- @stream = JSONStream.connect :host => Host, :port => Port
54
- EM.add_timer(0.5){ EM.stop }
55
- }
56
- @stream.code.should == 200
57
- @stream.headers[0].downcase.should include 'content-type'
62
+ connect_stream
63
+ stream.code.should == 200
64
+ stream.headers[0].downcase.should include 'content-type'
58
65
  end
59
66
 
60
67
  it "should parse headers even after connection close" do
61
- EM.run {
62
- $close_connection = true
63
- EM.start_server Host, Port, JSONServer
64
- @stream = JSONStream.connect :host => Host, :port => Port
65
- EM.add_timer(0.5){ EM.stop }
66
- }
67
- @stream.code.should == 200
68
- @stream.headers[0].downcase.should include 'content-type'
68
+ connect_stream
69
+ stream.code.should == 200
70
+ stream.headers[0].downcase.should include 'content-type'
69
71
  end
70
72
 
71
73
  it "should extract records" do
72
- EM.run {
73
- EM.start_server Host, Port, JSONServer
74
- @stream = JSONStream.connect :host => Host, :port => Port, :user_agent => 'TEST_USER_AGENT'
75
- EM.add_timer(0.5){ EM.stop }
76
- }
74
+ connect_stream :user_agent => 'TEST_USER_AGENT'
77
75
  $recieved_data.upcase.should include('USER-AGENT: TEST_USER_AGENT')
78
76
  end
79
77
 
80
78
  it "should send correct user agent" do
81
- EM.run {
82
- $close_connection = true
83
- EM.start_server Host, Port, JSONServer
84
- @stream = JSONStream.connect :host => Host, :port => Port
85
- EM.add_timer(0.5){ EM.stop }
86
- }
79
+ connect_stream
87
80
  end
88
81
  end
89
82
 
90
83
  context "on network failure" do
84
+ attr_reader :stream
91
85
  before :each do
92
86
  $data_to_send = ''
93
87
  $close_connection = true
94
88
  end
95
89
 
90
+ it "should timeout on inactivity" do
91
+ connect_stream :stop_in => 1.5 do
92
+ stream.should_receive(:reconnect)
93
+ end
94
+ end
95
+
96
96
  it "should reconnect on network failure" do
97
- EM.run {
98
- EM.start_server Host, Port, JSONServer
99
- @stream = JSONStream.connect :host => Host, :port => Port
100
- @stream.should_receive(:reconnect)
101
- EM.add_timer(0.5){ EM.stop }
102
- }
97
+ connect_stream do
98
+ stream.should_receive(:reconnect)
99
+ end
103
100
  end
104
101
 
105
102
  it "should reconnect with 0.25 at base" do
106
- EM.run {
107
- EM.start_server Host, Port, JSONServer
108
- @stream = JSONStream.connect :host => Host, :port => Port
109
- @stream.should_receive(:reconnect_after).with(0.25)
110
- EM.add_timer(0.5){ EM.stop }
111
- }
103
+ connect_stream do
104
+ stream.should_receive(:reconnect_after).with(0.25)
105
+ end
112
106
  end
113
107
 
114
108
  it "should reconnect with linear timeout" do
115
- EM.run {
116
- EM.start_server Host, Port, JSONServer
117
- @stream = JSONStream.connect :host => Host, :port => Port
118
- @stream.nf_last_reconnect = 1
119
- @stream.should_receive(:reconnect_after).with(1.25)
120
- EM.add_timer(0.5){ EM.stop }
121
- }
109
+ connect_stream do
110
+ stream.nf_last_reconnect = 1
111
+ stream.should_receive(:reconnect_after).with(1.25)
112
+ end
122
113
  end
123
114
 
124
115
  it "should stop reconnecting after 100 times" do
125
- EM.run {
126
- EM.start_server Host, Port, JSONServer
127
- @stream = JSONStream.connect :host => Host, :port => Port
128
- @stream.reconnect_retries = 100
129
- @stream.should_not_receive(:reconnect_after)
130
- EM.add_timer(0.5){ EM.stop }
131
- }
116
+ connect_stream do
117
+ stream.reconnect_retries = 100
118
+ stream.should_not_receive(:reconnect_after)
119
+ end
132
120
  end
133
121
 
134
122
  it "should notify after reconnect limit is reached" do
135
123
  timeout, retries = nil, nil
136
- EM.run {
137
- EM.start_server Host, Port, JSONServer
138
- @stream = JSONStream.connect :host => Host, :port => Port
139
- @stream.on_max_reconnects do |t, r|
124
+ connect_stream do
125
+ stream.on_max_reconnects do |t, r|
140
126
  timeout, retries = t, r
141
127
  end
142
- @stream.reconnect_retries = 100
143
- EM.add_timer(0.5){ EM.stop }
144
- }
128
+ stream.reconnect_retries = 100
129
+ end
145
130
  timeout.should == 0.25
146
131
  retries.should == 101
147
132
  end
148
133
  end
149
134
 
150
135
  context "on application failure" do
136
+ attr_reader :stream
151
137
  before :each do
152
138
  $data_to_send = 'HTTP/1.1 401 Unauthorized\r\nWWW-Authenticate: Basic realm="Firehose"\r\n\r\n1'
153
139
  $close_connection = true
154
140
  end
155
141
 
156
142
  it "should reconnect on application failure 10 at base" do
157
- EM.run {
158
- EM.start_server Host, Port, JSONServer
159
- @stream = JSONStream.connect :host => Host, :port => Port
160
- @stream.should_receive(:reconnect_after).with(10)
161
- EM.add_timer(0.5){ EM.stop }
162
- }
143
+ connect_stream do
144
+ stream.should_receive(:reconnect_after).with(10)
145
+ end
163
146
  end
164
147
 
165
148
  it "should reconnect with exponential timeout" do
166
- EM.run {
167
- EM.start_server Host, Port, JSONServer
168
- @stream = JSONStream.connect :host => Host, :port => Port
169
- @stream.af_last_reconnect = 160
170
- @stream.should_receive(:reconnect_after).with(320)
171
- EM.add_timer(0.5){ EM.stop }
172
- }
149
+ connect_stream do
150
+ stream.af_last_reconnect = 160
151
+ stream.should_receive(:reconnect_after).with(320)
152
+ end
173
153
  end
174
154
 
175
155
  it "should not try to reconnect after limit is reached" do
176
- EM.run {
177
- EM.start_server Host, Port, JSONServer
178
- @stream = JSONStream.connect :host => Host, :port => Port
179
- @stream.af_last_reconnect = 320
180
- @stream.should_not_receive(:reconnect_after)
181
- EM.add_timer(0.5){ EM.stop }
182
- }
156
+ connect_stream do
157
+ stream.af_last_reconnect = 320
158
+ stream.should_not_receive(:reconnect_after)
159
+ end
183
160
  end
184
- end
185
-
186
-
187
-
188
- end
189
-
161
+ end
162
+ end
@@ -1,12 +1,15 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
1
4
  # -*- encoding: utf-8 -*-
2
5
 
3
6
  Gem::Specification.new do |s|
4
7
  s.name = %q{twitter-stream}
5
- s.version = "0.1.4"
8
+ s.version = "0.1.6"
6
9
 
7
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
11
  s.authors = ["Vladimir Kolesnikov"]
9
- s.date = %q{2009-12-01}
12
+ s.date = %q{2010-05-19}
10
13
  s.description = %q{Simple Ruby client library for twitter streaming API. Uses EventMachine for connection handling. Adheres to twitter's reconnection guidline. JSON format only.}
11
14
  s.email = %q{voloko@gmail.com}
12
15
  s.extra_rdoc_files = [
@@ -27,7 +30,7 @@ Gem::Specification.new do |s|
27
30
  s.homepage = %q{http://github.com/voloko/twitter-stream}
28
31
  s.rdoc_options = ["--charset=UTF-8"]
29
32
  s.require_paths = ["lib"]
30
- s.rubygems_version = %q{1.3.5}
33
+ s.rubygems_version = %q{1.3.6}
31
34
  s.summary = %q{Twitter realtime API client}
32
35
  s.test_files = [
33
36
  "spec/spec_helper.rb",
@@ -51,3 +54,4 @@ Gem::Specification.new do |s|
51
54
  s.add_dependency(%q<rspec>, [">= 1.2.8"])
52
55
  end
53
56
  end
57
+
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: twitter-stream
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 6
9
+ version: 0.1.6
5
10
  platform: ruby
6
11
  authors:
7
12
  - Vladimir Kolesnikov
@@ -9,29 +14,37 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2009-12-01 00:00:00 +03:00
17
+ date: 2010-05-19 00:00:00 +04:00
13
18
  default_executable:
14
19
  dependencies:
15
20
  - !ruby/object:Gem::Dependency
16
21
  name: eventmachine
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
20
24
  requirements:
21
25
  - - ">="
22
26
  - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ - 12
30
+ - 8
23
31
  version: 0.12.8
24
- version:
32
+ type: :runtime
33
+ version_requirements: *id001
25
34
  - !ruby/object:Gem::Dependency
26
35
  name: rspec
27
- type: :development
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
30
38
  requirements:
31
39
  - - ">="
32
40
  - !ruby/object:Gem::Version
41
+ segments:
42
+ - 1
43
+ - 2
44
+ - 8
33
45
  version: 1.2.8
34
- version:
46
+ type: :development
47
+ version_requirements: *id002
35
48
  description: Simple Ruby client library for twitter streaming API. Uses EventMachine for connection handling. Adheres to twitter's reconnection guidline. JSON format only.
36
49
  email: voloko@gmail.com
37
50
  executables: []
@@ -64,18 +77,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
64
77
  requirements:
65
78
  - - ">="
66
79
  - !ruby/object:Gem::Version
80
+ segments:
81
+ - 0
67
82
  version: "0"
68
- version:
69
83
  required_rubygems_version: !ruby/object:Gem::Requirement
70
84
  requirements:
71
85
  - - ">="
72
86
  - !ruby/object:Gem::Version
87
+ segments:
88
+ - 0
73
89
  version: "0"
74
- version:
75
90
  requirements: []
76
91
 
77
92
  rubyforge_project:
78
- rubygems_version: 1.3.5
93
+ rubygems_version: 1.3.6
79
94
  signing_key:
80
95
  specification_version: 3
81
96
  summary: Twitter realtime API client