Class: Vines::Router

Inherits:
Object
  • Object
show all
Defined in:
lib/vines/router.rb

Overview

The router tracks all stream connections to the server for all clients, servers, and components. It sends stanzas to the correct stream based on the ‘to’ attribute. Router is a singleton, shared by all streams, that must be accessed with Router.instance, not Router.new.

Constant Summary collapse

ROUTABLE_STANZAS =
%w[message iq presence].freeze
STREAM_TYPES =
[:client, :server, :component].freeze
@@instance =
nil

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeRouter

Returns a new instance of Router.



23
24
25
26
27
# File 'lib/vines/router.rb', line 23

def initialize
  @config = nil
  @streams = Hash.new {|h,k| h[k] = [] }
  @pending = Hash.new {|h,k| h[k] = [] }
end

Class Method Details

.instanceObject



19
20
21
# File 'lib/vines/router.rb', line 19

def self.instance
  @@instance ||= self.new
end

Instance Method Details

#<<(connection) ⇒ Object

Add the connection to the routing table. The connection must return :client, :server, or :component from its stream_type method so the router can properly route stanzas to the stream.



62
63
64
65
66
# File 'lib/vines/router.rb', line 62

def <<(connection)
  type = stream_type(connection)
  @config ||= connection.config
  @streams[type] << connection
end

#available_resources(*jid) ⇒ Object

Returns streams for all available resources for this JID. A resource is marked available after it sends initial presence. This method accepts a single JID or a list of JIDs.



42
43
44
45
46
47
# File 'lib/vines/router.rb', line 42

def available_resources(*jid)
  ids = jid.flatten.map {|jid| JID.new(jid).bare }
  clients.select do |stream|
    stream.available? && ids.include?(stream.user.jid.bare)
  end
end

#connected_resources(jid) ⇒ Object

Returns streams for all connected resources for this JID. A resource is considered connected after it has completed authentication and resource binding.



32
33
34
35
36
37
# File 'lib/vines/router.rb', line 32

def connected_resources(jid)
  jid = JID.new(jid)
  clients.select do |stream|
    stream.connected? && jid == (jid.bare? ? stream.user.jid.bare : stream.user.jid)
  end
end

#delete(connection) ⇒ Object

Remove the connection from the routing table.



69
70
71
72
# File 'lib/vines/router.rb', line 69

def delete(connection)
  type = stream_type(connection)
  @streams[type].delete(connection)
end

#interested_resources(*jid) ⇒ Object

Returns streams for all interested resources for this JID. A resource is marked interested after it requests the roster. This method accepts a single JID or a list of JIDs.



52
53
54
55
56
57
# File 'lib/vines/router.rb', line 52

def interested_resources(*jid)
  ids = jid.flatten.map {|jid| JID.new(jid).bare }
  clients.select do |stream|
    stream.interested? && ids.include?(stream.user.jid.bare)
  end
end

#local?(stanza) ⇒ Boolean

Returns true if this stanza should be processed locally. Returns false if it’s destined for a remote domain or external component.

Returns:

  • (Boolean)


102
103
104
105
106
# File 'lib/vines/router.rb', line 102

def local?(stanza)
  return true unless ROUTABLE_STANZAS.include?(stanza.name)
  to = (stanza['to'] || '').strip
  to.empty? || local_jid?(to)
end

#local_jid?(jid) ⇒ Boolean

Returns:

  • (Boolean)


108
109
110
# File 'lib/vines/router.rb', line 108

def local_jid?(jid)
  @config.vhost?(JID.new(jid).domain)
end

#route(stanza) ⇒ Object

Send the stanza to the appropriate remote server-to-server stream or an external component stream.



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/vines/router.rb', line 76

def route(stanza)
  to, from = %w[to from].map {|attr| JID.new(stanza[attr]) }
  if stream = connection_to(to.domain)
    stream.write(stanza)
  elsif @pending.key?(to.domain)
    @pending[to.domain] << stanza
  elsif @config.s2s?(to.domain)
    @pending[to.domain] << stanza
    Vines::Stream::Server.start(@config, to.domain, from.domain) do |stream|
      if stream
        @pending[to.domain].each {|s| stream.write(s) }
      else
        @pending[to.domain].each do |s|
          xml = StanzaErrors::RemoteServerNotFound.new(s, 'cancel').to_xml
          connected_resources(s['from']).each {|c| c.write(xml) }
        end
      end
      @pending.delete(to.domain)
    end
  else
    raise StanzaErrors::RemoteServerNotFound.new(stanza, 'cancel')
  end
end

#sizeObject

Returns the total number of streams connected to the server.



113
114
115
# File 'lib/vines/router.rb', line 113

def size
  @streams.values.inject(0) {|sum, arr| sum + arr.size }
end