twitter-stream 0.1.4 → 0.1.6

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.

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