websocket-eventmachine-base 1.0.0

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.
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: []