2012-05-05 3 views
3

Я пытаюсь использовать тот же порт для обслуживания обычного HTTP-трафика, а также websocket HTML5 через Cramp (который построен поверх EventMachine), используя Ruby 1.9.3 и Thin 1.3.1. Вот минимальный, самодостаточный пример:Как обслуживать Cramp :: Websocket и обычное приложение Rack на одном и том же порту?

require 'thin' 
require 'cramp' 
require 'http_router' 

Cramp::Websocket.backend = :thin 

class SocketApp < Cramp::Action 
    self.transport = :websocket 

    on_start = :connected 
    on_finish = :disconnected 
    on_data = :message 

    def connected 
    puts 'Client connected' 
    end 
    def disconnected 
    puts 'Client disconnected' 
    end 
    def message(msg) 
    puts "Got message: #{msg}" 
    render 'Here is your reply' 
    end 
end 

class WebApp 
    def call(env) 
    [ 200, { 'Content-Type' => 'text/html' }, <<EOF 
<html><head> 
<script> 
    function init() { 
    function log(msg) { document.getElementById('log').innerHTML += msg + '<br>'; } 
    var socketUri = 'ws://' + document.location.host + '/socket'; 
    log('Socket URI: ' + socketUri); 
    var socket = new WebSocket(socketUri); 
    socket.onopen = function(e) { 
     log('onopen'); 
     socket.send('Is there anybody out there?'); 
     log('sent message'); 
    }; 
    socket.onclose = function(e) { 
     log('onclose; code = ' + e.code + ', reason = ' + e.reason); 
    }; 
    socket.onerror = function(e) { 
     log('onerror'); 
    }; 
    socket.onmessage = function(e) { 
     log('onmessage; data = ' + e.data); 
    }; 
    } 
</script> 
</head><body onload='init();'> 
    <h1>Serving Cramp::Websocket and normal Rack app on the same port</h1> 
    <p id='log'></p> 
</body></html> 
EOF 
    ] 
    end 
end 

app = HttpRouter.new do 
    add('/socket').to SocketApp 
    add('/').to WebApp.new 
end 

run app 

Если вы хотите попробовать это для себя, придерживайтесь этого кода в файл с именем config.ru и запустить thin start. Вам нужны драгоценные камни thin, cramp и http_router для установки.

Идея состоит в том, что код JavaScript делает соединение с WebSocket с ws://localhost:3000/socket, которое перекликается с сообщениями, отправленными на него, но это не работает должным образом. Событие open срабатывает, при отправке сообщения нет ошибки, но мы не получаем ответа.

С точки зрения сервера, соединение не было выполнено, поскольку сообщение Client connected не печатается.

Использование thin start -D, я вижу, что HTTP 101 происходит, и некоторые двоичные данные обмениваются.

Что я делаю неправильно?

Update: Если я разбить файл на две части, выдирать HttpRouter, и запустить два thin экземпляров на разных портах, она по-прежнему не работает. Поэтому проблема заключается в коде сокета, а не в HttpRouter или WebApp.

ответ

3

Ну, это обман, но я, наконец, решил его, переключившись на другую библиотеку: websocket-rack. Для любопытных исправлен код:

require 'thin' 
require 'http_router' 
require 'rack/websocket' 

class SocketApp < Rack::WebSocket::Application 
    def on_open(env) 
    puts 'Client connected' 
    end 
    def on_close(env) 
    puts 'Client disconnected' 
    end 
    def on_message(env, message) 
    puts "Got message: #{message}" 
    send_data 'Here is your reply' 
    end 
end 

class WebApp 
    def call(env) 
    [200, { 'Content-Type' => 'text/html' }, <<EOF 
<html><head> 
<script> 
    function init() { 
    function log(msg) { document.getElementById('log').innerHTML += msg + '<br>'; } 
    var socketUri = 'ws://' + document.location.host + '/socket'; 
    log('Socket URI: ' + socketUri); 
    var socket = new WebSocket(socketUri); 
    socket.onopen = function(e) { 
     log('onopen'); 
     socket.send('Is there anybody out there?'); 
     log('sent message'); 
    }; 
    socket.onclose = function(e) { 
     log('onclose; code = ' + e.code + ', reason = ' + e.reason); 
    }; 
    socket.onerror = function(e) { 
     log('onerror'); 
    }; 
    socket.onmessage = function(e) { 
     log('onmessage; data = ' + e.data); 
    }; 
    } 
</script> 
</head><body onload='init();'> 
    <h1>Serving WebSocket and normal Rack app on the same port</h1> 
    <p id='log'></p> 
</body></html> 
EOF 
    ] 
    end 
end 

app = HttpRouter.new do 
    add('/socket').to(SocketApp.new) 
    add('/').to(WebApp.new) 
end 

run app 
Смежные вопросы