pusher-client 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.bundle/config +2 -0
- data/.document +5 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +27 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +50 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/lib/pusher-client.rb +23 -0
- data/lib/pusher-client/channel.rb +54 -0
- data/lib/pusher-client/channels.rb +38 -0
- data/lib/pusher-client/socket.rb +164 -0
- data/test/pusherclient_test.rb +152 -0
- data/test/test.watchr +63 -0
- data/test/teststrap.rb +54 -0
- metadata +166 -0
data/.bundle/config
ADDED
data/.document
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
addressable (2.2.2)
|
5
|
+
bacon (1.1.0)
|
6
|
+
em-http-request (0.2.15)
|
7
|
+
addressable (>= 2.0.0)
|
8
|
+
eventmachine (>= 0.12.9)
|
9
|
+
eventmachine (0.12.10)
|
10
|
+
git (1.2.5)
|
11
|
+
jeweler (1.5.2)
|
12
|
+
bundler (~> 1.0.0)
|
13
|
+
git (>= 1.2.5)
|
14
|
+
rake
|
15
|
+
rake (0.8.7)
|
16
|
+
rcov (0.9.9)
|
17
|
+
|
18
|
+
PLATFORMS
|
19
|
+
ruby
|
20
|
+
|
21
|
+
DEPENDENCIES
|
22
|
+
bacon
|
23
|
+
bundler (~> 1.0.0)
|
24
|
+
em-http-request (~> 0.2.15)
|
25
|
+
eventmachine (~> 0.12.10)
|
26
|
+
jeweler (~> 1.5.2)
|
27
|
+
rcov
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Logan Koester
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
= PusherClient
|
2
|
+
|
3
|
+
pusher-client is a ruby gem for consuming WebSockets from the Pusher webservice[http://pusherapp.com]
|
4
|
+
|
5
|
+
It is driven by event-machine and maintains a connection to Pusher in its own thread.
|
6
|
+
|
7
|
+
== Installation
|
8
|
+
gem install pusher-client
|
9
|
+
== Usage
|
10
|
+
|
11
|
+
# Configuration
|
12
|
+
require 'pusher-client'
|
13
|
+
PusherClient.logger = Logger.new(STDOUT)
|
14
|
+
socket = PusherClient::Socket.new(YOUR_APPLICATION_KEY)
|
15
|
+
socket.connect
|
16
|
+
|
17
|
+
# Bind to a global event
|
18
|
+
socket.bind('globalevent') do |data|
|
19
|
+
# Do something
|
20
|
+
end
|
21
|
+
|
22
|
+
# Subscribe to a channel
|
23
|
+
socket.subscribe('mychannel')
|
24
|
+
|
25
|
+
# Bind to a channel event
|
26
|
+
socket['mychannel'].bind('channelevent') do |data|
|
27
|
+
# Do something
|
28
|
+
end
|
29
|
+
|
30
|
+
# Disconnect
|
31
|
+
socket.disconnect
|
32
|
+
|
33
|
+
For further documentation, read the source & test suite. Some features of the JavaScript client
|
34
|
+
are not yet implemented.
|
35
|
+
|
36
|
+
== Contributing to pusher-client
|
37
|
+
|
38
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
39
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
40
|
+
* Fork the project
|
41
|
+
* Start a feature/bugfix branch
|
42
|
+
* Commit and push until you are happy with your contribution
|
43
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
44
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
45
|
+
|
46
|
+
== Copyright
|
47
|
+
|
48
|
+
Copyright (c) 2010 Logan Koester. See LICENSE.txt for
|
49
|
+
further details.
|
50
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'rake'
|
11
|
+
|
12
|
+
require 'jeweler'
|
13
|
+
Jeweler::Tasks.new do |gem|
|
14
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
15
|
+
gem.name = "pusher-client"
|
16
|
+
gem.homepage = "http://github.com/logankoester/pusher-client"
|
17
|
+
gem.license = "MIT"
|
18
|
+
gem.summary = %Q{Ruby client for consuming WebSockets from http://pusherapp.com}
|
19
|
+
gem.description = %Q{Ruby client for consuming WebSockets from http://pusherapp.com}
|
20
|
+
gem.email = "logan@logankoester.com"
|
21
|
+
gem.authors = ["Logan Koester"]
|
22
|
+
end
|
23
|
+
Jeweler::RubygemsDotOrgTasks.new
|
24
|
+
|
25
|
+
require 'rake/testtask'
|
26
|
+
Rake::TestTask.new(:test) do |test|
|
27
|
+
test.libs << 'lib' << 'test'
|
28
|
+
test.pattern = 'test/**/*_test.rb'
|
29
|
+
test.verbose = true
|
30
|
+
end
|
31
|
+
|
32
|
+
require 'rcov/rcovtask'
|
33
|
+
Rcov::RcovTask.new do |test|
|
34
|
+
test.libs << 'test'
|
35
|
+
test.pattern = 'test/**/*_test.rb'
|
36
|
+
test.verbose = true
|
37
|
+
end
|
38
|
+
|
39
|
+
task :default => :test
|
40
|
+
|
41
|
+
require 'rake/rdoctask'
|
42
|
+
Rake::RDocTask.new do |rdoc|
|
43
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
44
|
+
|
45
|
+
rdoc.rdoc_dir = 'rdoc'
|
46
|
+
rdoc.title = "pusher-client #{version}"
|
47
|
+
rdoc.rdoc_files.include('README*')
|
48
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
49
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,23 @@
|
|
1
|
+
autoload :Logger, 'logger'
|
2
|
+
|
3
|
+
module PusherClient
|
4
|
+
HOST = 'ws.pusherapp.com'
|
5
|
+
WS_PORT = 80
|
6
|
+
WSS_PORT = 443
|
7
|
+
|
8
|
+
@logger = Logger.new(STDOUT)
|
9
|
+
|
10
|
+
def self.logger
|
11
|
+
@logger
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.logger=(logger)
|
15
|
+
@logger = logger
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
Thread.abort_on_exception = true
|
20
|
+
|
21
|
+
require File.dirname(__FILE__) + '/pusher-client/socket.rb'
|
22
|
+
require File.dirname(__FILE__) + '/pusher-client/channel.rb'
|
23
|
+
require File.dirname(__FILE__) + '/pusher-client/channels.rb'
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module PusherClient
|
2
|
+
|
3
|
+
class Channel
|
4
|
+
attr_accessor :global, :subscribed
|
5
|
+
attr_reader :name, :callbacks, :global_callbacks
|
6
|
+
|
7
|
+
def initialize(channel_name)
|
8
|
+
@name = channel_name
|
9
|
+
@global = false
|
10
|
+
@callbacks = {}
|
11
|
+
@global_callbacks = {}
|
12
|
+
@subscribed = false
|
13
|
+
end
|
14
|
+
|
15
|
+
def bind(event_name, &callback)
|
16
|
+
@callbacks[event_name] = callbacks[event_name] || []
|
17
|
+
@callbacks[event_name] << callback
|
18
|
+
return self
|
19
|
+
end
|
20
|
+
|
21
|
+
def dispatch_with_all(event_name, data)
|
22
|
+
dispatch(event_name, data)
|
23
|
+
dispatch_global_callbacks(event_name, data)
|
24
|
+
end
|
25
|
+
|
26
|
+
def dispatch(event_name, data)
|
27
|
+
PusherClient.logger.debug "Dispatching callbacks for #{event_name}"
|
28
|
+
if @callbacks[event_name]
|
29
|
+
@callbacks[event_name].each do |callback|
|
30
|
+
callback.call(data)
|
31
|
+
end
|
32
|
+
else
|
33
|
+
PusherClient.logger.debug "No callbacks to dispatch for #{event_name}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def dispatch_global_callbacks(event_name, data)
|
38
|
+
if @global_callbacks[event_name]
|
39
|
+
PusherClient.logger.debug "Dispatching global callbacks for #{event_name}"
|
40
|
+
@global_callbacks[event_name].each do |callback|
|
41
|
+
callback.call(data)
|
42
|
+
end
|
43
|
+
else
|
44
|
+
PusherClient.logger.debug "No global callbacks to dispatch for #{event_name}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def acknowledge_subscription(data)
|
49
|
+
@subscribed = true
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module PusherClient
|
2
|
+
class Channels
|
3
|
+
|
4
|
+
attr_reader :channels
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@channels = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def add(channel_name)
|
11
|
+
unless @channels[channel_name]
|
12
|
+
@channels[channel_name] = Channel.new(channel_name)
|
13
|
+
end
|
14
|
+
@channels[channel_name]
|
15
|
+
end
|
16
|
+
|
17
|
+
def find(channel_name)
|
18
|
+
@channels[channel_name]
|
19
|
+
end
|
20
|
+
|
21
|
+
def remove(channel_name)
|
22
|
+
@channels.delete(channel_name)
|
23
|
+
@channels
|
24
|
+
end
|
25
|
+
|
26
|
+
def empty?
|
27
|
+
@channels.empty?
|
28
|
+
end
|
29
|
+
|
30
|
+
def size
|
31
|
+
@channels.size
|
32
|
+
end
|
33
|
+
|
34
|
+
alias :<< :add
|
35
|
+
alias :[] :find
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'eventmachine'
|
3
|
+
require 'em-http'
|
4
|
+
|
5
|
+
module PusherClient
|
6
|
+
class Socket
|
7
|
+
|
8
|
+
# Mimick the JavaScript client
|
9
|
+
CLIENT_ID = 'js'
|
10
|
+
VERSION = '1.7.1'
|
11
|
+
|
12
|
+
attr_accessor :encrypted, :secure
|
13
|
+
attr_reader :path, :connected, :channels, :global_channel, :socket_id
|
14
|
+
|
15
|
+
def initialize(application_key, options={})
|
16
|
+
|
17
|
+
@path = "/app/#{application_key}?client=#{CLIENT_ID}&version=#{VERSION}"
|
18
|
+
@key = application_key
|
19
|
+
@socket_id = nil
|
20
|
+
@channels = Channels.new
|
21
|
+
@global_channel = Channel.new('pusher_global_channel')
|
22
|
+
@global_channel.global = true
|
23
|
+
@secure = false
|
24
|
+
@connected = false
|
25
|
+
@encrypted = options[:encrypted] || false
|
26
|
+
|
27
|
+
bind('pusher:connection_established') do |data|
|
28
|
+
@connected = true
|
29
|
+
@socket_id = data['socket_id']
|
30
|
+
subscribe_all
|
31
|
+
end
|
32
|
+
|
33
|
+
bind('pusher:connection_disconnected') do |data|
|
34
|
+
@channels.channels.each { |c| c.disconnect }
|
35
|
+
end
|
36
|
+
|
37
|
+
bind('pusher:error') do |data|
|
38
|
+
PusherClient.logger.fatal("Pusher : error : #{data.message}")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def connect
|
43
|
+
@connection_thread = Thread.new do
|
44
|
+
EventMachine.run {
|
45
|
+
if @encrypted || @secure
|
46
|
+
url = "wss://#{HOST}:#{WSS_PORT}#{@path}"
|
47
|
+
else
|
48
|
+
url = "ws://#{HOST}:#{WS_PORT}#{@path}"
|
49
|
+
end
|
50
|
+
PusherClient.logger.debug("Pusher : connecting : #{url}")
|
51
|
+
|
52
|
+
@connection = EventMachine::HttpRequest.new(url).get :timeout => 0
|
53
|
+
|
54
|
+
@connection.callback {
|
55
|
+
PusherClient.logger.debug "Websocket connected"
|
56
|
+
}
|
57
|
+
|
58
|
+
@connection.stream { |msg|
|
59
|
+
PusherClient.logger.debug "Received: #{msg}"
|
60
|
+
params = parser(msg)
|
61
|
+
return if (params['socket_id'] && params['socket_id'] == this.socket_id)
|
62
|
+
|
63
|
+
event_name = params['event']
|
64
|
+
event_data = params['data']
|
65
|
+
channel_name = params['channel']
|
66
|
+
|
67
|
+
send_local_event(event_name, event_data, channel_name)
|
68
|
+
}
|
69
|
+
|
70
|
+
@connection.errback {
|
71
|
+
PusherClient.logger.fatal "Pusher : eventmachine error"
|
72
|
+
}
|
73
|
+
|
74
|
+
@connection.disconnect {
|
75
|
+
PusherClient.logger.debug "Pusher : dropped connection"
|
76
|
+
}
|
77
|
+
}
|
78
|
+
end
|
79
|
+
@connection_thread.run
|
80
|
+
end
|
81
|
+
|
82
|
+
def disconnect
|
83
|
+
if @connected
|
84
|
+
PusherClient.logger.debug "Pusher : disconnecting"
|
85
|
+
@connection_thread.kill
|
86
|
+
@connected = false
|
87
|
+
else
|
88
|
+
PusherClient.logger.warn "Disconnect attempted... not connected"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def subscribe(channel_name)
|
93
|
+
channel = @channels << channel_name
|
94
|
+
if @connected
|
95
|
+
send_event('pusher:subscribe', {
|
96
|
+
'channel' => channel_name
|
97
|
+
})
|
98
|
+
channel.acknowledge_subscription(nil)
|
99
|
+
end
|
100
|
+
return channel
|
101
|
+
end
|
102
|
+
|
103
|
+
def unsubscribe(channel_name)
|
104
|
+
channel = @channels.remove channel_name
|
105
|
+
if @connected
|
106
|
+
send_event('pusher:unsubscribe', {
|
107
|
+
'channel' => channel_name
|
108
|
+
})
|
109
|
+
end
|
110
|
+
return channel
|
111
|
+
end
|
112
|
+
|
113
|
+
def bind(event_name, &callback)
|
114
|
+
@global_channel.bind(event_name, &callback)
|
115
|
+
return self
|
116
|
+
end
|
117
|
+
|
118
|
+
def [](channel_name)
|
119
|
+
if @channels[channel_name]
|
120
|
+
@channels[channel_name]
|
121
|
+
else
|
122
|
+
@channels << channel_name
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def subscribe_all
|
127
|
+
@channels.channels.each_with_index { |k,v| subscribe(k) }
|
128
|
+
end
|
129
|
+
|
130
|
+
# For compatibility with JavaScript client API
|
131
|
+
alias :subscribeAll :subscribe_all
|
132
|
+
|
133
|
+
def send_event(event_name, data)
|
134
|
+
payload = {'event' => event_name, 'data' => data}.to_json
|
135
|
+
@connection.send(payload)
|
136
|
+
PusherClient.logger.debug("Pusher : sending event : #{payload}")
|
137
|
+
end
|
138
|
+
|
139
|
+
protected
|
140
|
+
|
141
|
+
def send_local_event(event_name, event_data, channel_name)
|
142
|
+
if (channel_name)
|
143
|
+
channel = @channels[channel_name]
|
144
|
+
if (channel)
|
145
|
+
channel.dispatch_with_all(event_name, event_data)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
@global_channel.dispatch_with_all(event_name, event_data)
|
150
|
+
PusherClient.logger.debug("Pusher : event received : channel: #{channel_name}; event: #{event_name}")
|
151
|
+
end
|
152
|
+
|
153
|
+
def parser(data)
|
154
|
+
begin
|
155
|
+
return JSON.parse(data)
|
156
|
+
rescue => err
|
157
|
+
PusherClient.logger.warn(err)
|
158
|
+
PusherClient.logger.warn("Pusher : data attribute not valid JSON - you may wish to implement your own Pusher::Client.parser")
|
159
|
+
return data
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require File.dirname(File.expand_path(__FILE__)) + '/teststrap.rb'
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
describe "A PusherClient::Channels collection" do
|
5
|
+
before do
|
6
|
+
@channels = PusherClient::Channels.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should initialize empty" do
|
10
|
+
@channels.empty?.should.equal(true)
|
11
|
+
@channels.size.should.equal 0
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should instantiate new channels added to it by name" do
|
15
|
+
@channels << 'TestChannel'
|
16
|
+
@channels.find('TestChannel').class.should.equal(PusherClient::Channel)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should allow removal of channels by name" do
|
20
|
+
@channels << 'TestChannel'
|
21
|
+
@channels['TestChannel'].class.should.equal(PusherClient::Channel)
|
22
|
+
@channels.remove('TestChannel')
|
23
|
+
@channels.empty?.should.equal(true)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should not allow two channels of the same name" do
|
27
|
+
@channels << 'TestChannel'
|
28
|
+
@channels << 'TestChannel'
|
29
|
+
@channels.size.should.equal 1
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "A PusherClient::Channel" do
|
35
|
+
before do
|
36
|
+
@channels = PusherClient::Channels.new
|
37
|
+
@channel = @channels << "TestChannel"
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should not be subscribed by default' do
|
41
|
+
@channel.subscribed.should.equal false
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should not be global by default' do
|
45
|
+
@channel.global.should.equal false
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'can have procs bound to an event' do
|
49
|
+
@channel.bind('TestEvent') {}
|
50
|
+
@channel.callbacks.size.should.equal 1
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should run callbacks when an event is dispatched' do
|
54
|
+
|
55
|
+
@channel.bind('TestEvent') do
|
56
|
+
PusherClient.logger.test "Local callback running"
|
57
|
+
end
|
58
|
+
|
59
|
+
@channel.dispatch('TestEvent', {})
|
60
|
+
PusherClient.logger.test_messages.should.include?("Local callback running")
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "A PusherClient::Socket" do
|
66
|
+
before do
|
67
|
+
@socket = PusherClient::Socket.new(TEST_APP_KEY)
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should not connect when instantiated' do
|
71
|
+
@socket.connected.should.equal false
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "...when connected" do
|
75
|
+
before do
|
76
|
+
@socket.connect
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should know its connected' do
|
80
|
+
@socket.connected.should.equal true
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should know its socket_id' do
|
84
|
+
@socket.socket_id.should.equal '123abc'
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should not be subscribed to its global channel' do
|
88
|
+
@socket.global_channel.subscribed.should.equal false
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should subscribe to a channel' do
|
92
|
+
@channel = @socket.subscribe('testchannel')
|
93
|
+
@socket.channels['testchannel'].should.equal @channel
|
94
|
+
@channel.subscribed.should.equal true
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should unsubscribe from a channel' do
|
98
|
+
@channel = @socket.unsubscribe('testchannel')
|
99
|
+
PusherClient.logger.test_messages.last.should.include?('pusher:unsubscribe')
|
100
|
+
@socket.channels['testchannel'].should.equal nil
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'should allow binding of global events' do
|
104
|
+
@socket.bind('testevent') { |data| PusherClient.logger.test("testchannel received #{data}") }
|
105
|
+
@socket.global_channel.callbacks.has_key?('testevent').should.equal true
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should trigger callbacks for global events' do
|
109
|
+
@socket.bind('globalevent') { |data| PusherClient.logger.test("Global event!") }
|
110
|
+
@socket.global_channel.callbacks.has_key?('globalevent').should.equal true
|
111
|
+
|
112
|
+
@socket.simulate_received('globalevent', 'some data', '')
|
113
|
+
PusherClient.logger.test_messages.last.should.include?('Global event!')
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'should kill the connection thread when disconnect is called' do
|
117
|
+
@socket.disconnect
|
118
|
+
Thread.list.size.should.equal 1
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'should not be connected after disconnecting' do
|
122
|
+
@socket.disconnect
|
123
|
+
@socket.connected.should.equal false
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "when subscribed to a channel" do
|
127
|
+
before do
|
128
|
+
@channel = @socket.subscribe('testchannel')
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'should allow binding of callbacks for the subscribed channel' do
|
132
|
+
@socket['testchannel'].bind('testevent') { |data| PusherClient.logger.test(data) }
|
133
|
+
@socket['testchannel'].callbacks.has_key?('testevent').should.equal true
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should trigger channel callbacks when a message is received" do
|
137
|
+
# Bind 2 events for the channel
|
138
|
+
@socket['testchannel'].bind('coming') { |data| PusherClient.logger.test(data) }
|
139
|
+
@socket['testchannel'].bind('going') { |data| PusherClient.logger.test(data) }
|
140
|
+
|
141
|
+
# Simulate the first event
|
142
|
+
@socket.simulate_received('coming', 'Hello!', 'testchannel')
|
143
|
+
PusherClient.logger.test_messages.last.should.include?('Hello!')
|
144
|
+
|
145
|
+
# Simulate the second event
|
146
|
+
@socket.simulate_received('going', 'Goodbye!', 'testchannel')
|
147
|
+
PusherClient.logger.test_messages.last.should.include?('Goodbye!')
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
data/test/test.watchr
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
ENV["WATCHR"] = "1"
|
2
|
+
system 'clear'
|
3
|
+
puts "Watchr: Ready! :-)"
|
4
|
+
|
5
|
+
def notify_send(result)
|
6
|
+
#title = "Watchr Test Results"
|
7
|
+
if result.include?("FAILED") or result.include?("ERROR")
|
8
|
+
title = "FAIL"
|
9
|
+
image = "~/.autotest_images/fail.png"
|
10
|
+
message = "One or more tests have failed"
|
11
|
+
else
|
12
|
+
title = "PASS"
|
13
|
+
image = "~/.autotest_images/pass.png"
|
14
|
+
message = "All tests pass"
|
15
|
+
end
|
16
|
+
|
17
|
+
options = "-c Watchr --icon '#{File.expand_path(image)}' '#{title}' '#{message}' --urgency=critical"
|
18
|
+
system %(notify-send #{options} &)
|
19
|
+
end
|
20
|
+
|
21
|
+
def run(cmd)
|
22
|
+
puts(cmd)
|
23
|
+
`#{cmd}`
|
24
|
+
end
|
25
|
+
|
26
|
+
def run_all_tests
|
27
|
+
system('clear')
|
28
|
+
result = run "bacon test/*_test.rb"
|
29
|
+
notify_send result
|
30
|
+
puts result
|
31
|
+
end
|
32
|
+
|
33
|
+
def run_suite
|
34
|
+
run_all_tests
|
35
|
+
end
|
36
|
+
|
37
|
+
watch('test/teststrap\.rb') { run_all_tests }
|
38
|
+
watch('test/factories\.rb') { run_all_tests }
|
39
|
+
watch('test/.*_test.*\.rb') { run_all_tests }
|
40
|
+
watch('lib/*\.rb') { run_all_tests }
|
41
|
+
watch('lib/.*/*\.rb') { run_all_tests }
|
42
|
+
|
43
|
+
# Ctrl-\
|
44
|
+
Signal.trap 'QUIT' do
|
45
|
+
puts " --- Running all tests ---\n\n"
|
46
|
+
run_all_tests
|
47
|
+
end
|
48
|
+
|
49
|
+
@interrupted = false
|
50
|
+
|
51
|
+
# Ctrl-C
|
52
|
+
Signal.trap 'INT' do
|
53
|
+
if @interrupted then
|
54
|
+
@wants_to_quit = true
|
55
|
+
abort("\n")
|
56
|
+
else
|
57
|
+
puts "Interrupt a second time to quit"
|
58
|
+
@interrupted = true
|
59
|
+
Kernel.sleep 1.5
|
60
|
+
# raise Interrupt, nil # let the run loop catch it
|
61
|
+
run_suite
|
62
|
+
end
|
63
|
+
end
|
data/test/teststrap.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'bacon'
|
11
|
+
|
12
|
+
require File.dirname(__FILE__) + '/../lib/pusher-client.rb'
|
13
|
+
|
14
|
+
TEST_APP_KEY = "TEST_APP_KEY"
|
15
|
+
|
16
|
+
module PusherClient
|
17
|
+
class TestLogger < Logger
|
18
|
+
attr_reader :test_messages
|
19
|
+
|
20
|
+
def initialize(logdev, shift_age = 0, shift_size = 1048576)
|
21
|
+
@test_messages = []
|
22
|
+
super
|
23
|
+
end
|
24
|
+
def test(msg)
|
25
|
+
@test_messages << msg
|
26
|
+
debug msg
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Socket
|
31
|
+
# Simulate a connection being established
|
32
|
+
def connect
|
33
|
+
@connection_thread = Thread.new do
|
34
|
+
@connection = TestConnection.new
|
35
|
+
@global_channel.dispatch('pusher:connection_established', {'socket_id' => '123abc'})
|
36
|
+
end
|
37
|
+
@connection_thread.run
|
38
|
+
sleep(1)
|
39
|
+
end
|
40
|
+
|
41
|
+
def simulate_received(event_name, event_data, channel_name)
|
42
|
+
send_local_event(event_name, event_data, channel_name)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class TestConnection
|
47
|
+
def send(payload)
|
48
|
+
PusherClient.logger.test("SEND: #{payload}")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
PusherClient.logger = TestLogger.new('test.log')
|
53
|
+
|
54
|
+
end
|
metadata
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pusher-client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Logan Koester
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-12-29 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
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ~>
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
- 12
|
30
|
+
- 10
|
31
|
+
version: 0.12.10
|
32
|
+
type: :runtime
|
33
|
+
prerelease: false
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: em-http-request
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ~>
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
segments:
|
43
|
+
- 0
|
44
|
+
- 2
|
45
|
+
- 15
|
46
|
+
version: 0.2.15
|
47
|
+
type: :runtime
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: *id002
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: bacon
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
segments:
|
58
|
+
- 0
|
59
|
+
version: "0"
|
60
|
+
type: :development
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: *id003
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: bundler
|
65
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ~>
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
segments:
|
71
|
+
- 1
|
72
|
+
- 0
|
73
|
+
- 0
|
74
|
+
version: 1.0.0
|
75
|
+
type: :development
|
76
|
+
prerelease: false
|
77
|
+
version_requirements: *id004
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: jeweler
|
80
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
segments:
|
86
|
+
- 1
|
87
|
+
- 5
|
88
|
+
- 2
|
89
|
+
version: 1.5.2
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: *id005
|
93
|
+
- !ruby/object:Gem::Dependency
|
94
|
+
name: rcov
|
95
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
segments:
|
101
|
+
- 0
|
102
|
+
version: "0"
|
103
|
+
type: :development
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: *id006
|
106
|
+
description: Ruby client for consuming WebSockets from http://pusherapp.com
|
107
|
+
email: logan@logankoester.com
|
108
|
+
executables: []
|
109
|
+
|
110
|
+
extensions: []
|
111
|
+
|
112
|
+
extra_rdoc_files:
|
113
|
+
- LICENSE.txt
|
114
|
+
- README.rdoc
|
115
|
+
files:
|
116
|
+
- .bundle/config
|
117
|
+
- .document
|
118
|
+
- Gemfile
|
119
|
+
- Gemfile.lock
|
120
|
+
- LICENSE.txt
|
121
|
+
- README.rdoc
|
122
|
+
- Rakefile
|
123
|
+
- VERSION
|
124
|
+
- lib/pusher-client.rb
|
125
|
+
- lib/pusher-client/channel.rb
|
126
|
+
- lib/pusher-client/channels.rb
|
127
|
+
- lib/pusher-client/socket.rb
|
128
|
+
- test/pusherclient_test.rb
|
129
|
+
- test/test.watchr
|
130
|
+
- test/teststrap.rb
|
131
|
+
has_rdoc: true
|
132
|
+
homepage: http://github.com/logankoester/pusher-client
|
133
|
+
licenses:
|
134
|
+
- MIT
|
135
|
+
post_install_message:
|
136
|
+
rdoc_options: []
|
137
|
+
|
138
|
+
require_paths:
|
139
|
+
- lib
|
140
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
141
|
+
none: false
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
hash: 2534504559447735007
|
146
|
+
segments:
|
147
|
+
- 0
|
148
|
+
version: "0"
|
149
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
150
|
+
none: false
|
151
|
+
requirements:
|
152
|
+
- - ">="
|
153
|
+
- !ruby/object:Gem::Version
|
154
|
+
segments:
|
155
|
+
- 0
|
156
|
+
version: "0"
|
157
|
+
requirements: []
|
158
|
+
|
159
|
+
rubyforge_project:
|
160
|
+
rubygems_version: 1.3.7
|
161
|
+
signing_key:
|
162
|
+
specification_version: 3
|
163
|
+
summary: Ruby client for consuming WebSockets from http://pusherapp.com
|
164
|
+
test_files:
|
165
|
+
- test/pusherclient_test.rb
|
166
|
+
- test/teststrap.rb
|