Продолжу размышления по моей предыдущей заметке и попытаюсь что-нибудь написать.
Я посмотрел существующие Jabber-серверы и ни у одного не обнаружил поддержку вебсокетов. Думаю, это просто вопрос времени, когда разработчики допишут поддержку вебсокетов в свои jabber-серверы. Можно написать свой джаббер-сервер, если совсем делать нефиг, можно ждать, когда разработчики добавят поддержку вебсокетов. Но мы не будем их ждать и сделаем эту поддержку сами. Но как? Первое что приходит в голову - создать прокси-сервер, который будет уметь получать вебсокет-запросы и перенаправлять их jabber-серверу.
Для тестов я поставил jabber-сервер ejabberd на локальную машину, хотя можно было воспользоваться и многочисленными узлами, типа jabber.ru. Также я поставил клиент Psi и зарегистрировался при помощи него на локальном сервере.
Итак. Давайте для начала создадим html5 документ, который будет посылать запрос на наш jabber-прокси-сервер:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Jabber Websocket Proxy Test</title>
<script src="https://ajax.googleapis.com/ajax/libs/mootools/1.3.0/mootools-yui-compressed.js"></script>
</head>
<body>
<script>
var socket = new WebSocket('ws://localhost:6222/');
socket.onopen = function() {
var xml = "<?xml version='1.0' encoding='UTF-8'?>"
xml += "<stream:stream to='localhost' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' xml:lang='ru' version='1.0'>";
socket.send(xml);
socket.onmessage = function(e) {
var data = e.data
alert(data)
}
}
</script>
</body>
</html>
Как видно из примера, мы будем посылать кусок xml на сервер (начало xml-потока), что означает, что мы готовы авторизоваться на сервере. В ответ jabber-сервер должен нам вернуть некий ответ, в данном случае - список поддерживаемых механизмов аутентификации на сервере. Мы просто выведем полученный с сервера ответ при помощи js-функции alert() на экран. Этого нам будет достаточно,чтобы убедиться, что наш прокси работает.
Теперь приведу код jabber-via-websocket сервера на Ruby:
require 'em-websocket'
options = {
:port => 6222,
:remote_host => 'localhost',
:remote_port => 5222
}
EventMachine.run {
class Server < EventMachine::Connection
def initialize(input, output, server_close, client_close)
@input = input
@output = output
@server_close = server_close
@client_close = client_close
@input_sid = @input.subscribe { |msg| send_data msg }
@client_close_sid = @client_close.subscribe { |msg| close_connection }
end
def receive_data(data)
@output.push(data)
end
def unbind
@input.unsubscribe(@input_sid)
@client_close.unsubscribe(@client_close_sid)
end
end
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => options[:port]) do |ws|
ws.onopen {
output = EM::Channel.new
input = EM::Channel.new
server_close = EM::Channel.new
client_close = EM::Channel.new
output_sid = output.subscribe { |msg| ws.send msg }
server_close_sid = server_close.subscribe { |msg| ws.close_connection }
EventMachine::connect options[:remote_host], options[:remote_port], Server, input, output, server_close, client_close
ws.onmessage { |msg| input.push(msg)}
ws.onclose {
output.unsubscribe(output_sid)
server_close.unsubscribe(server_close_sid)
}
}
end
}
Не буду подробно описывать код. Скажу лишь, что он перенаправляет все поступившие запросы с 6222 порта на порт 5222 (стандартный порт jabber).
Остается запустить из консоли наш прокси-сервер (ruby proxy.rb) и html5 пример в google chrome и убедиться, что все работает. Мы должны увидеть алерт со следующим содержимым:
<?xml version='1.0'?>
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='749528783' from='localhost' version='1.0' xml:lang='en'>
<stream:features>
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
<mechanism>PLAIN</mechanism>
<mechanism>DIGEST-MD5</mechanism>
</mechanisms>
<c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='http://www.process-one.net/en/ejabberd/' ver='8P/XuMtKq0lNk50DLBC8v+TXoAU='/>
<register xmlns='http://jabber.org/features/iq-register'/>
</stream:features>
Это был первый шаг в сторону создания инструмента, позволяющего общаться через jabber прямо с веб-страницы. Продолжение следует.