Class: Vines::Cluster::PubSub

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

Overview

Manages the pubsub topic list and subscribers stored in redis. When a message is published to a topic, the receiving cluster node broadcasts the message to all subscribers at all other cluster nodes.

Instance Method Summary collapse

Constructor Details

#initialize(cluster) ⇒ PubSub

Returns a new instance of PubSub.



9
10
11
# File 'lib/vines/cluster/pubsub.rb', line 9

def initialize(cluster)
  @cluster = cluster
end

Instance Method Details

#add_node(domain, node) ⇒ Object

Create a pubsub topic (a.k.a. node), in the given domain, to which messages may be published. The domain argument will be one of the configured pubsub subdomains in conf/config.rb (e.g. games.wonderland.lit, topics.wonderland.lit, etc).



17
18
19
# File 'lib/vines/cluster/pubsub.rb', line 17

def add_node(domain, node)
  redis.sadd("pubsub:#{domain}:nodes", node)
end

#delete_node(domain, node) ⇒ Object

Remove a pubsub topic so messages may no longer be broadcast to it.



22
23
24
25
26
27
28
29
30
31
32
# File 'lib/vines/cluster/pubsub.rb', line 22

def delete_node(domain, node)
  redis.smembers("pubsub:#{domain}:subscribers_#{node}") do |subscribers|
    redis.multi
    subscribers.each do |jid|
      redis.srem("pubsub:#{domain}:subscriptions_#{jid}", node)
    end
    redis.del("pubsub:#{domain}:subscribers_#{node}")
    redis.srem("pubsub:#{domain}:nodes", node)
    redis.exec
  end
end

#node?(domain, node) ⇒ Boolean

Return true if the pubsub topic exists and messages may be published to it.

Returns:

  • (Boolean)


69
70
71
# File 'lib/vines/cluster/pubsub.rb', line 69

def node?(domain, node)
  @cluster.query(:sismember, "pubsub:#{domain}:nodes", node) == 1
end

#subscribe(domain, node, jid) ⇒ Object

Subscribe the JID to the pubsub topic so it will receive any messages published to it.



36
37
38
39
40
41
42
# File 'lib/vines/cluster/pubsub.rb', line 36

def subscribe(domain, node, jid)
  jid = JID.new(jid)
  redis.multi
  redis.sadd("pubsub:#{domain}:subscribers_#{node}", jid.to_s)
  redis.sadd("pubsub:#{domain}:subscriptions_#{jid}", node)
  redis.exec
end

#subscribed?(domain, node, jid) ⇒ Boolean

Return true if the JID is a registered subscriber to the pubsub topic and messages published to it should be routed to the JID.

Returns:

  • (Boolean)


75
76
77
78
# File 'lib/vines/cluster/pubsub.rb', line 75

def subscribed?(domain, node, jid)
  jid = JID.new(jid)
  @cluster.query(:sismember, "pubsub:#{domain}:subscribers_#{node}", jid.to_s) == 1
end

#subscribers(domain, node) ⇒ Object

Return a list of JIDs subscribed to the pubsub topic.



81
82
83
# File 'lib/vines/cluster/pubsub.rb', line 81

def subscribers(domain, node)
  @cluster.query(:smembers, "pubsub:#{domain}:subscribers_#{node}")
end

#unsubscribe(domain, node, jid) ⇒ Object

Unsubscribe the JID from the pubsub topic, deregistering its interest in receiving any messages published to it.



46
47
48
49
50
51
52
53
54
55
# File 'lib/vines/cluster/pubsub.rb', line 46

def unsubscribe(domain, node, jid)
  jid = JID.new(jid)
  redis.multi
  redis.srem("pubsub:#{domain}:subscribers_#{node}", jid.to_s)
  redis.srem("pubsub:#{domain}:subscriptions_#{jid}", node)
  redis.exec
  redis.scard("pubsub:#{domain}:subscribers_#{node}") do |count|
    delete_node(domain, node) if count == 0
  end
end

#unsubscribe_all(domain, jid) ⇒ Object

Unsubscribe the JID from all pubsub topics. This is useful when the JID’s session ends by logout or disconnect.



59
60
61
62
63
64
65
66
# File 'lib/vines/cluster/pubsub.rb', line 59

def unsubscribe_all(domain, jid)
  jid = JID.new(jid)
  redis.smembers("pubsub:#{domain}:subscriptions_#{jid}") do |nodes|
    nodes.each do |node|
      unsubscribe(domain, node, jid)
    end
  end
end