pusher-client 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,7 +6,7 @@ require 'pp'
6
6
 
7
7
  APP_KEY = ENV['PUSHER_KEY'] # || "YOUR_APPLICATION_KEY"
8
8
 
9
- PusherClient.logger = Logger.new('/dev/null')
9
+ PusherClient.logger = Logger.new(STDOUT)
10
10
  socket = PusherClient::Socket.new(APP_KEY)
11
11
 
12
12
  # Subscribe to a channel
@@ -1,21 +1,24 @@
1
1
  require 'json'
2
+ require 'hmac-sha2'
3
+ require 'digest/md5'
2
4
 
3
5
  module PusherClient
4
6
  class Socket
5
-
7
+
6
8
  # Mimick the JavaScript client
7
- CLIENT_ID = 'js'
8
- VERSION = '1.7.1'
9
+ CLIENT_ID = 'pusher-ruby-client'
10
+ VERSION = '0.2.2'
11
+ PROTOCOL = '5'
9
12
 
10
13
  attr_accessor :encrypted, :secure
11
14
  attr_reader :path, :connected, :channels, :global_channel, :socket_id
12
15
 
13
16
  def initialize(application_key, options={})
14
-
15
17
  raise ArgumentError if (!application_key.is_a?(String) || application_key.size < 1)
16
18
 
17
- @path = "/app/#{application_key}?client=#{CLIENT_ID}&version=#{VERSION}"
19
+ @path = "/app/#{application_key}?client=#{CLIENT_ID}&version=#{VERSION}&protocol=#{PROTOCOL}"
18
20
  @key = application_key
21
+ @secret = options[:secret]
19
22
  @socket_id = nil
20
23
  @channels = Channels.new
21
24
  @global_channel = Channel.new('pusher_global_channel')
@@ -25,8 +28,9 @@ module PusherClient
25
28
  @encrypted = options[:encrypted] || false
26
29
 
27
30
  bind('pusher:connection_established') do |data|
31
+ socket = JSON.parse(data)
28
32
  @connected = true
29
- @socket_id = data['socket_id']
33
+ @socket_id = socket['socket_id']
30
34
  subscribe_all
31
35
  end
32
36
 
@@ -35,7 +39,7 @@ module PusherClient
35
39
  end
36
40
 
37
41
  bind('pusher:error') do |data|
38
- PusherClient.logger.fatal("Pusher : error : #{data.message}")
42
+ PusherClient.logger.fatal("Pusher : error : #{data.inspect}")
39
43
  end
40
44
  end
41
45
 
@@ -48,7 +52,8 @@ module PusherClient
48
52
  PusherClient.logger.debug("Pusher : connecting : #{url}")
49
53
 
50
54
  @connection_thread = Thread.new {
51
- @connection = WebSocket.new(url)
55
+ options = {:ssl => @encrypted || @secure}
56
+ @connection = WebSocket.new(url, options)
52
57
  PusherClient.logger.debug "Websocket connected"
53
58
  loop do
54
59
  msg = @connection.receive[0]
@@ -77,13 +82,12 @@ module PusherClient
77
82
  end
78
83
  end
79
84
 
80
- def subscribe(channel_name)
85
+ def subscribe(channel_name, user_id = nil)
86
+ @user_data = {:user_id => user_id}.to_json unless user_id.nil?
87
+
81
88
  channel = @channels << channel_name
82
89
  if @connected
83
- send_event('pusher:subscribe', {
84
- 'channel' => channel.name
85
- })
86
- channel.acknowledge_subscription(nil)
90
+ authorize(channel, method(:authorize_callback))
87
91
  end
88
92
  return channel
89
93
  end
@@ -112,13 +116,55 @@ module PusherClient
112
116
  end
113
117
 
114
118
  def subscribe_all
115
- @channels.channels.clone.each{ |k,v|
119
+ @channels.channels.clone.each{ |k,v|
116
120
  subscribe(k)
117
121
  }
118
122
  end
119
-
123
+
124
+ #auth for private and presence
125
+ def authorize(channel, callback)
126
+ if is_private_channel(channel.name)
127
+ auth_data = get_private_auth(channel)
128
+ elsif is_presence_channel(channel.name)
129
+ auth_data = get_presence_auth(channel)
130
+ channel_data = @user_data
131
+ end
132
+ # could both be nil if didn't require auth
133
+ callback.call(channel, auth_data, channel_data)
134
+ end
135
+
136
+ def authorize_callback(channel, auth_data, channel_data)
137
+ send_event('pusher:subscribe', {
138
+ 'channel' => channel.name,
139
+ 'auth' => auth_data,
140
+ 'channel_data' => channel_data
141
+ })
142
+ channel.acknowledge_subscription(nil)
143
+ end
144
+
145
+ def is_private_channel(channel_name)
146
+ channel_name.match(/^private-/)
147
+ end
148
+
149
+ def is_presence_channel(channel_name)
150
+ channel_name.match(/^presence-/)
151
+ end
152
+
153
+ def get_private_auth(channel)
154
+ string_to_sign = @socket_id + ':' + channel.name
155
+ signature = HMAC::SHA256.hexdigest(@secret, string_to_sign)
156
+ return "#{@key}:#{signature}"
157
+ end
158
+
159
+ def get_presence_auth(channel)
160
+ string_to_sign = @socket_id + ':' + channel.name + ':' + @user_data
161
+ signature = HMAC::SHA256.hexdigest(@secret, string_to_sign)
162
+ return "#{@key}:#{signature}"
163
+ end
164
+
165
+
120
166
  # For compatibility with JavaScript client API
121
- alias :subscribeAll :subscribe_all
167
+ alias :subscribeAll :subscribe_all
122
168
 
123
169
  def send_event(event_name, data)
124
170
  payload = {'event' => event_name, 'data' => data}.to_json
@@ -1,6 +1,7 @@
1
1
  require 'rubygems'
2
2
  require 'socket'
3
3
  require 'libwebsocket'
4
+ require 'openssl'
4
5
 
5
6
  module PusherClient
6
7
  class WebSocket
@@ -11,6 +12,21 @@ module PusherClient
11
12
 
12
13
  @socket = TCPSocket.new(@hs.url.host, @hs.url.port || 80)
13
14
 
15
+ if params[:ssl] == true
16
+
17
+ ctx = OpenSSL::SSL::SSLContext.new
18
+ ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
19
+ # http://curl.haxx.se/ca/cacert.pem
20
+ ctx.ca_file = path_to_cert()
21
+
22
+ ssl_sock = OpenSSL::SSL::SSLSocket.new(@socket, ctx)
23
+ ssl_sock.sync_close = true
24
+ ssl_sock.connect
25
+
26
+ @socket = ssl_sock
27
+
28
+ end
29
+
14
30
  @socket.write(@hs.to_s)
15
31
  @socket.flush
16
32
 
@@ -29,6 +45,10 @@ module PusherClient
29
45
  end
30
46
  end
31
47
 
48
+ def path_to_cert
49
+ File.join(File.dirname(File.expand_path(__FILE__)), '../../certs/cacert.pem')
50
+ end
51
+
32
52
  def send(data)
33
53
  raise "no handshake!" unless @handshaked
34
54
 
@@ -1,17 +1,14 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
1
  # -*- encoding: utf-8 -*-
5
2
 
6
3
  Gem::Specification.new do |s|
7
4
  s.name = %q{pusher-client}
8
- s.version = "0.2.1"
5
+ s.version = "0.2.2"
9
6
 
10
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Logan Koester"]
8
+ s.authors = ["Logan Koester", "Phil Leggetter"]
12
9
  s.date = %q{2011-01-07}
13
- s.description = %q{Ruby client for consuming WebSockets from http://pusherapp.com}
14
- s.email = %q{logan@logankoester.com}
10
+ s.description = %q{Ruby client for consuming WebSockets from http://pusher.com}
11
+ s.email = %q{support@pusher.com}
15
12
  s.extra_rdoc_files = [
16
13
  "LICENSE.txt",
17
14
  "README.rdoc"
@@ -23,7 +20,6 @@ Gem::Specification.new do |s|
23
20
  "LICENSE.txt",
24
21
  "README.rdoc",
25
22
  "Rakefile",
26
- "VERSION",
27
23
  "examples/hello_pusher.rb",
28
24
  "examples/hello_pusher_async.rb",
29
25
  "lib/pusher-client.rb",
@@ -31,16 +27,17 @@ Gem::Specification.new do |s|
31
27
  "lib/pusher-client/channels.rb",
32
28
  "lib/pusher-client/socket.rb",
33
29
  "lib/pusher-client/websocket.rb",
30
+ "certs/cacert.pem",
34
31
  "pusher-client.gemspec",
35
32
  "test/pusherclient_test.rb",
36
33
  "test/test.watchr",
37
34
  "test/teststrap.rb"
38
35
  ]
39
- s.homepage = %q{http://github.com/logankoester/pusher-client}
36
+ s.homepage = %q{http://github.com/pusher/pusher-ruby-client}
40
37
  s.licenses = ["MIT"]
41
38
  s.require_paths = ["lib"]
42
39
  s.rubygems_version = %q{1.3.7}
43
- s.summary = %q{Ruby client for consuming WebSockets from http://pusherapp.com}
40
+ s.summary = %q{Ruby client for consuming WebSockets from http://pusher.com}
44
41
  s.test_files = [
45
42
  "examples/hello_pusher.rb",
46
43
  "examples/hello_pusher_async.rb",
@@ -48,32 +45,12 @@ Gem::Specification.new do |s|
48
45
  "test/teststrap.rb"
49
46
  ]
50
47
 
51
- if s.respond_to? :specification_version then
52
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
53
- s.specification_version = 3
48
+ s.add_runtime_dependency(%q<libwebsocket>, ["0.1.5"])
49
+ s.add_runtime_dependency(%q<ruby-hmac>, ["~> 0.4.0"])
50
+ s.add_runtime_dependency(%q<addressable>, ["~> 2.3.1"])
51
+ s.add_development_dependency(%q<bacon>, [">= 0"])
52
+ s.add_development_dependency(%q<rake>, [">= 0"])
53
+ s.add_development_dependency(%q<ruby-debug19>, [">= 0"])
54
54
 
55
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
56
- s.add_runtime_dependency(%q<eventmachine>, ["~> 0.12.10"])
57
- s.add_runtime_dependency(%q<libwebsocket>, ["~> 0.1.0"])
58
- s.add_development_dependency(%q<bacon>, [">= 0"])
59
- s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
60
- s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
61
- s.add_development_dependency(%q<rcov>, [">= 0"])
62
- else
63
- s.add_dependency(%q<eventmachine>, ["~> 0.12.10"])
64
- s.add_dependency(%q<libwebsocket>, ["~> 0.1.0"])
65
- s.add_dependency(%q<bacon>, [">= 0"])
66
- s.add_dependency(%q<bundler>, ["~> 1.0.0"])
67
- s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
68
- s.add_dependency(%q<rcov>, [">= 0"])
69
- end
70
- else
71
- s.add_dependency(%q<eventmachine>, ["~> 0.12.10"])
72
- s.add_dependency(%q<libwebsocket>, ["~> 0.1.0"])
73
- s.add_dependency(%q<bacon>, [">= 0"])
74
- s.add_dependency(%q<bundler>, ["~> 1.0.0"])
75
- s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
76
- s.add_dependency(%q<rcov>, [">= 0"])
77
- end
78
55
  end
79
56
 
data/test/teststrap.rb CHANGED
@@ -32,7 +32,7 @@ module PusherClient
32
32
  def connect(async = false)
33
33
  @connection_thread = Thread.new do
34
34
  @connection = TestConnection.new
35
- @global_channel.dispatch('pusher:connection_established', {'socket_id' => '123abc'})
35
+ @global_channel.dispatch('pusher:connection_established', JSON.dump({'socket_id' => '123abc'}))
36
36
  end
37
37
  @connection_thread.run
38
38
  @connection_thread.join unless async
metadata CHANGED
@@ -1,125 +1,127 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: pusher-client
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 2
8
- - 1
9
- version: 0.2.1
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.2
5
+ prerelease:
10
6
  platform: ruby
11
- authors:
7
+ authors:
12
8
  - Logan Koester
9
+ - Phil Leggetter
13
10
  autorequire:
14
11
  bindir: bin
15
12
  cert_chain: []
16
-
17
- date: 2011-01-07 00:00:00 -05:00
18
- default_executable:
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
21
- name: eventmachine
22
- requirement: &id001 !ruby/object:Gem::Requirement
13
+ date: 2011-01-07 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: libwebsocket
17
+ requirement: !ruby/object:Gem::Requirement
23
18
  none: false
24
- requirements:
25
- - - ~>
26
- - !ruby/object:Gem::Version
27
- segments:
28
- - 0
29
- - 12
30
- - 10
31
- version: 0.12.10
19
+ requirements:
20
+ - - '='
21
+ - !ruby/object:Gem::Version
22
+ version: 0.1.5
32
23
  type: :runtime
33
24
  prerelease: false
34
- version_requirements: *id001
35
- - !ruby/object:Gem::Dependency
36
- name: libwebsocket
37
- requirement: &id002 !ruby/object:Gem::Requirement
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - '='
29
+ - !ruby/object:Gem::Version
30
+ version: 0.1.5
31
+ - !ruby/object:Gem::Dependency
32
+ name: ruby-hmac
33
+ requirement: !ruby/object:Gem::Requirement
38
34
  none: false
39
- requirements:
35
+ requirements:
40
36
  - - ~>
41
- - !ruby/object:Gem::Version
42
- segments:
43
- - 0
44
- - 1
45
- - 0
46
- version: 0.1.0
37
+ - !ruby/object:Gem::Version
38
+ version: 0.4.0
47
39
  type: :runtime
48
40
  prerelease: false
49
- version_requirements: *id002
50
- - !ruby/object:Gem::Dependency
51
- name: bacon
52
- requirement: &id003 !ruby/object:Gem::Requirement
41
+ version_requirements: !ruby/object:Gem::Requirement
53
42
  none: false
54
- requirements:
55
- - - ">="
56
- - !ruby/object:Gem::Version
57
- segments:
58
- - 0
59
- version: "0"
60
- type: :development
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: 0.4.0
47
+ - !ruby/object:Gem::Dependency
48
+ name: addressable
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 2.3.1
55
+ type: :runtime
61
56
  prerelease: false
62
- version_requirements: *id003
63
- - !ruby/object:Gem::Dependency
64
- name: bundler
65
- requirement: &id004 !ruby/object:Gem::Requirement
57
+ version_requirements: !ruby/object:Gem::Requirement
66
58
  none: false
67
- requirements:
59
+ requirements:
68
60
  - - ~>
69
- - !ruby/object:Gem::Version
70
- segments:
71
- - 1
72
- - 0
73
- - 0
74
- version: 1.0.0
61
+ - !ruby/object:Gem::Version
62
+ version: 2.3.1
63
+ - !ruby/object:Gem::Dependency
64
+ name: bacon
65
+ requirement: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
75
71
  type: :development
76
72
  prerelease: false
77
- version_requirements: *id004
78
- - !ruby/object:Gem::Dependency
79
- name: jeweler
80
- requirement: &id005 !ruby/object:Gem::Requirement
73
+ version_requirements: !ruby/object:Gem::Requirement
81
74
  none: false
82
- requirements:
83
- - - ~>
84
- - !ruby/object:Gem::Version
85
- segments:
86
- - 1
87
- - 5
88
- - 2
89
- version: 1.5.2
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ - !ruby/object:Gem::Dependency
80
+ name: rake
81
+ requirement: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
90
87
  type: :development
91
88
  prerelease: false
92
- version_requirements: *id005
93
- - !ruby/object:Gem::Dependency
94
- name: rcov
95
- requirement: &id006 !ruby/object:Gem::Requirement
89
+ version_requirements: !ruby/object:Gem::Requirement
96
90
  none: false
97
- requirements:
98
- - - ">="
99
- - !ruby/object:Gem::Version
100
- segments:
101
- - 0
102
- version: "0"
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ - !ruby/object:Gem::Dependency
96
+ name: ruby-debug19
97
+ requirement: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ! '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
103
  type: :development
104
104
  prerelease: false
105
- version_requirements: *id006
106
- description: Ruby client for consuming WebSockets from http://pusherapp.com
107
- email: logan@logankoester.com
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: Ruby client for consuming WebSockets from http://pusher.com
112
+ email: support@pusher.com
108
113
  executables: []
109
-
110
114
  extensions: []
111
-
112
- extra_rdoc_files:
115
+ extra_rdoc_files:
113
116
  - LICENSE.txt
114
117
  - README.rdoc
115
- files:
118
+ files:
116
119
  - .document
117
120
  - Gemfile
118
121
  - Gemfile.lock
119
122
  - LICENSE.txt
120
123
  - README.rdoc
121
124
  - Rakefile
122
- - VERSION
123
125
  - examples/hello_pusher.rb
124
126
  - examples/hello_pusher_async.rb
125
127
  - lib/pusher-client.rb
@@ -127,44 +129,37 @@ files:
127
129
  - lib/pusher-client/channels.rb
128
130
  - lib/pusher-client/socket.rb
129
131
  - lib/pusher-client/websocket.rb
132
+ - certs/cacert.pem
130
133
  - pusher-client.gemspec
131
134
  - test/pusherclient_test.rb
132
135
  - test/test.watchr
133
136
  - test/teststrap.rb
134
- has_rdoc: true
135
- homepage: http://github.com/logankoester/pusher-client
136
- licenses:
137
+ homepage: http://github.com/pusher/pusher-ruby-client
138
+ licenses:
137
139
  - MIT
138
140
  post_install_message:
139
141
  rdoc_options: []
140
-
141
- require_paths:
142
+ require_paths:
142
143
  - lib
143
- required_ruby_version: !ruby/object:Gem::Requirement
144
+ required_ruby_version: !ruby/object:Gem::Requirement
144
145
  none: false
145
- requirements:
146
- - - ">="
147
- - !ruby/object:Gem::Version
148
- hash: 3350793472905548965
149
- segments:
150
- - 0
151
- version: "0"
152
- required_rubygems_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ! '>='
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ required_rubygems_version: !ruby/object:Gem::Requirement
153
151
  none: false
154
- requirements:
155
- - - ">="
156
- - !ruby/object:Gem::Version
157
- segments:
158
- - 0
159
- version: "0"
152
+ requirements:
153
+ - - ! '>='
154
+ - !ruby/object:Gem::Version
155
+ version: '0'
160
156
  requirements: []
161
-
162
157
  rubyforge_project:
163
- rubygems_version: 1.3.7
158
+ rubygems_version: 1.8.25
164
159
  signing_key:
165
160
  specification_version: 3
166
- summary: Ruby client for consuming WebSockets from http://pusherapp.com
167
- test_files:
161
+ summary: Ruby client for consuming WebSockets from http://pusher.com
162
+ test_files:
168
163
  - examples/hello_pusher.rb
169
164
  - examples/hello_pusher_async.rb
170
165
  - test/pusherclient_test.rb