lib/websocket/eventmachine/server.rb in websocket-eventmachine-server-1.0.0 vs lib/websocket/eventmachine/server.rb in websocket-eventmachine-server-1.0.1
- old
+ new
@@ -1,7 +1,6 @@
-require 'websocket'
-require 'eventmachine'
+require 'websocket-eventmachine-base'
module WebSocket
module EventMachine
# WebSocket Server (using EventMachine)
@@ -10,11 +9,11 @@
# ws.onopen { ws.send "Hello Client!"}
# ws.onmessage { |msg| ws.send "Pong: #{msg}" }
# ws.onclose { puts "WebSocket closed" }
# ws.onerror { |e| puts "Error: #{e}" }
# end
- class Server < ::EventMachine::Connection
+ class Server < Base
###########
### API ###
###########
@@ -39,191 +38,89 @@
@secure = !!args[:secure]
@secure_proxy = args[:secure_proxy] || @secure
@tls_options = args[:tls_options] || {}
end
+ ############################
+ ### EventMachine methods ###
+ ############################
+
+ # Eventmachine internal
+ # @private
+ def post_init
+ @state = :connecting
+ @handshake = WebSocket::Handshake::Server.new(:secure => @secure_proxy)
+ start_tls(@tls_options) if @secure
+ end
+
+ #######################
+ ### Private methods ###
+ #######################
+
+ private
+
+ def incoming_frame
+ WebSocket::Frame::Incoming::Server
+ end
+
+ def outgoing_frame
+ WebSocket::Frame::Outgoing::Server
+ end
+
+ public
+
+ #########################
+ ### Inherited methods ###
+ #########################
+
# Called when connection is opened.
# No parameters are passed to block
- def onopen(&blk); @onopen = blk; end
+ def onopen(&blk); super; end
# Called when connection is closed.
# No parameters are passed to block
- def onclose(&blk); @onclose = blk; end
+ def onclose(&blk); super; end
# Called when error occurs.
# One parameter passed to block:
# error - string with error message
- def onerror(&blk); @onerror = blk; end
+ def onerror(&blk); super; end
- # Called when message is received from server.
+ # Called when message is received.
# Two parameters passed to block:
- # message - string with message sent to server
+ # message - string with received message
# type - type of message. Valid values are :text and :binary
- def onmessage(&blk); @onmessage = blk; end
+ def onmessage(&blk); super; end
- # Called when ping message is received from server.
+ # Called when ping message is received
# One parameter passed to block:
# message - string with ping message
- def onping(&blk); @onping = blk; end
+ def onping(&blk); super; end
- # Called when pond message is received from server.
+ # Called when pond message is received
# One parameter passed to block:
# message - string with pong message
- def onpong(&blk); @onpong = blk; end
+ def onpong(&blk); super; end
- # Send data to client
+ # Send data
# @param data [String] Data to send
# @param args [Hash] Arguments for send
# @option args [String] :type Type of frame to send - available types are "text", "binary", "ping", "pong" and "close"
# @option args [Integer] :code Code for close frame
# @return [Boolean] true if data was send, otherwise call on_error if needed
- def send(data, args = {})
- type = args[:type] || :text
- unless type == :plain
- frame = WebSocket::Frame::Outgoing::Server.new args.merge(:version => @handshake.version, :data => data)
- if !frame.supported?
- trigger_onerror("Frame type '#{type}' is not supported in protocol version #{@handshake.version}")
- return false
- elsif !frame.require_sending?
- return false
- end
- data = frame.to_s
- end
- debug "Sending raw: ", data
- send_data(data)
- true
- end
+ def send(data, args = {}); super; end
# Close connection
- # @return [Boolean] true if connection is closed immediately, false if waiting for server to close connection
- def close(code = 1000, data = nil)
- if @state == :open
- @state = :closing
- return false if send(data, :type => :close, :code => code)
- else
- send(data, :type => :close) if @state == :closing
- @state = :closed
- end
- close_connection_after_writing
- true
- end
+ # @return [Boolean] true if connection is closed immediately, false if waiting for other side to close connection
+ def close(code = 1000, data = nil); super; end
- # Send ping message to client
+ # Send ping message
# @return [Boolean] false if protocol version is not supporting ping requests
- def ping(data = '')
- send(data, :type => :ping)
- end
+ def ping(data = ''); super; end
- # Send pong message to client
+ # Send pong message
# @return [Boolean] false if protocol version is not supporting pong requests
- def pong(data = '')
- send(data, :type => :pong)
- end
-
- ############################
- ### EventMachine methods ###
- ############################
-
- # Eventmachine internal
- # @private
- def post_init
- @state = :connecting
- @handshake = WebSocket::Handshake::Server.new(:secure => @secure_proxy)
- start_tls(@tls_options) if @secure
- end
-
- # Eventmachine internal
- # @private
- def receive_data(data)
- debug "Received raw: ", data
- case @state
- when :connecting then handle_connecting(data)
- when :open then handle_open(data)
- when :closing then handle_closing(data)
- end
- end
-
- # Eventmachine internal
- # @private
- def unbind
- unless @state == :closed
- @state = :closed
- close
- trigger_onclose('')
- end
- end
-
- #######################
- ### Private methods ###
- #######################
-
- private
-
- ['onopen'].each do |m|
- define_method "trigger_#{m}" do
- callback = instance_variable_get("@#{m}")
- callback.call if callback
- end
- end
-
- ['onerror', 'onping', 'onpong', 'onclose'].each do |m|
- define_method "trigger_#{m}" do |data|
- callback = instance_variable_get("@#{m}")
- callback.call(data) if callback
- end
- end
-
- def trigger_onmessage(data, type)
- @onmessage.call(data, type) if @onmessage
- end
-
- def handle_connecting(data)
- @handshake << data
- return unless @handshake.finished?
- if @handshake.valid?
- send(@handshake.to_s, :type => :plain) if @handshake.should_respond?
- @frame = WebSocket::Frame::Incoming::Server.new(:version => @handshake.version)
- @state = :open
- trigger_onopen
- handle_open(@handshake.leftovers) if @handshake.leftovers
- else
- trigger_onerror(@handshake.error)
- close
- end
- end
-
- def handle_open(data)
- @frame << data
- while frame = @frame.next
- case frame.type
- when :close
- @state = :closing
- close
- trigger_onclose(frame.to_s)
- when :ping
- pong(frame.to_s)
- trigger_onping(frame.to_s)
- when :pong
- trigger_onpong(frame.to_s)
- when :text
- trigger_onmessage(frame.to_s, :text)
- when :binary
- trigger_onmessage(frame.to_s, :binary)
- end
- end
- unbind if @frame.error?
- end
-
- def handle_closing(data)
- @state = :closed
- close
- trigger_onclose
- end
-
- def debug(description, data)
- return unless @debug
- puts(description + data.bytes.to_a.collect{|b| '\x' + b.to_s(16).rjust(2, '0')}.join) unless @state == :connecting
- end
+ def pong(data = ''); super; end
end
end
end