socket.io 0.0.1

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.
@@ -0,0 +1,11 @@
1
+ # .document is used by rdoc and yard to know how to generate documentation
2
+ # for example, it can be used to control how rdoc gets built when you do `gem install foo`
3
+
4
+ README.rdoc
5
+ lib/**/*.rb
6
+ bin/*
7
+
8
+ # Files below this - are treated as 'extra files', and aren't parsed for ruby code
9
+ -
10
+ features/**/*.feature
11
+ LICENSE
@@ -0,0 +1,40 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ # rcov generated
6
+ coverage
7
+
8
+ # rdoc generated
9
+ rdoc
10
+
11
+ # yard generated
12
+ doc
13
+ .yardoc
14
+
15
+ # Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
16
+ #
17
+ # * Create a file at ~/.gitignore
18
+ # * Include files you want ignored
19
+ # * Run: git config --global core.excludesfile ~/.gitignore
20
+ #
21
+ # After doing this, these files will be ignored in all your git projects,
22
+ # saving you from having to 'pollute' every project you touch with them
23
+ #
24
+ # Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
25
+ #
26
+ # For MacOS:
27
+ #
28
+ #.DS_Store
29
+ #
30
+ # For TextMate
31
+ #*.tmproj
32
+ #tmtags
33
+ #
34
+ # For emacs:
35
+ #*~
36
+ #\#*
37
+ #.\#*
38
+ #
39
+ # For vim:
40
+ #*.swp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in socket.io-ruby.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Derek Kastner
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.
@@ -0,0 +1,17 @@
1
+ = socket.io-ruby
2
+
3
+ Description goes here.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
13
+ * Send me a pull request. Bonus points for topic branches.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2011 Derek Kastner. See LICENSE for details.
@@ -0,0 +1,42 @@
1
+ require 'rubygems'
2
+
3
+ begin
4
+ require 'bundler'
5
+ rescue LoadError
6
+ $stderr.puts "You must install bundler - run `gem install bundler`"
7
+ end
8
+
9
+ begin
10
+ Bundler.setup
11
+ rescue Bundler::BundlerError => e
12
+ $stderr.puts e.message
13
+ $stderr.puts "Run `bundle install` to install missing gems"
14
+ exit e.status_code
15
+ end
16
+ require 'rake'
17
+
18
+ require 'bueller'
19
+ Bueller::Tasks.new
20
+
21
+ require 'rspec/core/rake_task'
22
+ RSpec::Core::RakeTask.new(:examples) do |examples|
23
+ examples.rspec_opts = '-Ispec'
24
+ end
25
+
26
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
27
+ spec.rspec_opts = '-Ispec'
28
+ spec.rcov = true
29
+ end
30
+
31
+ task :default => :examples
32
+
33
+ require 'rake/rdoctask'
34
+ Rake::RDocTask.new do |rdoc|
35
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
36
+
37
+ rdoc.main = 'README.rdoc'
38
+ rdoc.rdoc_dir = 'rdoc'
39
+ rdoc.title = "socket.io-ruby #{version}"
40
+ rdoc.rdoc_files.include('README*')
41
+ rdoc.rdoc_files.include('lib/**/*.rb')
42
+ end
@@ -0,0 +1,6 @@
1
+ require 'socket.io/packet'
2
+ require 'socket.io/websocket'
3
+
4
+ module SocketIo
5
+ end
6
+
@@ -0,0 +1,59 @@
1
+ require 'json'
2
+
3
+ module SocketIo
4
+ class Packet
5
+ attr_accessor :data, :id, :ack, :type_id, :endpoint
6
+
7
+ PACKET_REGEX = /([^:]+):([0-9]+)?(\+)?:([^:]+)?:?([\s\S]*)?/
8
+
9
+ PACKET_TYPES = [:disconnect, :connect, :heartbeat, :message, :json, :event, :ack, :error, :noop]
10
+ PACKET_TYPES.each do |type|
11
+ require "socket.io/packet/#{type}_packet"
12
+ end
13
+
14
+ def self.parse(string)
15
+ pieces = string.match(PACKET_REGEX);
16
+ return nil if pieces.nil?
17
+
18
+ type = PACKET_TYPES[pieces[1].to_i]
19
+ packet_class = self.const_get "#{type.capitalize}Packet"
20
+
21
+ packet = packet_class.new :id => pieces[2] || '',
22
+ :ack => pieces[3] ? 'data' : true,
23
+ :data => pieces[5] || '',
24
+ :endpoint => pieces[4] || ''
25
+
26
+ packet.parse_pieces pieces if packet.respond_to?(:parse_pieces)
27
+ packet
28
+ end
29
+
30
+ def self.parse_json(str)
31
+ JSON.parse str
32
+ rescue
33
+ false
34
+ end
35
+
36
+ def initialize(options = {})
37
+ options.each do |name, value|
38
+ self.send "#{name}=", value
39
+ end
40
+ end
41
+
42
+ def json
43
+ @json ||= self.class.parse_json(data)
44
+ end
45
+
46
+ def ackdata?
47
+ ack == 'data'
48
+ end
49
+
50
+ def to_s(payload = nil)
51
+ parts = []
52
+ parts << type_id
53
+ parts << (id || '') + (ack == 'data' ? '+' : '')
54
+ parts << endpoint
55
+ parts << payload if payload
56
+ parts.join ':'
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,28 @@
1
+ require 'json'
2
+
3
+ module SocketIo
4
+ class Packet
5
+ class AckPacket < Packet
6
+ attr_accessor :ack_id, :args
7
+
8
+ def parse_pieces(pieces)
9
+ if sub_pieces = data =~ /^([0-9]+)(\+)?(.*)/
10
+ self.ack_id = sub_pieces[1];
11
+ self.args = [];
12
+
13
+ if sub_pieces[3]
14
+ self.args = Packet.parse_json(sub_pieces[3]) || [];
15
+ end
16
+ end
17
+ end
18
+
19
+ def type_id; 6; end
20
+
21
+ def to_s
22
+ payload = ack_id.to_s
23
+ payload += '+' + args.to_json if args
24
+ super payload
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,15 @@
1
+ module SocketIo
2
+ class Packet
3
+ class ConnectPacket < Packet
4
+ def qs
5
+ data
6
+ end
7
+
8
+ def type_id; 1; end
9
+
10
+ def to_s
11
+ super(qs)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,7 @@
1
+ module SocketIo
2
+ class Packet
3
+ class DisconnectPacket < Packet
4
+ def type_id; 0; end
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,24 @@
1
+ module SocketIo
2
+ class Packet
3
+ class ErrorPacket < Packet
4
+ REASONS = ['transport not supported', 'client not handshaken', 'unauthorized']
5
+ ADVICE = %w{reconnect}
6
+
7
+ def from_pieces(pieces)
8
+ sub_pieces = data.split('+');
9
+ self.reason = REASONS[sub_pieces[0]] || '';
10
+ self.advice = ADVICE[sub_pieces[1]] || '';
11
+ end
12
+
13
+ def type_id; 7; end
14
+
15
+ def to_s
16
+ payload = nil
17
+ if reason != '' || advice != ''
18
+ payload = reason + (advice != '' ? ('+' + advice) : '')
19
+ end
20
+ super payload
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,27 @@
1
+ require 'json'
2
+
3
+ module SocketIo
4
+ class Packet
5
+ class EventPacket < Packet
6
+ def name
7
+ json['name']
8
+ end
9
+
10
+ def args
11
+ json['args'] || []
12
+ end
13
+
14
+ def type_id; 5; end
15
+
16
+ def to_s
17
+ ev = { 'name' => name }
18
+
19
+ if args && args.length
20
+ ev['args'] = args
21
+ end
22
+
23
+ super ev.to_json;
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,7 @@
1
+ module SocketIo
2
+ class Packet
3
+ class HeartbeatPacket < Packet
4
+ def type_id; 2; end
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ module SocketIo
2
+ class Packet
3
+ class JsonPacket < Packet
4
+ def type_id; 4; end
5
+
6
+ def to_s
7
+ super json
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module SocketIo
2
+ class Packet
3
+ class MessagePacket < Packet
4
+ def type_id; 3; end
5
+
6
+ def to_s
7
+ super json
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,7 @@
1
+ module SocketIo
2
+ class Packet
3
+ class NoopPacket < Packet
4
+ def type_id; 8; end
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module SocketIo
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,37 @@
1
+ require 'socket.io/websocket/carrier_wave'
2
+ require 'socket.io/websocket/receiver'
3
+ require 'socket.io/websocket/sender'
4
+
5
+ module SocketIo
6
+ module Websocket
7
+ include CarrierWave
8
+ include Receiver
9
+ include Sender
10
+
11
+ @@events = {}
12
+
13
+ def self.included(target)
14
+ target.transport = :websocket
15
+ target.on_start :init_session
16
+ target.on_data :handle_packet
17
+
18
+ target.extend ClassMethods
19
+
20
+ @@events[target] = {}
21
+ end
22
+
23
+ def events
24
+ @@events[self.class]
25
+ end
26
+
27
+ module ClassMethods
28
+ def events
29
+ Websocket.class_variable_get(:@@events)[self]
30
+ end
31
+
32
+ def on(event, method)
33
+ events[event.to_s] = method
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,28 @@
1
+ module SocketIo
2
+ module Websocket
3
+ module CarrierWave
4
+ @@cache = {}
5
+
6
+ def init_session
7
+ if session.nil?
8
+ send_connect
9
+ self.session = Time.now
10
+ end
11
+ end
12
+
13
+ def session_id
14
+ params[:session_id]
15
+ end
16
+
17
+ def session_key
18
+ 'sessions/' + session_id
19
+ end
20
+ def session
21
+ @@cache[session_key]
22
+ end
23
+ def session=(cid)
24
+ @@cache[session_key] = cid
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,48 @@
1
+ require 'socket.io/packet'
2
+
3
+ module SocketIo
4
+ module Websocket
5
+ module Receiver
6
+ def handle_packet(data)
7
+ packet = SocketIo::Packet.parse(data)
8
+
9
+ case packet.class.to_s
10
+ when 'SocketIo::Packet::DisconnectPacket' then
11
+ self.channel_id = nil
12
+ when 'SocketIo::Packet::HeartbeatPacket' then
13
+ self.channel_id = Time.now
14
+ when 'SocketIo::Packet::MessagePacket' then
15
+ handle_message(packet)
16
+ when 'SocketIo::Packet::JsonPacket' then
17
+ handle_json(packet)
18
+ when 'SocketIo::Packet::EventPacket' then
19
+ handle_event(packet)
20
+ when 'SocketIo::Packet::AckPacket' then
21
+ when 'SocketIo::Packet::ErrorPacket' then
22
+ when 'SocketIo::Packet::NoopPacket' then
23
+ end
24
+ end
25
+
26
+ def handle_message(packet)
27
+ ack_args = send events['message'], packet.data
28
+ ack packet, args: ack_args
29
+ end
30
+
31
+ def handle_json(packet)
32
+ ack_args = send events['message'], packet.json
33
+ ack packet, args: ack_args
34
+ end
35
+
36
+ def handle_event(packet)
37
+ json = packet.json
38
+ name = json['name']
39
+ ack_args = send events[name].to_s, *json['args']
40
+ ack packet, args: ack_args
41
+ end
42
+
43
+ def handle_error(packet)
44
+ puts "Error from client: #{packet.inspect}"
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,23 @@
1
+ require 'socket.io/packet'
2
+
3
+ module SocketIo
4
+ module Websocket
5
+ module Sender
6
+ Packet::PACKET_TYPES.each do |type|
7
+ define_method "send_#{type}" do |*args|
8
+ options = args[0] || {}
9
+ klass = Packet.const_get("#{type.capitalize}Packet")
10
+ packet = klass.new options
11
+ str = packet.to_s
12
+ render str
13
+ end
14
+ end
15
+
16
+ def ack(calling_packet, options = {})
17
+ ack_params = { ack_id: calling_packet.id }
18
+ ack_params[:args] = options[:args] if calling_packet.ackdata?
19
+ send_ack ack_params
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,35 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+ require 'socket.io/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'socket.io'
6
+ s.version = SocketIo::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.date = '2011-11-21'
9
+ s.authors = ['Derek Kastner']
10
+ s.email = 'dkastner@gmail.com'
11
+ s.homepage = 'http://github.com/dkastner/socket.io-ruby'
12
+ s.summary = %Q{A ruby implementation of a Socket.io-compliant websocket server}
13
+ s.description = %Q{A plugin for Cramp that enables websockets using the Socket.io protocol}
14
+ s.extra_rdoc_files = [
15
+ 'LICENSE',
16
+ 'README.markdown',
17
+ ]
18
+
19
+ s.required_rubygems_version = Gem::Requirement.new('>= 1.3.7')
20
+ s.rubygems_version = '1.3.7'
21
+ s.specification_version = 3
22
+
23
+ s.files = `git ls-files`.split("\n")
24
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
25
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
26
+ s.require_paths = ['lib']
27
+
28
+
29
+ s.add_dependency 'cramp', '~> 0.15.1'
30
+
31
+ s.add_development_dependency 'rspec'
32
+ s.add_development_dependency 'bundler'
33
+ s.add_development_dependency 'rake'
34
+ s.add_development_dependency 'rcov'
35
+ end
@@ -0,0 +1,8 @@
1
+ require 'bundler'
2
+ Bundler.setup
3
+
4
+ require 'socket.io'
5
+
6
+ # Requires supporting files with custom matchers and macros, etc,
7
+ # in ./support/ and its subdirectories.
8
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+ require 'socket.io/websocket'
3
+ require 'socket.io/websocket/receiver'
4
+ require 'json'
5
+
6
+ describe SocketIo::Websocket::Receiver do
7
+ class MyAction
8
+ def self.transport=(val); end
9
+ def self.on_start(val); end
10
+ def self.on_data(val); end
11
+ include SocketIo::Websocket
12
+
13
+ on :quux, :qat
14
+
15
+ def qat(one, two); end
16
+ end
17
+
18
+ let(:data) do
19
+ { 'name' => 'quux', 'args' => ['hi', 5] }.to_json
20
+ end
21
+
22
+ describe '#handle_packet' do
23
+ it 'handles an event packet' do
24
+ packet = SocketIo::Packet::EventPacket.new :data => data
25
+ SocketIo::Packet.stub!(:parse).and_return(packet)
26
+
27
+ action = MyAction.new
28
+ action.should_receive(:handle_event).with(packet)
29
+ action.handle_packet ''
30
+ end
31
+ end
32
+
33
+ describe '#handle_event' do
34
+ it 'fires the specified event callback' do
35
+ packet = SocketIo::Packet::EventPacket.new :data => data
36
+
37
+ action = MyAction.new
38
+ action.should_receive(:qat).with('hi',5).once
39
+ action.stub! :ack
40
+ action.handle_event packet
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+ require 'socket.io/websocket'
3
+
4
+ describe SocketIo::Websocket do
5
+ class SocketAction
6
+ def self.transport=(val); end
7
+ def self.on_start(val); end
8
+ def self.on_data(val); end
9
+ include SocketIo::Websocket
10
+ end
11
+
12
+ describe '.included' do
13
+ it 'initializes an `events` class variable' do
14
+ SocketAction.events.should == {}
15
+ end
16
+ end
17
+
18
+ describe '.on' do
19
+ it 'stores a callback for the specified event' do
20
+ SocketAction.on(:melody, :play_riff)
21
+ SocketAction.events['melody'].should == :play_riff
22
+ end
23
+ end
24
+ end
metadata ADDED
@@ -0,0 +1,130 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: socket.io
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Derek Kastner
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-11-21 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: cramp
16
+ requirement: &2165211900 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.15.1
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *2165211900
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ requirement: &2165211100 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *2165211100
36
+ - !ruby/object:Gem::Dependency
37
+ name: bundler
38
+ requirement: &2165210000 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *2165210000
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ requirement: &2165203780 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *2165203780
58
+ - !ruby/object:Gem::Dependency
59
+ name: rcov
60
+ requirement: &2165202980 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *2165202980
69
+ description: A plugin for Cramp that enables websockets using the Socket.io protocol
70
+ email: dkastner@gmail.com
71
+ executables: []
72
+ extensions: []
73
+ extra_rdoc_files:
74
+ - LICENSE
75
+ - README.markdown
76
+ files:
77
+ - .document
78
+ - .gitignore
79
+ - Gemfile
80
+ - LICENSE
81
+ - README.markdown
82
+ - Rakefile
83
+ - lib/socket.io.rb
84
+ - lib/socket.io/packet.rb
85
+ - lib/socket.io/packet/ack_packet.rb
86
+ - lib/socket.io/packet/connect_packet.rb
87
+ - lib/socket.io/packet/disconnect_packet.rb
88
+ - lib/socket.io/packet/error_packet.rb
89
+ - lib/socket.io/packet/event_packet.rb
90
+ - lib/socket.io/packet/heartbeat_packet.rb
91
+ - lib/socket.io/packet/json_packet.rb
92
+ - lib/socket.io/packet/message_packet.rb
93
+ - lib/socket.io/packet/noop_packet.rb
94
+ - lib/socket.io/version.rb
95
+ - lib/socket.io/websocket.rb
96
+ - lib/socket.io/websocket/carrier_wave.rb
97
+ - lib/socket.io/websocket/receiver.rb
98
+ - lib/socket.io/websocket/sender.rb
99
+ - socket.io.gemspec
100
+ - spec/spec_helper.rb
101
+ - spec/websocket/receiver_spec.rb
102
+ - spec/websocket_spec.rb
103
+ homepage: http://github.com/dkastner/socket.io-ruby
104
+ licenses: []
105
+ post_install_message:
106
+ rdoc_options: []
107
+ require_paths:
108
+ - lib
109
+ required_ruby_version: !ruby/object:Gem::Requirement
110
+ none: false
111
+ requirements:
112
+ - - ! '>='
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ none: false
117
+ requirements:
118
+ - - ! '>='
119
+ - !ruby/object:Gem::Version
120
+ version: 1.3.7
121
+ requirements: []
122
+ rubyforge_project:
123
+ rubygems_version: 1.8.11
124
+ signing_key:
125
+ specification_version: 3
126
+ summary: A ruby implementation of a Socket.io-compliant websocket server
127
+ test_files:
128
+ - spec/spec_helper.rb
129
+ - spec/websocket/receiver_spec.rb
130
+ - spec/websocket_spec.rb