mirror of
https://github.com/faye/faye-websocket-ruby.git
synced 2025-11-01 13:59:13 +00:00
Sort our server/ruby compatibility. Now running on Puma, Thin, old and new Rainbows, and Goliath, on MRI/JRuby/RBX.
This commit is contained in:
+5
-1
@@ -1,4 +1,5 @@
|
||||
language: ruby
|
||||
|
||||
rvm:
|
||||
- 1.8.7
|
||||
- 1.9.2
|
||||
@@ -6,10 +7,13 @@ rvm:
|
||||
- 2.0.0
|
||||
- jruby-18mode
|
||||
- jruby-19mode
|
||||
- rbx-18mode
|
||||
- rbx-19mode
|
||||
|
||||
before_script:
|
||||
- git submodule update --init --recursive
|
||||
- bundle install
|
||||
- cd vendor/parser && rake compile
|
||||
|
||||
script: bundle exec rspec spec/
|
||||
script: bundle exec rspec -c spec/
|
||||
|
||||
|
||||
+46
-16
@@ -19,9 +19,12 @@ access via proxies than WebSockets.
|
||||
Currently, the following web servers are supported, and can be accessed directly
|
||||
or via HAProxy:
|
||||
|
||||
* {Thin}[http://code.macournoyer.com/thin/]
|
||||
* {Rainbows}[http://rainbows.rubyforge.org/] using EventMachine
|
||||
* {Goliath}[http://postrank-labs.github.com/goliath/]
|
||||
* {Puma}[http://puma.io/]
|
||||
* {Rainbows}[http://rainbows.rubyforge.org/] using EventMachine
|
||||
* {Thin}[http://code.macournoyer.com/thin/]
|
||||
|
||||
Any web server that supports the <tt>rack.hijack</tt> API should also work.
|
||||
|
||||
The server-side socket can process {draft-75}[http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75],
|
||||
{draft-76}[http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76],
|
||||
@@ -31,6 +34,11 @@ supports both +text+ and +binary+ messages, and transparently handles +ping+,
|
||||
+pong+, +close+ and fragmented messages.
|
||||
|
||||
|
||||
== Installation
|
||||
|
||||
$ gem install faye-websocket
|
||||
|
||||
|
||||
== Handling WebSocket connections in Rack
|
||||
|
||||
You can handle WebSockets on the server side by listening for requests using the
|
||||
@@ -65,10 +73,14 @@ and sending messages. For example this is how you'd implement an echo server:
|
||||
|
||||
This is a standard Rack app, so it can be run using a <tt>config.ru</tt> file.
|
||||
However, so that incoming requests can be properly prepared to process WebSocket
|
||||
connections, you need to tell <tt>Faye::WebSocket</tt> which adapter to load;
|
||||
this can be either +thin+, +rainbows+ or +goliath+. If one of these servers is
|
||||
already loaded before <tt>faye/websocket</tt> is loaded, it will load
|
||||
appropriate adapters automatically.
|
||||
connections, <tt>Faye::WebSocket</tt> needs to monkey-patch certain web
|
||||
servers. If you're using one of these servers, you need to load an adapter:
|
||||
|
||||
* Goliath
|
||||
* Rainbows! version < 4.5.0
|
||||
* Thin
|
||||
|
||||
You load the adapter like so, passing either +goliath+, +rainbows+ or +thin+.
|
||||
|
||||
# config.ru
|
||||
require './app'
|
||||
@@ -261,6 +273,8 @@ further in a block passed to +run+:
|
||||
require 'thin'
|
||||
require './app'
|
||||
|
||||
Faye::WebSocket.load_adapter('thin')
|
||||
|
||||
EM.run {
|
||||
thin = Rack::Handler.get('thin')
|
||||
|
||||
@@ -275,18 +289,19 @@ further in a block passed to +run+:
|
||||
}
|
||||
|
||||
|
||||
=== Running the app with Puma
|
||||
|
||||
Puma has a command line interface for starting your application:
|
||||
|
||||
puma config.ru -p 9292
|
||||
|
||||
You do not need to call <tt>Faye::WebSocket.load_adapter</tt> to work with Puma
|
||||
but you must use at least version 2.0.0 of the +puma+ gem.
|
||||
|
||||
|
||||
=== Running the app with Rainbows
|
||||
|
||||
<tt>Faye::WebSocket</tt> can only be run using EventMachine. To begin with,
|
||||
you'll need a Rainbows config file that tells it to use EventMachine, along with
|
||||
whatever Rainbows/Unicorn configuration you require.
|
||||
|
||||
# rainbows.conf
|
||||
Rainbows! do
|
||||
use :EventMachine
|
||||
end
|
||||
|
||||
You can then run your <tt>config.ru</tt> file from the command line. Again,
|
||||
You can run your <tt>config.ru</tt> file from the command line. Again,
|
||||
<tt>Rack::Lint</tt> will complain unless you put the application in production
|
||||
mode.
|
||||
|
||||
@@ -308,6 +323,19 @@ Rainbows also has a Ruby API for starting a server:
|
||||
# This is non-blocking; use server.start.join to block
|
||||
server.start
|
||||
|
||||
If you're using version 4.4 or lower of Rainbows, you need to run it with the
|
||||
EventMachine backend and enable the adapter. Put this in your
|
||||
<tt>rainbows.conf</tt> file:
|
||||
|
||||
# rainbows.conf
|
||||
Rainbows! do
|
||||
use :EventMachine
|
||||
end
|
||||
|
||||
And make sure you load the adapter in your application:
|
||||
|
||||
Faye::WebSocket.load_adapter('rainbows')
|
||||
|
||||
|
||||
=== Running the app with Goliath
|
||||
|
||||
@@ -316,6 +344,7 @@ Goliath can be made to run arbitrary Rack apps by delegating to them from a
|
||||
|
||||
require 'goliath'
|
||||
require './app'
|
||||
Faye::WebSocket.load_adapter('goliath')
|
||||
|
||||
class EchoServer < Goliath::API
|
||||
def response(env)
|
||||
@@ -327,6 +356,7 @@ Goliath can be made to run arbitrary Rack apps by delegating to them from a
|
||||
|
||||
require 'goliath'
|
||||
require 'faye/websocket'
|
||||
Faye::WebSocket.load_adapter('goliath')
|
||||
|
||||
class EchoServer < Goliath::API
|
||||
def response(env)
|
||||
|
||||
+4
-8
@@ -1,17 +1,13 @@
|
||||
# Run using your favourite server:
|
||||
#
|
||||
# thin start -R examples/config.ru -p 7000
|
||||
# rainbows -E production examples/config.ru -p 7000
|
||||
#
|
||||
# If you run using one of these commands, the webserver is loaded before this
|
||||
# file, so Faye::WebSocket can figure out which adapter to load. If instead you
|
||||
# run using `rackup`, you need the `load_adapter` line below.
|
||||
#
|
||||
# rackup -E production -s thin examples/config.ru -p 7000
|
||||
# rainbows -c examples/rainbows.conf -E production examples/config.ru -p 7000
|
||||
|
||||
require 'rubygems'
|
||||
require File.expand_path('../app', __FILE__)
|
||||
# Faye::WebSocket.load_adapter('thin')
|
||||
|
||||
Faye::WebSocket.load_adapter('thin')
|
||||
Faye::WebSocket.load_adapter('rainbows')
|
||||
|
||||
run App
|
||||
|
||||
|
||||
+2
-5
@@ -8,11 +8,7 @@ engine = ARGV[2] || 'thin'
|
||||
spec = File.expand_path('../../spec', __FILE__)
|
||||
|
||||
require File.expand_path('../app', __FILE__)
|
||||
if %w[goliath thin].include?(engine)
|
||||
Faye::WebSocket.load_adapter(engine)
|
||||
else
|
||||
require engine
|
||||
end
|
||||
Faye::WebSocket.load_adapter(engine)
|
||||
|
||||
case engine
|
||||
|
||||
@@ -36,6 +32,7 @@ when 'rainbows'
|
||||
rackup[:port] = port
|
||||
rackup[:set_listener] = true
|
||||
options = rackup[:options]
|
||||
options[:config_file] = File.expand_path('../rainbows.conf', __FILE__)
|
||||
Rainbows::HttpServer.new(App, options).start.join
|
||||
|
||||
when 'thin'
|
||||
|
||||
+20
-16
@@ -1,30 +1,34 @@
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "faye-websocket"
|
||||
s.version = "0.4.7"
|
||||
s.summary = "Standards-compliant WebSocket server and client"
|
||||
s.author = "James Coglan"
|
||||
s.email = "jcoglan@gmail.com"
|
||||
s.homepage = "http://github.com/faye/faye-websocket-ruby"
|
||||
s.name = 'faye-websocket'
|
||||
s.version = '0.4.7'
|
||||
s.summary = 'Standards-compliant WebSocket server and client'
|
||||
s.author = 'James Coglan'
|
||||
s.email = 'jcoglan@gmail.com'
|
||||
s.homepage = 'http://github.com/faye/faye-websocket-ruby'
|
||||
|
||||
s.extra_rdoc_files = %w[README.rdoc]
|
||||
s.rdoc_options = %w[--main README.rdoc]
|
||||
s.require_paths = %w[lib]
|
||||
|
||||
s.files = %w[README.rdoc CHANGELOG.txt] +
|
||||
Dir.glob("lib/**/*.rb") +
|
||||
Dir.glob("{examples,spec}/**/*")
|
||||
Dir.glob('lib/**/*.rb') +
|
||||
Dir.glob('{examples,spec}/**/*')
|
||||
|
||||
s.add_dependency "eventmachine", ">= 0.12.0"
|
||||
s.add_dependency "websocket-protocol"
|
||||
s.add_dependency 'eventmachine', '>= 0.12.0'
|
||||
s.add_dependency 'websocket-protocol'
|
||||
|
||||
s.add_development_dependency "progressbar"
|
||||
s.add_development_dependency "rack"
|
||||
s.add_development_dependency "rspec"
|
||||
s.add_development_dependency 'progressbar'
|
||||
s.add_development_dependency 'puma', '>= 2.0.0'
|
||||
s.add_development_dependency 'rack'
|
||||
s.add_development_dependency 'rspec'
|
||||
|
||||
unless RUBY_PLATFORM =~ /java/
|
||||
s.add_development_dependency "puma", ">= 2.0.0"
|
||||
s.add_development_dependency "rainbows", ">= 4.5.0"
|
||||
s.add_development_dependency "thin", ">= 1.2.0"
|
||||
s.add_development_dependency 'rainbows', '~> 4.4.0'
|
||||
s.add_development_dependency 'thin', '>= 1.2.0'
|
||||
end
|
||||
|
||||
unless (defined?(RUBY_ENGINE) and RUBY_ENGINE =~ /rbx/) or RUBY_VERSION < '1.9'
|
||||
s.add_development_dependency 'goliath'
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ module Faye
|
||||
@connection = socket_object.env['em.connection']
|
||||
@stream_send = socket_object.env['stream.send']
|
||||
|
||||
if socket_object.env['rack.hijack?']
|
||||
if socket_object.env['rack.hijack']
|
||||
socket_object.env['rack.hijack'].call
|
||||
@rack_hijack_io = socket_object.env['rack.hijack_io']
|
||||
EventMachine.attach(@rack_hijack_io, Reader) do |reader|
|
||||
|
||||
@@ -22,9 +22,10 @@ module Faye
|
||||
autoload :Client, root + '/client'
|
||||
|
||||
ADAPTERS = {
|
||||
'thin' => :Thin,
|
||||
'goliath' => :Goliath,
|
||||
'puma' => :Puma,
|
||||
'rainbows' => :Rainbows,
|
||||
'goliath' => :Goliath
|
||||
'thin' => :Thin
|
||||
}
|
||||
|
||||
def self.determine_url(env)
|
||||
@@ -41,7 +42,8 @@ module Faye
|
||||
def self.load_adapter(backend)
|
||||
const = Kernel.const_get(ADAPTERS[backend]) rescue nil
|
||||
require(backend) unless const
|
||||
require File.expand_path("../adapters/#{backend}", __FILE__)
|
||||
path = File.expand_path("../adapters/#{backend}.rb", __FILE__)
|
||||
require(path) if File.file?(path)
|
||||
end
|
||||
|
||||
def self.websocket?(env)
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
require "spec_helper"
|
||||
require "socket"
|
||||
|
||||
IS_JRUBY = (defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby')
|
||||
|
||||
WebSocketSteps = EM::RSpec.async_steps do
|
||||
def server(port, backend, secure, &callback)
|
||||
@server = EchoServer.new
|
||||
@@ -77,13 +79,13 @@ WebSocketSteps = EM::RSpec.async_steps do
|
||||
end
|
||||
|
||||
describe Faye::WebSocket::Client do
|
||||
next if WebSocket::Protocol.jruby?
|
||||
include WebSocketSteps
|
||||
|
||||
let(:port) { 4180 }
|
||||
|
||||
let(:protocols) { ["foo", "echo"] }
|
||||
let(:protocols) { ["foo", "echo"] }
|
||||
let(:plain_text_url) { "ws://0.0.0.0:#{port}/" }
|
||||
let(:wrong_url) { "ws://0.0.0.0:9999/" }
|
||||
let(:secure_url) { "wss://0.0.0.0:#{port}/" }
|
||||
|
||||
shared_examples_for "socket client" do
|
||||
@@ -134,7 +136,19 @@ describe Faye::WebSocket::Client do
|
||||
end
|
||||
end
|
||||
|
||||
describe "with a Puma server" do
|
||||
let(:socket_url) { plain_text_url }
|
||||
let(:blocked_url) { wrong_url }
|
||||
|
||||
before { server port, :puma, false }
|
||||
after { stop }
|
||||
|
||||
it_should_behave_like "socket client"
|
||||
end
|
||||
|
||||
describe "with a plain-text Thin server" do
|
||||
next if IS_JRUBY
|
||||
|
||||
let(:socket_url) { plain_text_url }
|
||||
let(:blocked_url) { secure_url }
|
||||
|
||||
@@ -145,7 +159,7 @@ describe Faye::WebSocket::Client do
|
||||
end
|
||||
|
||||
describe "with a secure Thin server" do
|
||||
next if WebSocket::Protocol.rbx?
|
||||
next if IS_JRUBY
|
||||
|
||||
let(:socket_url) { secure_url }
|
||||
let(:blocked_url) { plain_text_url }
|
||||
|
||||
+17
-10
@@ -4,11 +4,11 @@ require 'bundler/setup'
|
||||
require File.expand_path('../../lib/faye/websocket', __FILE__)
|
||||
require File.expand_path('../../vendor/em-rspec/lib/em-rspec', __FILE__)
|
||||
|
||||
require 'puma'
|
||||
|
||||
unless RUBY_PLATFORM =~ /java/
|
||||
Faye::WebSocket.load_adapter('thin')
|
||||
Thin::Logging.silent = true
|
||||
require 'rainbows'
|
||||
Unicorn::Configurator::DEFAULTS[:logger] = Logger.new(StringIO.new)
|
||||
end
|
||||
|
||||
class EchoServer
|
||||
@@ -20,15 +20,19 @@ class EchoServer
|
||||
socket.rack_response
|
||||
end
|
||||
|
||||
def log(*args)
|
||||
end
|
||||
|
||||
def listen(port, backend, ssl = false)
|
||||
case backend
|
||||
when :rainbows
|
||||
rackup = Unicorn::Configurator::RACKUP
|
||||
rackup[:port] = port
|
||||
rackup[:set_listener] = true
|
||||
options = rackup[:options]
|
||||
@server = Rainbows::HttpServer.new(self, options)
|
||||
@server.start
|
||||
when :puma
|
||||
events = Puma::Events.new(StringIO.new, StringIO.new)
|
||||
binder = Puma::Binder.new(events)
|
||||
binder.parse(["tcp://0.0.0.0:#{port}"], self)
|
||||
@server = Puma::Server.new(self, events)
|
||||
@server.binder = binder
|
||||
@server.run
|
||||
|
||||
when :thin
|
||||
Rack::Handler.get('thin').run(self, :Port => port) do |s|
|
||||
if ssl
|
||||
@@ -44,7 +48,10 @@ class EchoServer
|
||||
end
|
||||
|
||||
def stop
|
||||
@server.stop
|
||||
case @server
|
||||
when Puma::Server then @server.stop(true)
|
||||
else @server.stop
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Vendored
+1
-1
Submodule vendor/protocol updated: 86b3235e82...9a28b3f90d
Reference in New Issue
Block a user