Skip to content
This repository has been archived by the owner on Feb 12, 2018. It is now read-only.

Commit

Permalink
Reorganized the new XMPP code into a packet file, a basic connection …
Browse files Browse the repository at this point in the history
…class/file that handles XML, and a component class/file that handles authing. I think. The main file still handles Disco and is now about 30 lines. I really have to do something about config thuogh, possibly just passing the parsed config hash into Component instead of all the values individually.
  • Loading branch information
danopia committed Nov 26, 2009
1 parent 3b4a0be commit f409e17
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 69 deletions.
57 changes: 57 additions & 0 deletions lib/xmpp/component.rb
@@ -0,0 +1,57 @@

module Sails
module XMPP
class Component < Connection
attr_accessor :subdomain, :jid, :domain, :secret

def initialize subdomain, domain, secret
super()

@subdomain = subdomain
@domain = domain
@jid = "#{@subdomain}.#{@domain}"
@me = @jid
@secret = secret

start_auth
rescue => e
p e
puts e.message, e.backtrace
end

def receive_object packet, node
case packet.name

when 'stream:error'
error = node.children.first.name rescue nil
message = case error
when 'conflict': 'The XMPP server denied this component because it conflicts with one that is already connected.'
when nil: 'Unable to connect to XMPP. The server denied the component for an unknown reason.'
else; "Unable to connect to XMPP: #{error}"
end
raise Sails::ProviderError, message

when 'stream:stream'
id = packet.id

puts "Stream opened, sending challenge response"

key = Digest::SHA1.hexdigest(id + @secret)
send_raw "<handshake>#{key}</handshake>"

when 'handshake'
puts "Server accepted component; we are now live"
#TODO: flush queues

else
@@handler.call packet, node
end
end

def start_auth
send_raw "<stream:stream xmlns=\"jabber:component:accept\" xmlns:stream=\"http://etherx.jabber.org/streams\" to=\"#{@jid}\">"
end

end
end
end
75 changes: 75 additions & 0 deletions lib/xmpp/connection.rb
@@ -0,0 +1,75 @@
require 'rubygems'
require 'eventmachine'
require 'socket'
require 'hpricot'

module Sails
module XMPP
class Connection < EventMachine::Connection
def self.connect host, port, *args
EventMachine::connect host, port, self, *args
end
def self.start_loop *args
EventMachine::run { self.connect *args }
end

def self.on_packet &blck
@@handler = blck
end

def self.send *args
@@instance.send *args
end
def send name, type, to, data, id=nil
send_raw "<#{name} type=\"#{type}\" id=\"#{id}\" to=\"#{to}\" from=\"#{@me}\">#{data}</#{name}>"
end

def self.send_raw data
@@instance.send_raw data
end
def send_raw data
data = data.to_s
puts ">> #{data}"
send_data "#{data}\n"
end

def initialize
super
begin
@port, @ip = Socket.unpack_sockaddr_in get_peername
puts "Connected to XMPP at #{@ip}:#{@port}"
rescue TypeError
puts "Unable to determine endpoint (connection refused?)"
end

@buffer = ''
@@instance = self
end

def receive_data data
puts "<< #{data}"
if @@handler
doc = Hpricot "<root>#{data}</root>"
doc.root.children.each do |node|
unless node.is_a? Hpricot::XMLDecl
packet = Packet.new self, node
receive_object packet, node
end
end
end
end

def receive_object packet, node
@@handler.call packet, node
end

def unbind
puts "Disconnected from XMPP, reconnecting in 5 seconds"

EventMachine::add_timer 5 do
EventMachine.next_tick { self.class.connect @ip, @port }
end
end
end
end
end
23 changes: 23 additions & 0 deletions lib/xmpp/packet.rb
@@ -0,0 +1,23 @@

module Sails
module XMPP
class Packet
attr_accessor :connection, :name, :type, :to, :from, :id, :node

def initialize connection, xml
@connection = connection
@node = xml

@name = xml.name
@type = xml['type'] || 'default'
@to = xml['to']
@from = xml['from']
@id = xml['id']
end

def respond data
@connection.send @name, 'result', @from, data, @id
end
end
end
end
79 changes: 10 additions & 69 deletions new_xmpp_component.rb
@@ -1,5 +1,7 @@
require 'sails'
require 'lib/xmpp_connection'
require 'lib/xmpp/packet'
require 'lib/xmpp/connection'
require 'lib/xmpp/component'
require 'yaml'

puts "Loading config"
Expand All @@ -9,80 +11,19 @@
raise Sails::ProviderError, 'Could not read the sails.conf file. Make sure it exists and is proper YAML.'
end

class Packet
attr_accessor :name, :type, :to, :from, :id, :node

def self.send_raw data
Sails::XMPPConnection.send data
end

def self.send name, type, to, data, id=nil
send_raw "<#{name} type=\"#{type}\" id=\"#{id}\" to=\"#{to}\" from=\"#{$name}\">#{data}</#{name}>"
end

def initialize xml
@node = xml

@name = xml.name
@type = xml['type'] || 'default'
@to = xml['to']
@from = xml['from']
@id = xml['id']
end

def respond data
Packet.send @name, 'result', @from, data, @id
end
end

def got_packet xml
packet = Packet.new xml
Sails::XMPP::Component.on_packet do |packet, xml|
case [packet.name, packet.type]

when ['iq', 'get']
if (xml/'query').first.name == 'query'
handle_disco packet, (xml/'query').first['xmlns'].split('#').last
if (xml/'query').first['xmlns'].include? 'items'
packet.respond "<query xmlns=\"http://jabber.org/protocol/disco#items\"><item jid=\"#{packet.connection.jid}\" name=\"#{$config['identity']}\"/></query>"
else
packet.respond "<query xmlns=\"http://jabber.org/protocol/disco#info\"><identity category=\"collaboration\" type=\"ruby-on-sails\" name=\"#{$config['identity']}\"/><feature var=\"http://waveprotocol.org/protocol/0.2/waveserver\"/></query>"
end
end
end
end

def handle_disco packet, type
if type == 'items'
packet.respond "<query xmlns=\"http://jabber.org/protocol/disco#items\"><item jid=\"#{$name}\" name=\"#{$config['identity']}\"/></query>"
else
packet.respond "<query xmlns=\"http://jabber.org/protocol/disco#info\"><identity category=\"collaboration\" type=\"ruby-on-sails\" name=\"#{$config['identity']}\"/><feature var=\"http://waveprotocol.org/protocol/0.2/waveserver\"/></query>"
end
end

Sails::XMPPConnection.on_packet do |xml|
case xml.name

when 'stream:error'
error = xml.children.first.name rescue nil
message = case error
when 'conflict': 'The XMPP server denied this component because it conflicts with one that is already connected.'
when nil: 'Unable to connect to XMPP. The server denied the component for an unknown reason.'
else; "Unable to connect to XMPP: #{error}"
end
raise Sails::ProviderError, message

when 'stream:stream'
id = xml['id']

puts "Stream opened, sending challenge response"

key = Digest::SHA1.hexdigest(id + $config['xmpp-password'])
Packet.send_raw "<handshake>#{key}</handshake>"

when 'handshake'
puts "Server accepted component; we are now live"
#TODO: flush queues

else
got_packet xml
end
end

$name = "#{$config['service-name']}.#{$config['domain-name']}"

Sails::XMPPConnection.start_loop $config['xmpp-connect-host'], $config['xmpp-connect-port'].to_i, $name
Sails::XMPP::Component.start_loop $config['xmpp-connect-host'], $config['xmpp-connect-port'].to_i, $config['service-name'], $config['domain-name'], $config['xmpp-password']

0 comments on commit f409e17

Please sign in to comment.