c3s 0.2.7 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Manifest CHANGED
@@ -1,7 +1,7 @@
1
1
  Manifest
2
2
  README.rdoc
3
3
  Rakefile
4
- c3s.gemspec
4
+ c3s
5
5
  lib/c3s.rb
6
6
  lib/c3s_logger.rb
7
7
  lib/component.rb
@@ -9,5 +9,25 @@ lib/component_connection.rb
9
9
  lib/configreader.rb
10
10
  lib/databaseadapter.rb
11
11
  lib/model.rb
12
- lib/nodetracker.rb
13
- lib/publisher.rb
12
+ lib/pubsub/node.rb
13
+ lib/pubsub/nodetracker.rb
14
+ lib/pubsub/publisher.rb
15
+ lib/pubsub/subscriber.rb
16
+ pkg/c3s-0.3.2.gem
17
+ pkg/c3s-0.3.2.tar.gz
18
+ pkg/c3s-0.3.2/Manifest
19
+ pkg/c3s-0.3.2/README.rdoc
20
+ pkg/c3s-0.3.2/Rakefile
21
+ pkg/c3s-0.3.2/c3s
22
+ pkg/c3s-0.3.2/c3s.gemspec
23
+ pkg/c3s-0.3.2/lib/c3s.rb
24
+ pkg/c3s-0.3.2/lib/c3s_logger.rb
25
+ pkg/c3s-0.3.2/lib/component.rb
26
+ pkg/c3s-0.3.2/lib/component_connection.rb
27
+ pkg/c3s-0.3.2/lib/configreader.rb
28
+ pkg/c3s-0.3.2/lib/databaseadapter.rb
29
+ pkg/c3s-0.3.2/lib/model.rb
30
+ pkg/c3s-0.3.2/lib/pubsub/node.rb
31
+ pkg/c3s-0.3.2/lib/pubsub/nodetracker.rb
32
+ pkg/c3s-0.3.2/lib/pubsub/publisher.rb
33
+ pkg/c3s-0.3.2/lib/pubsub/subscriber.rb
data/Rakefile CHANGED
@@ -2,7 +2,7 @@ require 'rubygems'
2
2
  require 'rake'
3
3
  require 'echoe'
4
4
 
5
- Echoe.new('c3s', '0.2.7') do |p|
5
+ Echoe.new('c3s', '0.3.2') do |p|
6
6
  p.description = "C3s library gem."
7
7
  p.url = "http://github.com/rikas/c3s"
8
8
  p.author = "Ricardo Otero"
data/c3s ADDED
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This is the command used to run the component
4
+
5
+ require 'rubygems'
6
+
7
+ # Check for gem versions
8
+ gem 'c3s', '>=0.3.2'
9
+ gem 'xmpp4r', '>=0.5'
10
+
11
+ require 'c3s'
12
+ require 'pathname'
13
+
14
+ PROVIDERS_DIR = File.join(ENV['HOME'], "ptcb", "code", "providers")
15
+
16
+ def usage
17
+ puts "Usage: provider [provider_dir]"
18
+ puts ""
19
+ puts "Available providers: #{available_providers}"
20
+ puts ""
21
+ exit
22
+ end
23
+
24
+ def available_providers
25
+ available_providers = []
26
+ Dir.glob(File.join(PROVIDERS_DIR, "*")) do |dir|
27
+ next unless File.directory?(dir)
28
+ conf = File.join(dir, "component.yml")
29
+ path = Pathname.new(dir)
30
+ available_providers << path.basename if File.exist?(conf)
31
+ end
32
+ available_providers.join(", ")
33
+ end
34
+
35
+ args = ARGV
36
+ if (args.size!=1)
37
+ usage
38
+ else
39
+ provider = File.join(PROVIDERS_DIR, args.last)
40
+ if (!File.directory?(provider))
41
+ puts "Couldn't find '#{args.last}' provider"
42
+ exit
43
+ end
44
+ end
45
+
46
+ # Set process name to provider
47
+ $0 = args.last
48
+
49
+ # Set the dir variables
50
+ C3S_COMPONENT_DIR = File.join(PROVIDERS_DIR, args.last)
51
+ C3S_LIB_DIR = File.join(C3S_COMPONENT_DIR, 'lib')
52
+ C3S_LOG_DIR = File.join(C3S_COMPONENT_DIR, 'logs')
53
+
54
+ # Power to the requires
55
+ $:.unshift C3S_COMPONENT_DIR
56
+ $:.unshift C3S_LIB_DIR
57
+ $:.unshift File.join(C3S_LIB_DIR, args.last)
58
+
59
+ require 'lib/runner'
data/c3s.gemspec CHANGED
@@ -2,15 +2,15 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{c3s}
5
- s.version = "0.2.7"
5
+ s.version = "0.3.2"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Ricardo Otero"]
9
- s.date = %q{2009-12-16}
9
+ s.date = %q{2010-02-11}
10
10
  s.description = %q{C3s library gem.}
11
11
  s.email = %q{oterosantos@gmail.com}
12
- s.extra_rdoc_files = ["README.rdoc", "lib/c3s.rb", "lib/c3s_logger.rb", "lib/component.rb", "lib/component_connection.rb", "lib/configreader.rb", "lib/databaseadapter.rb", "lib/model.rb", "lib/nodetracker.rb", "lib/publisher.rb"]
13
- s.files = ["Manifest", "README.rdoc", "Rakefile", "c3s.gemspec", "lib/c3s.rb", "lib/c3s_logger.rb", "lib/component.rb", "lib/component_connection.rb", "lib/configreader.rb", "lib/databaseadapter.rb", "lib/model.rb", "lib/nodetracker.rb", "lib/publisher.rb"]
12
+ s.extra_rdoc_files = ["README.rdoc", "lib/c3s.rb", "lib/c3s_logger.rb", "lib/component.rb", "lib/component_connection.rb", "lib/configreader.rb", "lib/databaseadapter.rb", "lib/model.rb", "lib/pubsub/node.rb", "lib/pubsub/nodetracker.rb", "lib/pubsub/publisher.rb", "lib/pubsub/subscriber.rb"]
13
+ s.files = ["Manifest", "README.rdoc", "Rakefile", "c3s", "lib/c3s.rb", "lib/c3s_logger.rb", "lib/component.rb", "lib/component_connection.rb", "lib/configreader.rb", "lib/databaseadapter.rb", "lib/model.rb", "lib/pubsub/node.rb", "lib/pubsub/nodetracker.rb", "lib/pubsub/publisher.rb", "lib/pubsub/subscriber.rb", "c3s.gemspec"]
14
14
  s.homepage = %q{http://github.com/rikas/c3s}
15
15
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "C3s", "--main", "README.rdoc"]
16
16
  s.require_paths = ["lib"]
data/lib/c3s.rb CHANGED
@@ -19,7 +19,7 @@ require 'databaseadapter'
19
19
  require 'c3s_logger'
20
20
 
21
21
  module C3s
22
- VERSION = "0.2.7"
22
+ VERSION = "0.2.9"
23
23
 
24
24
  def self.included(base)
25
25
  base.extend ClassMethods
data/lib/c3s_logger.rb CHANGED
@@ -5,7 +5,8 @@ module C3s
5
5
  class C3sLogger
6
6
  attr_accessor :logger
7
7
 
8
- def initialize(log_file)
8
+ def initialize
9
+ log_file = File.join(C3S_LOG_DIR, 'component.log')
9
10
  logger = Logger.new(log_file, "weekly")
10
11
  logger.formatter = C3sLogFormatter.new
11
12
  self.logger = logger
data/lib/component.rb CHANGED
@@ -8,7 +8,9 @@ rescue Exception => e
8
8
  end
9
9
  require 'xmpp4r/discovery'
10
10
  require 'xmpp4r/pubsub/helper/nodebrowser'
11
- require 'publisher'
11
+ require 'pubsub/publisher'
12
+ require 'pubsub/subscriber'
13
+ require 'pubsub/node'
12
14
 
13
15
  module C3s
14
16
  class Component < Jabber::Component
@@ -16,15 +18,21 @@ module C3s
16
18
  # Component configuration hash
17
19
  attr_accessor :config
18
20
 
21
+ ##
22
+ # Active record main class associated with component
23
+ attr_accessor :model
24
+
19
25
  ##
20
26
  # Initializes the jabber component with
21
27
  # a configuration hash read with ConfigReader
22
28
  #
23
29
  # config:: [Hash] configuration hash
24
- def initialize(config)
30
+ def initialize(config, model)
25
31
  super(config['jid'])
26
32
  self.config = config
33
+ self.model = model
27
34
  Jabber::debug = config['debug'].to_s.eql?"true"
35
+ config['pubsub'] = "pubsub.#{config['url']}"
28
36
  end
29
37
 
30
38
  ##
@@ -33,6 +41,7 @@ module C3s
33
41
  # Throws ClientAuthenticationFailure
34
42
  def connect
35
43
  super(config['url'], config['port'])
44
+
36
45
  if is_connected?
37
46
  auth(config['password'])
38
47
  else
@@ -45,7 +54,7 @@ module C3s
45
54
  # provides a callback named *handle_iq* for especific components
46
55
  # to use.
47
56
  def start
48
- super()
57
+ super
49
58
 
50
59
  Thread.abort_on_exception = true
51
60
 
@@ -55,6 +64,84 @@ module C3s
55
64
  end
56
65
  t.join
57
66
  end
67
+
68
+ add_message_callback do |msg|
69
+ t = Thread.new do
70
+ handle_msg(msg)
71
+ end
72
+ t.join
73
+ end
74
+ end
75
+
76
+ ##
77
+ # Tries to send the message. It will repeat the process if
78
+ # sending the stanza fails, reconnecting the client. This should be used
79
+ # instead of the default send method.
80
+ # msg:: the stanza to send
81
+ def send!(msg)
82
+ attempts = 0
83
+ begin
84
+ attempts += 1
85
+ send(msg)
86
+ rescue Errno::EPIPE, IOError => e
87
+ sleep 1
88
+ disconnect
89
+ reconnect
90
+ retry unless attempts > 3
91
+ raise e
92
+ rescue Errno::ECONNRESET => e
93
+ sleep (attempts^2) * 60 + 60
94
+ disconnect
95
+ reconnect
96
+ retry unless attempts > 3
97
+ raise e
98
+ end
99
+ end
100
+
101
+ ##
102
+ # Handles discovery, sets and gets
103
+ # iq:: [Jabber::IQ] the received IQ packet
104
+ def handle_iq(iq)
105
+ if iq.query.kind_of?(Jabber::Discovery::IqQueryDiscoInfo)
106
+ handle_disco_info(iq)
107
+ elsif iq.query.first_element(config['name']) # TODO assuming that pubsubnode = xml root
108
+ handle_set(iq) if iq.type == :set
109
+ handle_get(iq) if iq.type == :get
110
+ end
111
+ rescue Exception => e
112
+ $LOG.error("#{e.inspect} #{e.backtrace.join("\n")}")
113
+ send_error(iq, ['bad-request', nil])
114
+ end
115
+
116
+ def handle_msg(msg)
117
+ end
118
+
119
+ ##
120
+ # Handles set of information
121
+ # iq:: [Jabber::IQ] the received IQ packet
122
+ def handle_set(iq)
123
+ stanza = iq.query.first_element(config['name']) # TODO assuming that pubsubnode = xml root
124
+
125
+ # Build data for activerecord object. The jid is taken from
126
+ # the 'jid' attribute on the main tag under the <query>
127
+ data = {:jid => iq.from.to_s}
128
+ self.model.new.nodes.each do |node|
129
+ data.merge!(node => stanza.first_element_text(node))
130
+ end
131
+
132
+ changed = true
133
+ @object = self.model.find_by_jid(data[:jid]) || self.model.new
134
+
135
+ $LOG.info "Saving #{config['name']} context for #{data[:jid]} #{data.inspect}"
136
+ @object.update_attributes(data)
137
+ changed = @object.changed?
138
+ @object.save!
139
+
140
+ publish(iq, stanza, changed) if @object.errors.count == 0
141
+
142
+ rescue Exception => e
143
+ $LOG.error("#{e.inspect} #{e.backtrace.join("\n")}")
144
+ send_error(iq, ['bad-request', @object.errors.full_messages.first])
58
145
  end
59
146
 
60
147
  ##
@@ -67,13 +154,13 @@ module C3s
67
154
  send_error(iq, ['bad-request', nil])
68
155
  return
69
156
  end
70
-
157
+
71
158
  reply.type = :result
72
159
  reply.query.add(Jabber::Discovery::Identity.new(config['category'], config['description'], config['type']))
73
160
  reply.query.add(Jabber::Discovery::Feature.new(Jabber::Discovery::IqQueryDiscoInfo.new.namespace))
74
161
  reply.query.add(Jabber::Discovery::Feature.new(Jabber::Discovery::IqQueryDiscoItems.new.namespace))
75
162
 
76
- send(reply)
163
+ send!(reply)
77
164
  end
78
165
 
79
166
  ##
@@ -89,7 +176,7 @@ module C3s
89
176
  error = Jabber::ErrorResponse.new(err.first, err.last)
90
177
  reply.add error
91
178
 
92
- send(reply) if iq.type != :error
179
+ send!(reply) if iq.type != :error
93
180
  end
94
181
 
95
182
  ##
@@ -98,27 +185,41 @@ module C3s
98
185
  # data:: what to publish
99
186
  # changed:: the data is different from last set operation?
100
187
  def publish(iq, data, changed)
101
- jid = (iq.is_a?(Jabber::Iq)) ? iq.from.bare.to_s : iq
188
+ jid = (iq.is_a?(Jabber::Iq)) ? iq.from.to_s : iq
102
189
  if changed
103
- pub = Publisher.new(self, "pubsub."+config['url'])
104
- pub.create_nodes("/#{config['name']}/#{jid}")
190
+ pub = Publisher.new(self, config['pubsub'])
191
+ pub.create_nodes("#{config['name']}:#{jid}")
105
192
  pub.publish(jid, data)
106
193
  end
107
194
 
108
195
  send_ok(iq) if iq.is_a?(Jabber::Iq)
109
196
  end
110
197
 
198
+ def get_subscriptions
199
+ @pubsub = Jabber::PubSub::ServiceHelper.new(self, config['pubsub'])
200
+ subs = @pubsub.get_subscriptions_from_all_nodes
201
+ puts "SUBSCRIPTIONS: #{subs.inspect}"
202
+ subs
203
+ end
204
+
205
+ def unsubscribe_all
206
+ subscriptions = get_subscriptions
207
+ return if !@pubsub
208
+ subscriptions.each do |sub|
209
+ @pubsub.unsubscribe_from(sub.node, sub.subid)
210
+ end
211
+ end
212
+
111
213
  ##
112
214
  # Sends an OK response to a given iq
113
215
  # iq:: the iq to respond to
114
216
  def send_ok(iq)
115
- reply = Jabber::Iq.new()
217
+ reply = iq.answer
116
218
  reply.id = iq.id
117
219
  reply.to = iq.from
118
220
  reply.type = :result
119
- reply.add(Jabber::IqQuery::new)
120
221
 
121
- send(reply) if iq.type != :error
222
+ send!(reply) if iq.type != :error
122
223
  end
123
224
  end
124
225
 
@@ -1,9 +1,5 @@
1
1
  module C3s
2
- class ComponentConnection
3
- ##
4
- # The configuration file
5
- CONFIG_FILE = "component.yml"
6
-
2
+ class ComponentConnection
7
3
  def initialize(componentclass, options={})
8
4
  @no_db = options[:no_db]
9
5
  if !componentclass.superclass.eql?(C3s::Component)
@@ -11,8 +7,8 @@ module C3s
11
7
  exit
12
8
  end
13
9
 
14
- reader = C3s::ConfigReader.new(CONFIG_FILE, options)
15
- puts "Reading configurations from '#{CONFIG_FILE}'..."
10
+ reader = C3s::ConfigReader.new(options)
11
+ puts "Reading configurations from yaml file..."
16
12
  @server_config = reader.section('server')
17
13
  @client_config = reader.section('client')
18
14
 
@@ -37,12 +33,12 @@ module C3s
37
33
  exit
38
34
  end
39
35
  end
40
- connect()
36
+ connect
41
37
  end
42
38
 
43
39
  def connect
44
40
  puts "Connecting to #{@server_config['url']} (port #{@server_config['port']})..."
45
-
41
+
46
42
  begin
47
43
  @component.connect
48
44
  rescue Jabber::ComponentAuthenticationFailure => e
@@ -52,20 +48,22 @@ module C3s
52
48
  puts "Connection refused on #{@server_config['url']} (port #{@server_config['port']})"
53
49
  exit
54
50
  rescue Exception => e
55
- puts "Error do fim do mundo!"
56
- puts e.message
51
+ puts "ERROR: Couldn't connect to server!"
52
+ $LOG.error "Couldn't connect to server!"
57
53
  exit
58
54
  end
59
55
  puts "External component #{@client_config['jid']} connected successfully."
60
56
 
57
+ # TODO - never used?!
61
58
  @component.on_exception do |e, component, where|
62
- $LOG.error "FATAL ERROR"
59
+ $LOG.error "**************FATAL ERROR"
63
60
  $LOG.error e.message
64
61
  $LOG.error e.backtrace.join("\n")
62
+ exit
65
63
  end
66
64
 
67
65
  puts "Starting messaging loop..."
68
- @component.start()
66
+ @component.start
69
67
  end
70
68
 
71
69
  def self.stop
data/lib/configreader.rb CHANGED
@@ -6,11 +6,12 @@ module C3s
6
6
  SECTIONS = ['client', 'server', 'db']
7
7
 
8
8
  class ConfigReader
9
+
9
10
  ##
10
11
  # Reads the configuration file
11
- # file::[String] the configuration file
12
- def initialize(file, options={})
13
- @config = YAML::load_file(File.join(file))
12
+ def initialize(options={})
13
+ config_file = File.join(C3S_COMPONENT_DIR, 'component.yml')
14
+ @config = YAML::load_file(config_file)
14
15
 
15
16
  SECTIONS.delete('db') if options[:no_db]
16
17
  check_config
@@ -3,15 +3,18 @@ require 'active_record'
3
3
  module C3s
4
4
  class DatabaseAdapter
5
5
  def initialize(config)
6
+ log_file = File.join(C3S_LOG_DIR, "database.log")
7
+ db_file = File.join(C3S_COMPONENT_DIR, config['database'])
8
+
6
9
  ActiveRecord::Base.colorize_logging = false
7
- ActiveRecord::Base.logger = Logger.new(File.open('logs/database.log', 'a'))
10
+ ActiveRecord::Base.logger = Logger.new(File.open(log_file, 'a'))
8
11
 
9
12
  ActiveRecord::Base.establish_connection(
10
13
  :adapter => config['adapter'],
11
14
  :host => config['host'],
12
15
  :username => config['username'],
13
16
  :password => config['password'],
14
- :database => config['database'],
17
+ :database => db_file, # TODO works only for sqlite3 dbs!
15
18
  :encoding => config['encoding']
16
19
  )
17
20
  end
@@ -0,0 +1,47 @@
1
+ module C3s
2
+ class Node
3
+ PATTERN = /^(?:([^@\/:]*):?)?(?:([^@]*)@)??([^@\/]*)(?:\/(.*?))?$/
4
+
5
+ attr_reader :jid
6
+ attr_accessor :provider
7
+
8
+ ##
9
+ # Create a new c3s pubsub node. If called as new('provider:jid') or
10
+ # new('provider:jid/resource') parse the string and split (provider, jid, resource)
11
+ def initialize(provider = "", jid = nil)
12
+ @jid = jid
13
+ @provider = provider
14
+
15
+ if @jid.nil? and @provider
16
+ @provider, @node, @domain, @resource = @provider.to_s.scan(PATTERN).first
17
+ @jid = Jabber::JID.new(@node, @domain, @resource)
18
+ end
19
+
20
+ @provider.downcase! if @provider
21
+ end
22
+
23
+ ##
24
+ # Returns a string representation of the node
25
+ # * ""
26
+ # * "provider"
27
+ # * "provider:user@domain"
28
+ # * "provider:user@domain/resource"
29
+ def to_s
30
+ s = @provider
31
+ s = "#{s}:#{@jid.to_s}" if @jid
32
+ end
33
+
34
+ ##
35
+ # Returns the resource for this node
36
+ def resource
37
+ return nil unless @jid
38
+ @jid.resource
39
+ end
40
+
41
+ ##
42
+ # Checks if a node is a leaf node on c3s pubsub
43
+ def leaf?
44
+ resource ? true : false
45
+ end
46
+ end
47
+ end
File without changes
@@ -0,0 +1,118 @@
1
+ require 'xmpp4r/pubsub'
2
+ require 'pubsub/nodetracker'
3
+
4
+ module C3s
5
+ class Publisher
6
+ ##
7
+ # Initializes the publisher
8
+ # client:: [Jabber::Client] the client publishing
9
+ # service:: [String] pubsub service name (eg: pubsub.jabber)
10
+ def initialize(client, service_name)
11
+ @client = client
12
+ @service = service_name
13
+ @pubsub = Jabber::PubSub::ServiceHelper.new(@client, @service)
14
+ end
15
+
16
+ ##
17
+ # Creates the collection node(s) and leaf node if needed
18
+ # nodetree:: [String] node tree (eg: location:user@jabber.com/resource)
19
+ def create_nodes(nodetree)
20
+ nodes = nodetree.split(":")
21
+
22
+ # build array like this one:
23
+ # ['location', 'user@jabber.com', 'user@jabber.com/resource']
24
+ nodes.insert(1, nodes.last.split("/").first)
25
+
26
+ collection = nodes.shift # collection (eg: location)
27
+ subcollection = "#{collection}:#{nodes.shift}" # subcollection (eg: location:user@jabber.com)
28
+ leaf = "#{collection}:#{nodes.shift}" # leaf node name (eg: location:user@jabber.com/resource)
29
+ leaf << "/default" unless leaf.match(/.*\/.*/)
30
+
31
+ # create nodes
32
+ create_node(collection, {:collection => true})
33
+ create_node(subcollection, {:father => collection, :collection => true})
34
+ create_node(leaf, {:father => subcollection, :collection => false})
35
+ end
36
+
37
+ ##
38
+ # Creates a pubsub node
39
+ # nodename:: [String] the node name
40
+ # options:: [Hash] hash with options. These can be:
41
+ # * :collection => true or false
42
+ # * :father => the father node or nil if its root
43
+ def create_node(nodename, options={})
44
+ return if node_exists?(nodename)
45
+ config = Jabber::PubSub::NodeConfig.new
46
+
47
+ if options[:father]
48
+ config.options = config.options.merge({'pubsub#collection' => options[:father]})
49
+ end
50
+
51
+ if options[:collection]
52
+ node = create_collection_node(nodename, config)
53
+ else
54
+ node = create_leaf_node(nodename, config)
55
+ end
56
+
57
+ # grant owner to admin user (eg: admin@jabber.com)
58
+ grant_owner_to_admin(node)
59
+ end
60
+
61
+ ##
62
+ # Creates the collection node if needed
63
+ # name:: [String] collection node name
64
+ # config:: [PubSub::NodeConfig] node configuration
65
+ def create_collection_node(name, config)
66
+ $LOG.debug("Creating collection node #{name}...")
67
+ $LOG.debug("Node config: #{config.options.inspect}")
68
+ return if node_exists?(name)
69
+ node = @pubsub.create_collection_node(name, config)
70
+ end
71
+
72
+ ##
73
+ # Creates a leaf node to publish if needed
74
+ # This node must be associated with the collection node
75
+ # name:: [String] the name of the leaf node
76
+ # config:: [PubSub::NodeConfig] node configuration
77
+ def create_leaf_node(name, config)
78
+ $LOG.debug("Creating leaf node #{name}")
79
+ $LOG.debug("Node config: #{config.options.inspect}")
80
+ return if node_exists?(name)
81
+ node = @pubsub.create_node(name, config)
82
+ end
83
+
84
+ def grant_owner_to_admin(node)
85
+ return unless node
86
+ @pubsub.set_affiliations(node, "admin@#{@client.config['url']}", 'owner')
87
+ end
88
+
89
+ ##
90
+ # Publishes content to the leaf node
91
+ # node:: [String] the node to plublish to
92
+ # content:: [REXML::Element] content xml to publish into node
93
+ def publish(node, content)
94
+ item = Jabber::PubSub::Item.new
95
+ item.add(content)
96
+
97
+ node << "/default" unless node.match(/.*\/.*/)
98
+ node = [@client.config['name'], node].join(":")
99
+ @pubsub.publish_item_to(node, item)
100
+ end
101
+
102
+ ##
103
+ # Checks for existance of a node with a given name. This
104
+ # node can be a leaf or a collection
105
+ # name:: [String] the node name
106
+ def node_exists?(name)
107
+ return true if NodeTracker.include?(name)
108
+ nodebrowser = Jabber::PubSub::NodeBrowser.new(@client)
109
+ nodebrowser.get_info(@service, name)
110
+ # TODO this could be used instead
111
+ # nodebrowser.nodes(@client.jid).include?(name)
112
+ NodeTracker.add_node(name)
113
+ true
114
+ rescue Jabber::ServerError => error
115
+ return false if error.to_s.include?("item-not-found")
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,52 @@
1
+ require 'xmpp4r/pubsub'
2
+ require 'pubsub/nodetracker'
3
+
4
+ module C3s
5
+ class Subscriber
6
+ ##
7
+ # Initializes the publisher
8
+ # client:: [Jabber::Client] the client publishing
9
+ # service:: [String] pubsub service name (eg: pubsub.jabber)
10
+ def initialize(client, service_name)
11
+ @client = client
12
+ @service = service_name
13
+ @pubsub = Jabber::PubSub::ServiceHelper.new(@client, @service)
14
+ @browser = Jabber::PubSub::NodeBrowser.new(@client)
15
+ end
16
+
17
+ ##
18
+ # Subscribes to collection node.
19
+ # nodename:: [String] the node name
20
+ def subscribe_collection(nodename)
21
+ return if !is_collection?(nodename)
22
+ subscription = @pubsub.subscribe_to(nodename)
23
+ options = {
24
+ 'pubsub#subscription_type' => 'items',
25
+ 'pubsub#subscription_depth' => 'all'
26
+ }
27
+ @pubsub.set_options_for(nodename, @client.jid, options, subscription.subid)
28
+ end
29
+
30
+ ##
31
+ # Unsubscribe node
32
+ # nodename:: [String] the node name
33
+ def unsubscribe_from(nodename)
34
+ @pubsub.unsubscribe_from(nodename)
35
+ end
36
+
37
+ ##
38
+ # Checks if a node is a collection node
39
+ # nodename:: [String] the node name
40
+ def is_collection?(nodename)
41
+ info = @browser.get_info(@service, nodename)
42
+ info['type'].eql?('collection')
43
+ end
44
+
45
+ ##
46
+ # Returns the last item from a node. This node must be a leaf node.
47
+ # nodename:: [String] the node name
48
+ def get_last_item(nodename)
49
+ @pubsub.get_items_from(nodename, 1)
50
+ end
51
+ end
52
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: c3s
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.7
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ricardo Otero
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-12-16 00:00:00 +00:00
12
+ date: 2010-02-11 00:00:00 +00:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -28,13 +28,15 @@ extra_rdoc_files:
28
28
  - lib/configreader.rb
29
29
  - lib/databaseadapter.rb
30
30
  - lib/model.rb
31
- - lib/nodetracker.rb
32
- - lib/publisher.rb
31
+ - lib/pubsub/node.rb
32
+ - lib/pubsub/nodetracker.rb
33
+ - lib/pubsub/publisher.rb
34
+ - lib/pubsub/subscriber.rb
33
35
  files:
34
36
  - Manifest
35
37
  - README.rdoc
36
38
  - Rakefile
37
- - c3s.gemspec
39
+ - c3s
38
40
  - lib/c3s.rb
39
41
  - lib/c3s_logger.rb
40
42
  - lib/component.rb
@@ -42,8 +44,11 @@ files:
42
44
  - lib/configreader.rb
43
45
  - lib/databaseadapter.rb
44
46
  - lib/model.rb
45
- - lib/nodetracker.rb
46
- - lib/publisher.rb
47
+ - lib/pubsub/node.rb
48
+ - lib/pubsub/nodetracker.rb
49
+ - lib/pubsub/publisher.rb
50
+ - lib/pubsub/subscriber.rb
51
+ - c3s.gemspec
47
52
  has_rdoc: true
48
53
  homepage: http://github.com/rikas/c3s
49
54
  licenses: []
data/lib/publisher.rb DELETED
@@ -1,95 +0,0 @@
1
- require 'xmpp4r/pubsub'
2
- require 'nodetracker'
3
-
4
- module C3s
5
- class Publisher
6
- ##
7
- # Initializes the publisher
8
- # client:: [Jabber::Client] the client publishing
9
- # service:: [String] pubsub service name (eg: pubsub.jabber)
10
- def initialize(client, service_name)
11
- @client = client
12
- @service = service_name
13
- @pubsub = Jabber::PubSub::ServiceHelper.new(@client, @service)
14
- end
15
-
16
- ##
17
- # Creates the collection node(s) and leaf node if needed
18
- # nodetree:: [String] node tree (eg: /location/user@jabber.com)
19
- def create_nodes(nodetree)
20
- nodes = nodetree.split("/")
21
- nodes.delete("")
22
-
23
- # all nodes except the last are assumed as collection nodes
24
- last_collection = nil
25
- nodes[0..nodes.size-2].each do |name|
26
- create_collection_node(name) if !node_exists?(name)
27
- last_collection = name
28
- end
29
-
30
- # last node is assumed as a leaf node
31
- leaf = nodetree[1..nodetree.size-1] if nodetree[0..0].eql?"/"
32
- leaf.gsub!("/", ":")
33
- create_leaf_node(leaf, last_collection) if !node_exists?(leaf)
34
- end
35
-
36
- ##
37
- # Creates the collection node if needed
38
- # name:: [String] collection node name
39
- def create_collection_node(name)
40
- config = Jabber::PubSub::NodeConfig.new
41
- node = @pubsub.create_collection_node(name, config)
42
- grant_owner_to_admin(node)
43
- end
44
-
45
- ##
46
- # Creates a leaf node to publish if needed
47
- # This node must be associated with the collection node
48
- # name:: [String] the name of the leaf node
49
- # collection:: [String] the collection node that contains the node
50
- def create_leaf_node(name, collection)
51
- config = Jabber::PubSub::NodeConfig.new
52
- config.options = config.options.merge({'pubsub#collection' => collection})
53
- node = @pubsub.create_node(name, config)
54
- grant_owner_to_admin(node)
55
- end
56
-
57
- def grant_owner_to_admin(node)
58
- return unless node
59
- @pubsub.set_affiliations(node, "admin@#{@client.config['url']}", 'owner')
60
- end
61
-
62
- ##
63
- # Publishes content to the leaf node
64
- # node:: [String] the node to plublish to
65
- # content:: [REXML::Element] content xml to publish into node
66
- def publish(node, content)
67
- item = Jabber::PubSub::Item.new
68
- item.add(content)
69
- node = [@client.config['name'], node].join(":")
70
- @pubsub.publish_item_to(node, item)
71
- end
72
-
73
- def fix_permissions
74
- nodebrowser = Jabber::PubSub::NodeBrowser.new(@client)
75
- nodes = nodebrowser.nodes_names(@service)
76
- nodes.each do |node|
77
- grant_owner_to_admin(node['node'])
78
- end
79
- end
80
-
81
- ##
82
- # Checks for existance of a node with a given name. This
83
- # node can be a leaf or a collection
84
- # name:: [String] the node name
85
- def node_exists?(name)
86
- return true if NodeTracker.include?(name)
87
- nodebrowser = Jabber::PubSub::NodeBrowser.new(@client)
88
- nodebrowser.get_info(@service, name)
89
- NodeTracker.add_node(name)
90
- true
91
- rescue Jabber::ServerError => error
92
- return false if error.to_s.include?("item-not-found")
93
- end
94
- end
95
- end