diff --git a/README.md b/README.md index 8933161a..d8d37896 100644 --- a/README.md +++ b/README.md @@ -100,9 +100,10 @@ frame.next # "Hello" frame.next # "world!"" ``` -## Examples +## Examples & Projects using WebSocket-Ruby -For examples on how to use WebSocket Ruby see examples directory in the repository. Provided examples are fully working servers - they are passing full autobahn compatibility suit. +- [WebSocket-EventMachine-Client](https://github.com/imanel/websocket-eventmachine-client) - client based on EventMachine +- [WebSocket-EventMachine-Server](https://github.com/imanel/websocket-eventmachine-server) - server based on EventMachine (drop-in replacement for EM-WebSocket) ## Native extension @@ -110,10 +111,6 @@ WebSocket gem is written in pure Ruby, without any dependencies or native extens In order to use native extension just install [websocket-native](http://github.com/imanel/websocket-ruby-native) gem or add it to Gemfile - WebSocket will automatically detect and load it. -## Examples & Projects using WebSocket-Ruby - -- [WebSocket-EventMachine-Server](https://github.com/imanel/websocket-eventmachine-server) - server based on EventMachine (drop-in replacement for EM-WebSocket) - ## License (The MIT License) diff --git a/autobahn-client.json b/autobahn-client.json deleted file mode 100644 index ec564f9a..00000000 --- a/autobahn-client.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "url": "ws://127.0.0.1:9001", - - "options": {"failByDrop": false}, - "outdir": "./autobahn/client", - "webport": 8080, - - "cases": ["1.1.1"], - "exclude-cases": [], - "exclude-agent-cases": {} -} diff --git a/autobahn-server.json b/autobahn-server.json deleted file mode 100644 index 3728107e..00000000 --- a/autobahn-server.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "options": {"failByDrop": false}, - "outdir": "./autobahn/server", - - "servers": [ - {"agent": "WebSocket-Ruby
(1.0.4 Pure)", "url": "ws://localhost:9001", "options": {"version": 18}}, - {"agent": "WebSocket-Ruby
(1.0.4 Native)", "url": "ws://localhost:9002", "options": {"version": 18}}, - {"agent": "Faye-WebSocket
(0.4.6 Thin)", "url": "ws://localhost:7000", "options": {"version": 18}}, - {"agent": "EM-WebSocket
(0.3.8)", "url": "ws://localhost:8080", "options": {"version": 18}} - ], - - "cases": ["*"], - "exclude-cases": [], - "exclude-agent-cases": {} -} diff --git a/examples/base.rb b/examples/base.rb deleted file mode 100644 index c56efc6e..00000000 --- a/examples/base.rb +++ /dev/null @@ -1,162 +0,0 @@ -require 'rubygems' -require 'eventmachine' -require "#{File.expand_path(File.dirname(__FILE__))}/../lib/websocket" - -module WebSocket - module EventMachine - class Base < ::EventMachine::Connection - - ########### - ### API ### - ########### - - def onopen(&blk); @onopen = blk; end # Called when connection is opened - def onclose(&blk); @onclose = blk; end # Called when connection is closed - def onerror(&blk); @onerror = blk; end # Called when error occurs - def onmessage(&blk); @onmessage = blk; end # Called when message is received from server - def onping(&blk); @onping = blk; end # Called when ping message is received from server - def onpong(&blk); @onpong = blk; end # Called when pond message is received from server - - # Send data to client - # @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" - # @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 = outgoing_frame.new(:version => @handshake.version, :data => data, :type => type) - 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 - - # Close connection - # @return [Boolean] true if connection is closed immediately, false if waiting for server to close connection - def close - if @state == :open - @state = :closing - return false if send('', :type => :close) - else - send('', :type => :close) if @state == :closing - @state = :closed - end - close_connection_after_writing - true - end - - # Send ping message to client - # @return [Boolean] false if protocol version is not supporting ping requests - def ping(data = '') - send(data, :type => :ping) - end - - # Send pong message to client - # @return [Boolean] false if protocol version is not supporting pong requests - def pong(data = '') - send(data, :type => :pong) - end - - ############################ - ### EventMachine methods ### - ############################ - - 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 - - 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 = incoming_frame.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) - puts(description + data.bytes.to_a.collect{|b| '\x' + b.to_s(16).rjust(2, '0')}.join) unless @state == :connecting - end - - end - end -end diff --git a/examples/client.rb b/examples/client.rb deleted file mode 100644 index acf6d983..00000000 --- a/examples/client.rb +++ /dev/null @@ -1,70 +0,0 @@ -require "#{File.expand_path(File.dirname(__FILE__))}/base" -require 'uri' - -# Example WebSocket Client (using EventMachine) -# @example -# ws = WebSocket::EventMachine::Client.connect(:host => "0.0.0.0", :port => 8080) -# ws.onmessage { |msg| ws.send "Pong: #{msg}" } -# ws.send "data" -module WebSocket - module EventMachine - class Client < Base - - # Connect to websocket server - # @param args [Hash] The request arguments - # @option args [String] :host The host IP/DNS name - # @option args [Integer] :port The port to connect too(default = 80) - # @option args [Integer] :version Version of protocol to use(default = 13) - def self.connect(args = {}) - host = nil - port = nil - if args[:uri] - uri = URI.parse(args[:uri]) - host = uri.host - port = uri.port - end - host = args[:host] if args[:host] - port = args[:port] if args[:port] - port ||= 80 - - ::EventMachine.connect host, port, self, args - end - - # Initialize connection - # @param args [Hash] Arguments for connection - # @option args [String] :host The host IP/DNS name - # @option args [Integer] :port The port to connect too(default = 80) - # @option args [Integer] :version Version of protocol to use(default = 13) - def initialize(args) - @args = args - end - - ############################ - ### EventMachine methods ### - ############################ - - # Called after initialize of connection, but before connecting to server - def post_init - @state = :connecting - @handshake = WebSocket::Handshake::Client.new(@args) - end - - # Called by EventMachine after connecting. - # Sends handshake to server - def connection_completed - send(@handshake.to_s, :type => :plain) - end - - private - - def incoming_frame - WebSocket::Frame::Incoming::Client - end - - def outgoing_frame - WebSocket::Frame::Outgoing::Client - end - - end - end -end diff --git a/examples/server.rb b/examples/server.rb deleted file mode 100644 index 871fca0c..00000000 --- a/examples/server.rb +++ /dev/null @@ -1,56 +0,0 @@ -require "#{File.expand_path(File.dirname(__FILE__))}/base" - -# Example WebSocket Server (using EventMachine) -# @example -# WebSocket::EventMachine::Server.start(:host => "0.0.0.0", :port => 8080) do |ws| -# 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 -module WebSocket - module EventMachine - class Server < Base - - # Start server - # @param options [Hash] The request arguments - # @option args [String] :host The host IP/DNS name - # @option args [Integer] :port The port to connect too(default = 80) - def self.start(options, &block) - ::EventMachine::start_server(options[:host], options[:port], self, options) do |c| - block.call(c) - end - end - - # Initialize connection - # @param args [Hash] Arguments for server - # @option args [Boolean] :secure If true then server will run over SSL - # @option args [Hash] :tls_options Options for SSL if secure = true - def initialize(args) - @secure = args[:secure] || false - @tls_options = args[:tls_options] || {} - end - - ############################ - ### Eventmachine methods ### - ############################ - - def post_init - @state = :connecting - @handshake = WebSocket::Handshake::Server.new(:secure => @secure) - start_tls(@tls_options) if @secure - end - - private - - def incoming_frame - WebSocket::Frame::Incoming::Server - end - - def outgoing_frame - WebSocket::Frame::Outgoing::Server - end - - end - end -end diff --git a/examples/tests/autobahn_client.rb b/examples/tests/autobahn_client.rb deleted file mode 100644 index 062bc189..00000000 --- a/examples/tests/autobahn_client.rb +++ /dev/null @@ -1,52 +0,0 @@ -require "#{File.expand_path(File.dirname(__FILE__))}/../client" -require 'cgi' - -EM.epoll -EM.run do - - host = 'ws://localhost:9001' - agent = "WebSocket-Ruby (Ruby #{RUBY_VERSION})" - cases = 0 - skip = [] - - ws = WebSocket::EventMachine::Client.connect(:uri => "#{host}/getCaseCount") - - ws.onmessage do |msg, type| - puts "$ Total cases to run: #{msg}" - cases = msg.to_i - end - - ws.onclose do - - run_case = lambda do |n| - - if n > cases - puts "$ Requesting report" - ws = WebSocket::EventMachine::Client.connect(:uri => "#{host}/updateReports?agent=#{CGI.escape agent}") - ws.onclose do - EM.stop - end - - elsif skip.include?(n) - EM.next_tick { run_case.call(n+1) } - - else - puts "$ Test number #{n}" - ws = WebSocket::EventMachine::Client.connect(:uri => "#{host}/runCase?case=#{n}&agent=#{CGI.escape agent}") - - ws.onmessage do |msg, type| - puts "Received #{msg}(#{type})" - ws.send(msg, :type => type) - end - - ws.onclose do |msg| - puts("Closing: #{msg}") if msg - run_case.call(n + 1) - end - end - end - - run_case.call(1) - end - -end diff --git a/examples/tests/autobahn_server.rb b/examples/tests/autobahn_server.rb deleted file mode 100644 index 57e74378..00000000 --- a/examples/tests/autobahn_server.rb +++ /dev/null @@ -1,24 +0,0 @@ -require "#{File.expand_path(File.dirname(__FILE__))}/../server" - -EM.epoll -EM.run do - - trap("TERM") { stop } - trap("INT") { stop } - - WebSocket::EventMachine::Server.start(:host => "0.0.0.0", :port => 9001) do |ws| - - ws.onmessage do |msg, type| - ws.send msg, :type => type - end - - end - - puts "Server started at port 9001" - - def stop - puts "Terminating WebSocket Server" - EventMachine.stop - end - -end diff --git a/examples/tests/echo_client.rb b/examples/tests/echo_client.rb deleted file mode 100644 index 7df30164..00000000 --- a/examples/tests/echo_client.rb +++ /dev/null @@ -1,42 +0,0 @@ -require "#{File.expand_path(File.dirname(__FILE__))}/../client" - -EM.epoll -EM.run do - - trap("TERM") { stop } - trap("INT") { stop } - - ws = WebSocket::EventMachine::Client.connect(:host => "localhost", :port => 9001); - - ws.onopen do - puts "Connected" - ws.send "Hello" - end - - ws.onmessage do |msg, type| - puts "Received message: #{msg}" - ws.send msg, :type => type - end - - ws.onclose do - puts "Disconnected" - end - - ws.onerror do |e| - puts "Error: #{e}" - end - - ws.onping do |msg| - puts "Receied ping: #{msg}" - end - - ws.onpong do |msg| - puts "Received pong: #{msg}" - end - - def stop - puts "Terminating connection" - EventMachine.stop - end - -end diff --git a/examples/tests/echo_server.rb b/examples/tests/echo_server.rb deleted file mode 100644 index 7a8a64ca..00000000 --- a/examples/tests/echo_server.rb +++ /dev/null @@ -1,45 +0,0 @@ -require "#{File.expand_path(File.dirname(__FILE__))}/../server" - -EM.epoll -EM.run do - - trap("TERM") { stop } - trap("INT") { stop } - - WebSocket::EventMachine::Server.start(:host => "0.0.0.0", :port => 9001) do |ws| - - ws.onopen do - puts "Client connected" - end - - ws.onmessage do |msg, type| - puts "Received message: #{msg}" - ws.send msg, :type => type - end - - ws.onclose do - puts "Client disconnected" - end - - ws.onerror do |e| - puts "Error: #{e}" - end - - ws.onping do |msg| - puts "Receied ping: #{msg}" - end - - ws.onpong do |msg| - puts "Received pong: #{msg}" - end - - end - - puts "Server started at port 9001" - - def stop - puts "Terminating WebSocket Server" - EventMachine.stop - end - -end