Class: Blather::Stream

Inherits:
EventMachine::Connection
  • Object
show all
Defined in:
lib/blather/stream/parser.rb,
lib/blather/stream.rb,
lib/blather/stream/client.rb,
lib/blather/stream/features.rb,
lib/blather/stream/component.rb,
lib/blather/stream/features/tls.rb,
lib/blather/stream/features/sasl.rb,
lib/blather/stream/features/session.rb,
lib/blather/stream/features/resource.rb

Overview

:nodoc:

Direct Known Subclasses

Client, Component

Defined Under Namespace

Classes: Client, Component, Features, NoConnection, Parser, Resource, SASL, Session, TLS

Constant Summary collapse

STREAM_NS =
'http://etherx.jabber.org/streams'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(client, jid, pass) ⇒ Stream

Called by EM.connect to initialize stream variables



60
61
62
63
64
65
66
67
68
69
# File 'lib/blather/stream.rb', line 60

def initialize(client, jid, pass) # :nodoc:
  super()

  @error = nil
  @receiver = @client = client

  self.jid = jid
  @to = self.jid.domain
  @password = pass
end

Instance Attribute Details

#jidObject

Returns the value of attribute jid.



8
9
10
# File 'lib/blather/stream.rb', line 8

def jid
  @jid
end

#passwordObject

Returns the value of attribute password.



7
8
9
# File 'lib/blather/stream.rb', line 7

def password
  @password
end

Class Method Details

.connect(host, port, conn, client, jid, pass) ⇒ Object

Attempt a connection Stream will raise NoConnection if it receives #unbind before #post_init this catches that and returns false prompting for another attempt



38
39
40
41
42
# File 'lib/blather/stream.rb', line 38

def self.connect(host, port, conn, client, jid, pass)
  EM.connect host, port, conn, client, jid, pass
rescue NoConnection
  false
end

.start(client, jid, pass, host = nil, port = 5222) ⇒ Object

Start the stream between client and server

[client] must be an object that will respond to #call and #jid=
[jid] must be a valid argument for JID.new (see JID)
[pass] must be the password
[host] (optional) must be the hostname or IP to connect to. defaults to the domain of [jid]
[port] (optional) must be the port to connect to. defaults to 5222


17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/blather/stream.rb', line 17

def self.start(client, jid, pass, host = nil, port = 5222)
  jid = JID.new jid
  if host
    connect host, port, self, client, jid, pass
  else
    require 'resolv'
    srv = []
    Resolv::DNS.open { |dns| srv = dns.getresources("_xmpp-client._tcp.#{jid.domain}", Resolv::DNS::Resource::IN::SRV) }
    if srv.empty?
      connect jid.domain, port, self, client, jid, pass
    else
      srv.sort! { |a,b| (a.priority != b.priority) ? (a.priority <=> b.priority) : (b.weight <=> a.weight) }
      srv.each { |r| break unless connect(r.target.to_s, r.port, self, client, jid, pass) === false }
    end
  end
end

Instance Method Details

#connection_completedObject

Called when EM completes the connection to the server this kicks off the starttls/authorize/bind process



74
75
76
77
# File 'lib/blather/stream.rb', line 74

def connection_completed # :nodoc:
#      @keepalive = EM::PeriodicTimer.new(60) { send_data ' ' }
  start
end

#post_initObject



92
93
94
# File 'lib/blather/stream.rb', line 92

def post_init
  @connected = true
end

#receive(node) ⇒ Object

Called by the parser with parsed nodes



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/blather/stream.rb', line 109

def receive(node) # :nodoc:
  Blather.logger.debug "RECEIVING (#{node.element_name}) #{node}"
  @node = node

  if @node.namespace && @node.namespace.prefix == 'stream'
    case @node.element_name
    when 'stream'
      @state = :ready if @state == :stopped
      return
    when 'error'
      handle_stream_error
      return
    when 'end'
      stop
      return
    when 'features'
      @state = :negotiating
      @receiver = Features.new(
        self,
        proc { ready! },
        proc { |err| @error = err; stop }
      )
    end
  end
  @receiver.receive_data @node.to_stanza
end

#receive_data(data) ⇒ Object

Called by EM with data from the wire



81
82
83
84
85
86
87
88
89
90
# File 'lib/blather/stream.rb', line 81

def receive_data(data) # :nodoc:
  Blather.logger.debug "\n#{'-'*30}\n"
  Blather.logger.debug "<< #{data}"
  @parser << data

rescue ParseError => e
  @error = e
  send "<stream:error><xml-not-well-formed xmlns='#{StreamError::STREAM_ERR_NS}'/></stream:error>"
  stop
end

#send(stanza) ⇒ Object

Send data over the wire

The argument for this can be anything that
responds to #to_s


52
53
54
55
56
# File 'lib/blather/stream.rb', line 52

def send(stanza)
  #TODO Queue if not ready
  Blather.logger.debug "SENDING: (#{caller[1]}) #{stanza}"
  send_data stanza.respond_to?(:to_xml) ? stanza.to_xml : stanza.to_s
end

#unbindObject

Called by EM when the connection is closed

Raises:



98
99
100
101
102
103
104
105
# File 'lib/blather/stream.rb', line 98

def unbind # :nodoc:
  raise NoConnection unless @connected

#      @keepalive.cancel
  @state = :stopped
  @client.receive_data @error if @error
  @client.unbind
end