pusher 0.7.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -17,6 +17,7 @@ tmtags
17
17
  coverage
18
18
  rdoc
19
19
  pkg
20
+ .yardoc
20
21
 
21
22
  ## PROJECT::SPECIFIC
22
23
  .bundle
@@ -0,0 +1 @@
1
+ script: "rspec spec/*_spec.rb"
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pusher (0.6.0)
4
+ pusher (0.7.0)
5
5
  crack (~> 0.1.0)
6
6
  json (~> 1.4.0)
7
7
  ruby-hmac (~> 0.4.0)
@@ -10,28 +10,26 @@ PATH
10
10
  GEM
11
11
  remote: http://rubygems.org/
12
12
  specs:
13
- addressable (2.2.2)
13
+ addressable (2.2.4)
14
14
  crack (0.1.8)
15
15
  diff-lcs (1.1.2)
16
- em-http-request (0.2.14)
16
+ em-http-request (0.2.15)
17
17
  addressable (>= 2.0.0)
18
18
  eventmachine (>= 0.12.9)
19
19
  eventmachine (0.12.10)
20
20
  json (1.4.6)
21
- rspec (2.0.1)
22
- rspec-core (~> 2.0.1)
23
- rspec-expectations (~> 2.0.1)
24
- rspec-mocks (~> 2.0.1)
25
- rspec-core (2.0.1)
26
- rspec-expectations (2.0.1)
27
- diff-lcs (>= 1.1.2)
28
- rspec-mocks (2.0.1)
29
- rspec-core (~> 2.0.1)
30
- rspec-expectations (~> 2.0.1)
21
+ rspec (2.5.0)
22
+ rspec-core (~> 2.5.0)
23
+ rspec-expectations (~> 2.5.0)
24
+ rspec-mocks (~> 2.5.0)
25
+ rspec-core (2.5.1)
26
+ rspec-expectations (2.5.0)
27
+ diff-lcs (~> 1.1.2)
28
+ rspec-mocks (2.5.0)
31
29
  ruby-hmac (0.4.0)
32
30
  signature (0.1.2)
33
31
  ruby-hmac
34
- webmock (1.4.0)
32
+ webmock (1.6.2)
35
33
  addressable (>= 2.2.2)
36
34
  crack (>= 0.1.7)
37
35
 
@@ -39,11 +37,7 @@ PLATFORMS
39
37
  ruby
40
38
 
41
39
  DEPENDENCIES
42
- crack (~> 0.1.0)
43
40
  em-http-request (~> 0.2.7)
44
- json (~> 1.4.0)
45
41
  pusher!
46
42
  rspec (~> 2.0)
47
- ruby-hmac (~> 0.4.0)
48
- signature (~> 0.1.2)
49
43
  webmock
data/README.md CHANGED
@@ -28,18 +28,25 @@ Errors are logged to `Pusher.logger`. It will by default use `Logger` from stdli
28
28
  Asynchronous triggering
29
29
  -----------------------
30
30
 
31
- To avoid blocking in a typical web application, if you are running inside eventmachine (for example if you use the thin server), you may wish to use the `trigger_async` method which uses the em-http-request gem to make api requests to pusher. It returns a deferrable which you can optionally bind to with success and failure callbacks. This is not a gem dependency, so you will need to install it manually.
31
+ To avoid blocking in a typical web application, you may wish to use the `trigger_async` method which uses the makes asynchronous API requests to Pusher. `trigger_async` returns a deferrable which you can optionally bind to with success and failure callbacks.
32
32
 
33
- d = Pusher['a_channel'].trigger_async('an_event', {:some => 'data'}, socket_id)
34
- d.callback {
33
+ You need to be running eventmachine to make use of this functionality. This is already the case if, for example, you're deploying to Heroku or using the Thin web server. You will also need to add `em-http-request` to your Gemfile.
34
+
35
+ $ gem install em-http-request
36
+
37
+ deferrable = Pusher['a_channel'].trigger_async('an_event', {
38
+ :some => 'data'
39
+ }, socket_id)
40
+ deferrable.callback {
35
41
  # Do something on success
36
42
  }
37
- d.errback { |error|
38
- # error is a pusher exception
43
+ deferrable.errback { |error|
44
+ # error is a instance of Pusher::Error
39
45
  }
40
46
 
41
47
  Private channels
42
- -----------------------
48
+ ----------------
49
+
43
50
  The Pusher Gem also deals with signing requests for authenticated private channels. A quick Rails controller example:
44
51
 
45
52
  reponse = Pusher['private-my_channel'].authenticate(params[:socket_id])
@@ -1,7 +1,18 @@
1
1
  autoload 'Logger', 'logger'
2
2
  require 'uri'
3
3
 
4
+ # Used for configuring API credentials and creating Channel objects
5
+ #
4
6
  module Pusher
7
+ # All Pusher errors descend from this class so you can easily rescue Pusher
8
+ # errors
9
+ #
10
+ # @example
11
+ # begin
12
+ # Pusher['a_channel'].trigger!('an_event', {:some => 'data'})
13
+ # rescue Pusher::Error => e
14
+ # # Do something on error
15
+ # end
5
16
  class Error < RuntimeError; end
6
17
  class AuthenticationError < Error; end
7
18
  class ConfigurationError < Error; end
@@ -11,6 +22,7 @@ module Pusher
11
22
  attr_writer :logger
12
23
  attr_accessor :app_id, :key, :secret
13
24
 
25
+ # @private
14
26
  def logger
15
27
  @logger ||= begin
16
28
  log = Logger.new(STDOUT)
@@ -19,11 +31,12 @@ module Pusher
19
31
  end
20
32
  end
21
33
 
34
+ # @private
22
35
  def authentication_token
23
36
  Signature::Token.new(@key, @secret)
24
37
  end
25
38
 
26
- # Builds a connection url for Pusherapp
39
+ # @private Builds a connection url for Pusherapp
27
40
  def url
28
41
  URI::Generic.build({
29
42
  :scheme => self.scheme,
@@ -33,7 +46,12 @@ module Pusher
33
46
  })
34
47
  end
35
48
 
36
- # Allows configuration from a url
49
+ # Configure Pusher connection by providing a url rather than specifying
50
+ # scheme, key, secret, and app_id separately.
51
+ #
52
+ # @example
53
+ # Pusher.url = http://KEY:SECRET@api.pusherapp.com/apps/APP_ID
54
+ #
37
55
  def url=(url)
38
56
  uri = URI.parse(url)
39
57
  self.app_id = uri.path.split('/').last
@@ -43,7 +61,12 @@ module Pusher
43
61
  self.port = uri.port
44
62
  end
45
63
 
46
- # Configure ssl by setting Pusher.encrypted = true
64
+ # Configure whether Pusher API calls should be made over SSL
65
+ # (default false)
66
+ #
67
+ # @example
68
+ # Pusher.encrypted = true
69
+ #
47
70
  def encrypted=(boolean)
48
71
  Pusher.scheme = boolean ? 'https' : 'http'
49
72
  # Configure port if it hasn't already been configured
@@ -65,6 +88,13 @@ module Pusher
65
88
  self.url = ENV['PUSHER_URL']
66
89
  end
67
90
 
91
+ # Return a channel by name
92
+ #
93
+ # @example
94
+ # Pusher['my-channel']
95
+ # @return [Channel]
96
+ # @raise [ConfigurationError] unless key, secret and app_id have been
97
+ # configured
68
98
  def self.[](channel_name)
69
99
  raise ConfigurationError, 'Missing configuration: please check that Pusher.url is configured' unless configured?
70
100
  @channels ||= {}
@@ -2,6 +2,7 @@ require 'crack/core_extensions' # Used for Hash#to_params
2
2
  require 'hmac-sha2'
3
3
 
4
4
  module Pusher
5
+ # Trigger events on Channels
5
6
  class Channel
6
7
  attr_reader :name
7
8
 
@@ -11,6 +12,17 @@ module Pusher
11
12
  @name = name
12
13
  end
13
14
 
15
+ # Trigger event asynchronously using EventMachine::HttpRequest
16
+ #
17
+ # @param (see #trigger!)
18
+ # @return [EM::DefaultDeferrable]
19
+ # Attach a callback to be notified of success (with no parameters).
20
+ # Attach an errback to be notified of failure (with an error parameter
21
+ # which includes the HTTP status code returned)
22
+ # @raise [LoadError] unless em-http-request gem is available
23
+ # @raise [Pusher::Error] unless the eventmachine reactor is running. You
24
+ # probably want to run your application inside a server such as thin
25
+ #
14
26
  def trigger_async(event_name, data, socket_id = nil, &block)
15
27
  unless defined?(EventMachine) && EventMachine.reactor_running?
16
28
  raise Error, "In order to use trigger_async you must be running inside an eventmachine loop"
@@ -24,7 +36,7 @@ module Pusher
24
36
  deferrable = EM::DefaultDeferrable.new
25
37
 
26
38
  http = @http_async.post({
27
- :query => request.query, :timeout => 2, :body => request.body,
39
+ :query => request.query, :timeout => 5, :body => request.body,
28
40
  :head => {'Content-Type'=> 'application/json'}
29
41
  })
30
42
  http.callback {
@@ -43,6 +55,23 @@ module Pusher
43
55
  deferrable
44
56
  end
45
57
 
58
+ # Trigger event
59
+ #
60
+ # @example
61
+ # begin
62
+ # Pusher['my-channel'].trigger!('an_event', {:some => 'data'})
63
+ # rescue Pusher::Error => e
64
+ # # Do something on error
65
+ # end
66
+ #
67
+ # @param data [Object] Event data to be triggered in javascript.
68
+ # Objects other than strings will be converted to JSON
69
+ # @param socket_id Allows excluding a given socket_id from receiving the
70
+ # event - see http://pusherapp.com/docs/duplicates for more info
71
+ #
72
+ # @raise [Pusher::Error] on invalid Pusher response
73
+ # @raise any Net::HTTP related errors
74
+ #
46
75
  def trigger!(event_name, data, socket_id = nil)
47
76
  require 'net/http' unless defined?(Net::HTTP)
48
77
  require 'net/https' if (ssl? && !defined?(Net::HTTPS))
@@ -62,18 +91,29 @@ module Pusher
62
91
  handle_response(response.code.to_i, response.body.chomp)
63
92
  end
64
93
 
94
+ # Trigger event, catching and logging any errors.
95
+ #
96
+ # @note CAUTION! No exceptions will be raised on failure
97
+ # @param (see #trigger!)
98
+ #
65
99
  def trigger(event_name, data, socket_id = nil)
66
100
  trigger!(event_name, data, socket_id)
67
101
  rescue StandardError => e
68
- handle_error e
102
+ Pusher.logger.error("#{e.message} (#{e.class})")
103
+ Pusher.logger.debug(e.backtrace.join("\n"))
69
104
  end
70
105
 
71
- # Auth string is:
72
- # if custom data provided:
73
- # socket_id:channel_name:[JSON-encoded custom data]
74
- # if no custom data:
75
- # socket_id:channel_name
76
- def socket_auth(socket_id, custom_string = nil)
106
+ # Compute authentication string required to subscribe to this channel.
107
+ #
108
+ # See http://pusherapp.com/docs/auth_signatures for more details.
109
+ #
110
+ # @param socket_id [String] Each Pusher socket connection receives a
111
+ # unique socket_id. This is sent from pusher.js to your server when
112
+ # channel authentication is required.
113
+ # @param custom_string [String] Allows signing additional data
114
+ # @return [String]
115
+ #
116
+ def authentication_string(socket_id, custom_string = nil)
77
117
  raise "Invalid socket_id" if socket_id.nil? || socket_id.empty?
78
118
  raise 'Custom argument must be a string' unless custom_string.nil? || custom_string.kind_of?(String)
79
119
 
@@ -85,8 +125,18 @@ module Pusher
85
125
  return "#{token.key}:#{signature}"
86
126
  end
87
127
 
88
- # Custom data is sent to server as JSON-encoded string in the :data key
89
- # If :data present, server must include it in auth check
128
+ # Deprecated - for backward compatibility
129
+ alias :socket_auth :authentication_string
130
+
131
+ # Generate an authentication endpoint response
132
+ #
133
+ # @example
134
+ # render :json => Pusher['private-my_channel'].authenticate(params[:socket_id])
135
+ #
136
+ # @return [Hash]
137
+ #
138
+ # @private Custom data is sent to server as JSON-encoded string
139
+ #
90
140
  def authenticate(socket_id, custom_data = nil)
91
141
  custom_data = Pusher::JSON.generate(custom_data) if custom_data
92
142
  auth = socket_auth(socket_id, custom_data)
@@ -97,11 +147,6 @@ module Pusher
97
147
 
98
148
  private
99
149
 
100
- def handle_error(e)
101
- Pusher.logger.error("#{e.message} (#{e.class})")
102
- Pusher.logger.debug(e.backtrace.join("\n"))
103
- end
104
-
105
150
  def handle_response(status_code, body)
106
151
  case status_code
107
152
  when 202
@@ -113,7 +158,7 @@ module Pusher
113
158
  when 404
114
159
  raise Error, "Resource not found: app_id is probably invalid"
115
160
  else
116
- raise Error, "Unknown error in Pusher: #{body}"
161
+ raise Error, "Unknown error (status code #{status_code}): #{body}"
117
162
  end
118
163
  end
119
164
 
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "pusher"
6
- s.version = "0.7.0"
6
+ s.version = "0.7.1"
7
7
  s.platform = Gem::Platform::RUBY
8
8
  s.authors = ["New Bamboo"]
9
9
  s.email = ["support@pusherapp.com"]
@@ -105,7 +105,7 @@ describe Pusher::Channel do
105
105
  ).to_return(:status => 500, :body => "some error")
106
106
  lambda {
107
107
  Pusher['test_channel'].trigger!('new_event', 'Some data')
108
- }.should raise_error(Pusher::Error, 'Unknown error in Pusher: some error')
108
+ }.should raise_error(Pusher::Error, 'Unknown error (status code 500): some error')
109
109
  end
110
110
  end
111
111
 
@@ -132,7 +132,7 @@ describe Pusher::Channel do
132
132
 
133
133
  describe "trigger_async" do
134
134
  before :each do
135
- WebMock.reset_webmock
135
+ WebMock.reset!
136
136
  WebMock.disable_net_connect!
137
137
 
138
138
  @pusher_url_regexp = %r{/apps/20/channels/test_channel/events}
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 7
8
- - 0
9
- version: 0.7.0
8
+ - 1
9
+ version: 0.7.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - New Bamboo
@@ -14,13 +14,14 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-11-22 00:00:00 +00:00
17
+ date: 2011-02-17 00:00:00 +00:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: json
22
22
  prerelease: false
23
23
  requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
24
25
  requirements:
25
26
  - - ~>
26
27
  - !ruby/object:Gem::Version
@@ -35,6 +36,7 @@ dependencies:
35
36
  name: crack
36
37
  prerelease: false
37
38
  requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
38
40
  requirements:
39
41
  - - ~>
40
42
  - !ruby/object:Gem::Version
@@ -49,6 +51,7 @@ dependencies:
49
51
  name: ruby-hmac
50
52
  prerelease: false
51
53
  requirement: &id003 !ruby/object:Gem::Requirement
54
+ none: false
52
55
  requirements:
53
56
  - - ~>
54
57
  - !ruby/object:Gem::Version
@@ -63,6 +66,7 @@ dependencies:
63
66
  name: signature
64
67
  prerelease: false
65
68
  requirement: &id004 !ruby/object:Gem::Requirement
69
+ none: false
66
70
  requirements:
67
71
  - - ~>
68
72
  - !ruby/object:Gem::Version
@@ -77,6 +81,7 @@ dependencies:
77
81
  name: rspec
78
82
  prerelease: false
79
83
  requirement: &id005 !ruby/object:Gem::Requirement
84
+ none: false
80
85
  requirements:
81
86
  - - ~>
82
87
  - !ruby/object:Gem::Version
@@ -90,6 +95,7 @@ dependencies:
90
95
  name: webmock
91
96
  prerelease: false
92
97
  requirement: &id006 !ruby/object:Gem::Requirement
98
+ none: false
93
99
  requirements:
94
100
  - - ">="
95
101
  - !ruby/object:Gem::Version
@@ -102,6 +108,7 @@ dependencies:
102
108
  name: em-http-request
103
109
  prerelease: false
104
110
  requirement: &id007 !ruby/object:Gem::Requirement
111
+ none: false
105
112
  requirements:
106
113
  - - ~>
107
114
  - !ruby/object:Gem::Version
@@ -124,6 +131,7 @@ extra_rdoc_files: []
124
131
  files:
125
132
  - .document
126
133
  - .gitignore
134
+ - .travis.yml
127
135
  - Gemfile
128
136
  - Gemfile.lock
129
137
  - LICENSE
@@ -147,6 +155,7 @@ rdoc_options: []
147
155
  require_paths:
148
156
  - lib
149
157
  required_ruby_version: !ruby/object:Gem::Requirement
158
+ none: false
150
159
  requirements:
151
160
  - - ">="
152
161
  - !ruby/object:Gem::Version
@@ -154,6 +163,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
154
163
  - 0
155
164
  version: "0"
156
165
  required_rubygems_version: !ruby/object:Gem::Requirement
166
+ none: false
157
167
  requirements:
158
168
  - - ">="
159
169
  - !ruby/object:Gem::Version
@@ -163,7 +173,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
163
173
  requirements: []
164
174
 
165
175
  rubyforge_project:
166
- rubygems_version: 1.3.6
176
+ rubygems_version: 1.3.7
167
177
  signing_key:
168
178
  specification_version: 3
169
179
  summary: Pusherapp client