criando um instant messenger
DESCRIPTION
Essa é a minha palestra no evento Ruby + Rails no mundo real, falando sobre a criação de um instant messenger em ruby e rails.TRANSCRIPT
Criando um Instant Messenger com Rails
Vinícius Baggio Fuentes
Agenda
• Experimentar: por que ruby e rails?
• Botando a mão na massa
• Trocando idéias com o GoogleTalk
• Juntando tudo: Rails
• Distributed Ruby (DRb)
• Perguntas
Experimentar: por que ruby e rails?
• Because we can!
• Rápidos resultados
• Criatividade e liberdade
Experimentar: por que ruby e rails?
• Because we can!
• Rápidos resultados
• Criatividade e liberdade
Botando a mão na massa (i)
• O que é XMPP/Jabber
Botando a mão na massa (i)
• O que é XMPP/Jabber
• Trocar XMLs via rede
Botando a mão na massa (i)
• O que é XMPP/Jabber
• Trocar XMLs via rede
• Autenticação e encriptação
Botando a mão na massa (i)
• O que é XMPP/Jabber
• Trocar XMLs via rede
• Autenticação e encriptação
• Descentralizado
Botando a mão na massa (i)
• O que é XMPP/Jabber
• Trocar XMLs via rede
• Autenticação e encriptação
• Descentralizado
• Extensível
Botando a mão na massa (ii)
• Usos do XMPP
Botando a mão na massa (ii)
• Usos do XMPP
• Conversar
Botando a mão na massa (ii)
• Usos do XMPP
• Conversar
• Web Services
Botando a mão na massa (ii)
• Usos do XMPP
• Conversar
• Web Services
• Robôs ajudantes
Botando a mão na massa (ii)
• Usos do XMPP
• Conversar
• Web Services
• Robôs ajudantes
• Manutenção e deploy
Botando a mão na massa (iii)
• XMPP
Botando a mão na massa (iii)
• XMPP
• JID
Botando a mão na massa (iii)
• XMPP
• JID
• Presence
Botando a mão na massa (iii)
• XMPP
• JID
• Presence
• Messages
Botando a mão na massa (iii)
• XMPP
• JID
• Presence
• Messages
JID’s:[email protected]/GTalk
[email protected]/Pidgin
Botando a mão na massa (iii)
• XMPP
• JID
• Presence
• Messages
Botando a mão na massa (iii)
• XMPP
• JID
• Presence
• Messages
<presence from='[email protected]' type='unavailable' to='[email protected]/chattyAB9DA217' xmlns='jabber:client'/>
Botando a mão na massa (iii)
• XMPP
• JID
• Presence
• Messages
Botando a mão na massa (iii)
• XMPP
• JID
• Presence
• Messages
<message type='chat' to='[email protected]' xmlns='jabber:client'>
<body>Nao fuja!</body></message>
Botando a mão na massa (iii)
• XMPP
• JID
• Presence
• Messages
Botando a mão na massa (iv)
• XMPP em Ruby:
Botando a mão na massa (iv)
• XMPP em Ruby:
• XMPP4R
Botando a mão na massa (iv)
• XMPP em Ruby:
• XMPP4R
• XMPP4R::Simple
Botando a mão na massa (iv)
• XMPP em Ruby:
• XMPP4R
• XMPP4R::Simple
• Net::XMPP
Trocando idéias com o GoogleTalk
Trocando idéias com o GoogleTalk
require ‘xmpp4r’
include JabberJabber::debug = true
jid = Jabber::JID.new ‘[email protected]/Chatty’password = ‘*******’
client = Jabber::Client.new jidclient.connect ‘talk.google.com’client.auth passwordclient.send Presence.new@clients[email] = client
Trocando idéias com o GoogleTalk
require ‘xmpp4r’
include JabberJabber::debug = true
jid = Jabber::JID.new ‘[email protected]/Chatty’password = ‘*******’
client = Jabber::Client.new jidclient.connect ‘talk.google.com’client.auth passwordclient.send Presence.new@clients[email] = client
Type: Status:nil (available) nil (available):error :away:probe :chat:subscribe :dnd:subscribed :xa:unavailable:unsubscribe:unsubscribed
Trocando idéias com o GoogleTalk
client.add_message_callback do |msg|unless msg.type == :error or msg.body.nil?
push_msg msgend
end
client.add_presence_callback do |presence|push_presence presence
end
Trocando idéias com o GoogleTalk
def push_msg(msg)from = msg.from.bare.to_sto = msg.to.bare.to_sbody = msg.body
new_msg = {:body => body, :from => from}@msg_stack[to].push new_msg
end
Trocando idéias com o GoogleTalkdef push_presence(presence)
from = presence.from.bare.to_sto = presence.to.bare.to_sif presence.type == :unavailable
status = :unavailableelse
status = presence.show || :availableendnew_presence = {:status => status, :from => from}@presence_stack[to].push new_presence
end
Trocando idéias com o GoogleTalk
client.close
Trocando idéias com o GoogleTalk
class XMPPConnectorinclude Singletondef login(email, password); ...; end;def get_presences(jid); ...; end;def get_messages(jid); ...; end;def send_message(jid, to, msg); ...; end;def set_status(jid, status); ...; end;def logout(jid); ...; end;privatedef check_timeout; ...; end;def push_msg(msg); ...; end;def push_presence(msg); ...; end;
end
Trocando idéias com o GoogleTalk
connector = XMPPConnector.instancejid = connector.login(‘[email protected]’, ‘*****’)msgs = connector.get_messages(jid)presences = connector.get_presences(jid)connector.send_message(jid, ‘[email protected]’, ‘Oi!’)connector.set.status(jid, :dnd);
Juntando tudo: Rails
Acabou a parte do XMPP!Vamos pro Rails!!
Juntando tudo: Railsrequire ‘xmppconnector’
class MessengerController < ApplicationControllerfilter_parameter_logging :passworddef login
email = params[:email]password = params[:password]xmpp = XMPPConnector.instancesession[:jid] = xmpp.login(email, password)render :action => ‘chat’
end...
end
check_updates
send_msg
vinibaggio
vinibaggio
****************
Pergunta fatídica...
Pergunta fatídica...
Does it scale?
Pergunta fatídica...
Does it scale?Nope.
mongrel simples
Request
dispatcherApp Rails
XMPP Layer
joao
maria
* vinibaggio
localhost:3000/login
MessengerController::login Messenger#login(vinibaggio)
OK:render => "chat"
localhost:3000/chat
Tipo de request: Login (Mongrel simples)
mod_rails (Passenger)
Request
dispatcher
Instância
Rails 1
XMPP Layer 1
joao
maria
localhost:3000/login
localhost:3000/chat
Tipo de request: Login (mod_rails)
Instância
Rails 2
Instância
Rails 5
XMPP Layer 5
pedro
paulo
XMPP Layer 2
vitor
* vinibaggio
Messenger#login(vinibaggio)MessengerController::login
OK:render => "chat"
mod_rails (Passenger)
Request
dispatcher
Instância
Rails 1
XMPP Layer 1
joao
maria
localhost:3000/send_msg
localhost:3000/timeout
Tipo de request: Send_msg (mod_rails)
Instância
Rails 2
Instância
Rails 5
XMPP Layer 5
pedro
paulo
XMPP Layer 2
vitor
vinibaggio
Messenger#send_msg(vinibaggio)MessengerController::send_msg
ERROR
flash[:error] = "Invalid connection"
Distributed Ruby!
• Remote Method Invocation (RMI)
• Standard library
• Access Control Lists (ACLs)
require ‘drb’DRb.start_service ‘druby://localhost:6666’, []DRb.thread.join
Servidor
require ‘drb’r = DRbObject.new nil, ‘druby://localhost:6666’while true
puts r.sizer << 1puts r.sizesleep 10
end
Cliente
Tempo
0s
5s
10s
15s
A
B
01
12
23
34
mod_rails
Request
dispatcher
Instância
Rails 1
RemoteXMPP
joao
maria
pedro
paulo
vitor
vinibaggio
Requests
Arquitetura com mod_rails + DRb
Instância
Rails 2
Instância
Rails 5
Response
require ‘drb’include ‘xmppconnector’DRb.start_service ‘druby://localhost:6666’,
XMPPConnector.instanceDRb.thread.join
Servidor XMPP + DRb
Rails + DRbrequire ‘xmppconnector’
class MessengerController < ApplicationControllerfilter_parameter_logging :passworddef login
...end
def xmppDRbObject.new nil, ‘druby://localhost:6666’
end...
end
That’s it!
• Relembrando...
• Biblioteca XMPP4R para XMPP
• Rails para fazer a interface
• Paralelizando a arquitetura
• Distributed Ruby (DRb)
Obrigado!!!
• Perguntas??
• Contato:
• www.vinibaggio.com