websocket-eventmachine-base 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ Gemfile.lock
2
+ pkg/*.gem
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0
4
+
5
+ - initial release
data/README.md ADDED
@@ -0,0 +1,11 @@
1
+ # WebSocket Base for Ruby client and server
2
+
3
+ WebSocket-EventMachine-Base is base gem for [WebSocket-EventMachine-Client](http://github.com/imanel/websocket-eventmachine-client) and [WebSocket-EventMachine-Server](http://github.com/imanel/websocket-eventmachine-server)
4
+
5
+ This gem should not be used directly - please refer to client or server gem for full specification.
6
+
7
+ - [Docs](http://rdoc.info/github/imanel/websocket-eventmachine-base/master/frames)
8
+
9
+ ## License
10
+
11
+ The MIT License - Copyright (c) 2012 Bernard Potocki
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,7 @@
1
+ module WebSocket
2
+ module EventMachine
3
+ class Base
4
+ VERSION = '1.0.0'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,191 @@
1
+ require 'websocket'
2
+ require 'eventmachine'
3
+
4
+ module WebSocket
5
+ module EventMachine
6
+
7
+ # WebSocket Base for Client and Server (using EventMachine)
8
+ class Base < ::EventMachine::Connection
9
+
10
+ ###########
11
+ ### API ###
12
+ ###########
13
+
14
+ # Called when connection is opened.
15
+ # No parameters are passed to block
16
+ def onopen(&blk); @onopen = blk; end
17
+
18
+ # Called when connection is closed.
19
+ # No parameters are passed to block
20
+ def onclose(&blk); @onclose = blk; end
21
+
22
+ # Called when error occurs.
23
+ # One parameter passed to block:
24
+ # error - string with error message
25
+ def onerror(&blk); @onerror = blk; end
26
+
27
+ # Called when message is received.
28
+ # Two parameters passed to block:
29
+ # message - string with received message
30
+ # type - type of message. Valid values are :text and :binary
31
+ def onmessage(&blk); @onmessage = blk; end
32
+
33
+ # Called when ping message is received
34
+ # One parameter passed to block:
35
+ # message - string with ping message
36
+ def onping(&blk); @onping = blk; end
37
+
38
+ # Called when pond message is received
39
+ # One parameter passed to block:
40
+ # message - string with pong message
41
+ def onpong(&blk); @onpong = blk; end
42
+
43
+ # Send data
44
+ # @param data [String] Data to send
45
+ # @param args [Hash] Arguments for send
46
+ # @option args [String] :type Type of frame to send - available types are "text", "binary", "ping", "pong" and "close"
47
+ # @option args [Integer] :code Code for close frame
48
+ # @return [Boolean] true if data was send, otherwise call on_error if needed
49
+ def send(data, args = {})
50
+ type = args[:type] || :text
51
+ unless type == :plain
52
+ frame = outgoing_frame.new(:version => @handshake.version, :data => data, :type => type.to_s, :code => args[:code])
53
+ if !frame.supported?
54
+ trigger_onerror("Frame type '#{type}' is not supported in protocol version #{@handshake.version}")
55
+ return false
56
+ elsif !frame.require_sending?
57
+ return false
58
+ end
59
+ data = frame.to_s
60
+ end
61
+ debug "Sending raw: ", data
62
+ send_data(data)
63
+ true
64
+ end
65
+
66
+ # Close connection
67
+ # @return [Boolean] true if connection is closed immediately, false if waiting for other side to close connection
68
+ def close(code = 1000, data = nil)
69
+ if @state == :open
70
+ @state = :closing
71
+ return false if send(data, :type => :close, :code => code)
72
+ else
73
+ send(data, :type => :close) if @state == :closing
74
+ @state = :closed
75
+ end
76
+ close_connection_after_writing
77
+ true
78
+ end
79
+
80
+ # Send ping message
81
+ # @return [Boolean] false if protocol version is not supporting ping requests
82
+ def ping(data = '')
83
+ send(data, :type => :ping)
84
+ end
85
+
86
+ # Send pong message
87
+ # @return [Boolean] false if protocol version is not supporting pong requests
88
+ def pong(data = '')
89
+ send(data, :type => :pong)
90
+ end
91
+
92
+ ############################
93
+ ### EventMachine methods ###
94
+ ############################
95
+
96
+ # Eventmachine internal
97
+ # @private
98
+ def receive_data(data)
99
+ debug "Received raw: ", data
100
+ case @state
101
+ when :connecting then handle_connecting(data)
102
+ when :open then handle_open(data)
103
+ when :closing then handle_closing(data)
104
+ end
105
+ end
106
+
107
+ # Eventmachine internal
108
+ # @private
109
+ def unbind
110
+ unless @state == :closed
111
+ @state = :closed
112
+ close
113
+ trigger_onclose('')
114
+ end
115
+ end
116
+
117
+ #######################
118
+ ### Private methods ###
119
+ #######################
120
+
121
+ private
122
+
123
+ ['onopen'].each do |m|
124
+ define_method "trigger_#{m}" do
125
+ callback = instance_variable_get("@#{m}")
126
+ callback.call if callback
127
+ end
128
+ end
129
+
130
+ ['onerror', 'onping', 'onpong', 'onclose'].each do |m|
131
+ define_method "trigger_#{m}" do |data|
132
+ callback = instance_variable_get("@#{m}")
133
+ callback.call(data) if callback
134
+ end
135
+ end
136
+
137
+ def trigger_onmessage(data, type)
138
+ @onmessage.call(data, type) if @onmessage
139
+ end
140
+
141
+ def handle_connecting(data)
142
+ @handshake << data
143
+ return unless @handshake.finished?
144
+ if @handshake.valid?
145
+ send(@handshake.to_s, :type => :plain) if @handshake.should_respond?
146
+ @frame = incoming_frame.new(:version => @handshake.version)
147
+ @state = :open
148
+ trigger_onopen
149
+ handle_open(@handshake.leftovers) if @handshake.leftovers
150
+ else
151
+ trigger_onerror(@handshake.error)
152
+ close
153
+ end
154
+ end
155
+
156
+ def handle_open(data)
157
+ @frame << data
158
+ while frame = @frame.next
159
+ case frame.type
160
+ when :close
161
+ @state = :closing
162
+ close
163
+ trigger_onclose(frame.to_s)
164
+ when :ping
165
+ pong(frame.to_s)
166
+ trigger_onping(frame.to_s)
167
+ when :pong
168
+ trigger_onpong(frame.to_s)
169
+ when :text
170
+ trigger_onmessage(frame.to_s, :text)
171
+ when :binary
172
+ trigger_onmessage(frame.to_s, :binary)
173
+ end
174
+ end
175
+ unbind if @frame.error?
176
+ end
177
+
178
+ def handle_closing(data)
179
+ @state = :closed
180
+ close
181
+ trigger_onclose
182
+ end
183
+
184
+ def debug(description, data)
185
+ return unless @debug
186
+ puts(description + data.bytes.to_a.collect{|b| '\x' + b.to_s(16).rjust(2, '0')}.join) unless @state == :connecting
187
+ end
188
+
189
+ end
190
+ end
191
+ end
@@ -0,0 +1 @@
1
+ require File.expand_path('../websocket/eventmachine/base', __FILE__)
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "websocket/eventmachine/base/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "websocket-eventmachine-base"
7
+ s.version = WebSocket::EventMachine::Base::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Bernard Potocki"]
10
+ s.email = ["bernard.potocki@imanel.org"]
11
+ s.homepage = "http://github.com/imanel/websocket-eventmachine-base"
12
+ s.summary = %q{WebSocket base for Ruby client and server}
13
+ s.description = %q{WebSocket base for Ruby client and server}
14
+
15
+ s.add_dependency 'websocket', '~> 1.0'
16
+ s.add_dependency 'websocket-native', '~> 1.0'
17
+ s.add_dependency 'eventmachine', '~> 1.0'
18
+
19
+ s.files = `git ls-files`.split("\n")
20
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
21
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
22
+ s.require_paths = ["lib"]
23
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: websocket-eventmachine-base
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Bernard Potocki
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-12-20 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: websocket
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: websocket-native
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '1.0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '1.0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: eventmachine
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '1.0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.0'
62
+ description: WebSocket base for Ruby client and server
63
+ email:
64
+ - bernard.potocki@imanel.org
65
+ executables: []
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - .gitignore
70
+ - CHANGELOG.md
71
+ - README.md
72
+ - Rakefile
73
+ - lib/websocket-eventmachine-base.rb
74
+ - lib/websocket/eventmachine/base.rb
75
+ - lib/websocket/eventmachine/base/version.rb
76
+ - websocket-eventmachine-base.gemspec
77
+ homepage: http://github.com/imanel/websocket-eventmachine-base
78
+ licenses: []
79
+ post_install_message:
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ! '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ requirements: []
96
+ rubyforge_project:
97
+ rubygems_version: 1.8.24
98
+ signing_key:
99
+ specification_version: 3
100
+ summary: WebSocket base for Ruby client and server
101
+ test_files: []