class Vines::Stream::Client::Session

A Session tracks the state of a client stream over its lifetime from negotiation to processing stanzas to shutdown. By disconnecting the stream's state from the stream, we can allow multiple TCP connections to access one logical session (e.g. HTTP streams).

Attributes

domain[RW]
id[R]
last_broadcast_presence[R]
state[R]
user[RW]

Public Class Methods

new(stream) click to toggle source
# File lib/vines/stream/client/session.rb, line 16
def initialize(stream)
  @stream = stream
  @id = Kit.uuid
  @config = stream.config
  @state = Client::Start.new(stream)
  @available = false
  @domain = nil
  @last_broadcast_presence = nil
  @requested_roster = false
  @unbound = false
  @user = nil
end

Public Instance Methods

<=>(session) click to toggle source
# File lib/vines/stream/client/session.rb, line 29
def <=>(session)
  session.is_a?(Session) ? self.id <=> session.id : nil
end
advance(state) click to toggle source
# File lib/vines/stream/client/session.rb, line 39
def advance(state)
  @state = state
end
authenticated?() click to toggle source

Returns true if this client has properly authenticated with the server.

# File lib/vines/stream/client/session.rb, line 45
def authenticated?
  !@user.nil?
end
available!() click to toggle source

Notify the session that the client has sent an initial presence broadcast and is now considered to be an “available” resource. Available resources are sent presence subscription stanzas.

# File lib/vines/stream/client/session.rb, line 52
def available!
  @available = true
  save_to_cluster
end
available?() click to toggle source

An available resource has sent initial presence and can receive presence subscription requests.

# File lib/vines/stream/client/session.rb, line 59
def available?
  @available && connected?
end
available_subscribed_to_resources() click to toggle source

Returns streams for available resources to which this user has successfully subscribed.

# File lib/vines/stream/client/session.rb, line 123
def available_subscribed_to_resources
  subscribed = @user.subscribed_to_contacts.map {|c| c.jid }
  router.available_resources(subscribed, @user.jid)
end
available_subscribers() click to toggle source

Returns streams for available resources that are subscribed to this user's presence updates.

# File lib/vines/stream/client/session.rb, line 130
def available_subscribers
  subscribed = @user.subscribed_from_contacts.map {|c| c.jid }
  router.available_resources(subscribed, @user.jid)
end
bind!(resource) click to toggle source

Complete resource binding with the given resource name, provided by the client or generated by the server. Once resource binding is completed, the stream is considered to be “connected” and ready for traffic.

# File lib/vines/stream/client/session.rb, line 66
def bind!(resource)
  @user.jid.resource = resource
  router << self
  save_to_cluster
end
connected?() click to toggle source

A connected resource has authenticated and bound a resource identifier.

# File lib/vines/stream/client/session.rb, line 74
def connected?
  !@unbound && authenticated? && !@user.jid.bare?
end
hash() click to toggle source
# File lib/vines/stream/client/session.rb, line 35
def hash
  @id.hash
end
interested?() click to toggle source

An interested resource has requested its roster and can receive roster pushes.

# File lib/vines/stream/client/session.rb, line 80
def interested?
  @requested_roster && connected?
end
last_broadcast_presence=(node) click to toggle source
# File lib/vines/stream/client/session.rb, line 84
def last_broadcast_presence=(node)
  @last_broadcast_presence = node
  save_to_cluster
end
ready?() click to toggle source
# File lib/vines/stream/client/session.rb, line 89
def ready?
  @state.class == Client::Ready
end
remote_subscribed_to_contacts() click to toggle source

Returns contacts hosted at remote servers to which this user has successfully subscribed.

# File lib/vines/stream/client/session.rb, line 137
def remote_subscribed_to_contacts
  @user.subscribed_to_contacts.reject do |c|
    @config.local_jid?(c.jid)
  end
end
remote_subscribers(to=nil) click to toggle source

Returns contacts hosted at remote servers that are subscribed to this user's presence updates.

# File lib/vines/stream/client/session.rb, line 145
def remote_subscribers(to=nil)
  jid = (to.nil? || to.empty?) ? nil : JID.new(to).bare
  @user.subscribed_from_contacts.reject do |c|
    @config.local_jid?(c.jid) || (jid && c.jid.bare != jid)
  end
end
requested_roster!() click to toggle source

Notify the session that the client has requested its roster and is now considered to be an “interested” resource. Interested resources are sent roster pushes when changes are made to their contacts.

# File lib/vines/stream/client/session.rb, line 96
def requested_roster!
  @requested_roster = true
  save_to_cluster
end
stream_type() click to toggle source
# File lib/vines/stream/client/session.rb, line 101
def stream_type
  :client
end
unbind!(stream) click to toggle source

Called by the stream when it's disconnected from the client. The stream passes itself to this method in case multiple streams are accessing this session (e.g. BOSH/HTTP).

# File lib/vines/stream/client/session.rb, line 112
def unbind!(stream)
  router.delete(self)
  delete_from_cluster
  unsubscribe_pubsub
  @unbound = true
  @available = false
  broadcast_unavailable
end
write(data) click to toggle source
# File lib/vines/stream/client/session.rb, line 105
def write(data)
  @stream.write(data)
end

Private Instance Methods

broadcast(stanza, recipients) click to toggle source
# File lib/vines/stream/client/session.rb, line 174
def broadcast(stanza, recipients)
  recipients.each do |recipient|
    stanza['to'] = recipient.user.jid.to_s
    recipient.write(stanza)
  end
end
broadcast_unavailable() click to toggle source
# File lib/vines/stream/client/session.rb, line 154
def broadcast_unavailable
  return unless authenticated?
  Fiber.new do
    broadcast(unavailable, available_subscribers)
    broadcast(unavailable, router.available_resources(@user.jid, @user.jid))
    remote_subscribers.each do |contact|
      node = unavailable
      node['to'] = contact.jid.bare.to_s
      router.route(node) rescue nil # ignore RemoteServerNotFound
    end
  end.resume
end
delete_from_cluster() click to toggle source
# File lib/vines/stream/client/session.rb, line 191
def delete_from_cluster
  if connected? && @config.cluster?
    @config.cluster.delete_session(@user.jid)
  end
end
router() click to toggle source
# File lib/vines/stream/client/session.rb, line 181
def router
  @config.router
end
save_to_cluster() click to toggle source
# File lib/vines/stream/client/session.rb, line 185
def save_to_cluster
  if @config.cluster?
    @config.cluster.save_session(@user.jid, to_hash)
  end
end
to_hash() click to toggle source
# File lib/vines/stream/client/session.rb, line 203
def to_hash
  presence = @last_broadcast_presence ? @last_broadcast_presence.to_s : nil
  {available: @available, interested: @requested_roster, presence: presence.to_s}
end
unavailable() click to toggle source
# File lib/vines/stream/client/session.rb, line 167
def unavailable
  doc = Nokogiri::XML::Document.new
  doc.create_element('presence',
    'from' => @user.jid.to_s,
    'type' => 'unavailable')
end
unsubscribe_pubsub() click to toggle source
# File lib/vines/stream/client/session.rb, line 197
def unsubscribe_pubsub
  if connected?
    @config.vhost(@user.jid.domain).unsubscribe_pubsub(@user.jid)
  end
end