c3s 0.2.7 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest +23 -3
- data/Rakefile +1 -1
- data/c3s +59 -0
- data/c3s.gemspec +4 -4
- data/lib/c3s.rb +1 -1
- data/lib/c3s_logger.rb +2 -1
- data/lib/component.rb +113 -12
- data/lib/component_connection.rb +11 -13
- data/lib/configreader.rb +4 -3
- data/lib/databaseadapter.rb +5 -2
- data/lib/pubsub/node.rb +47 -0
- data/lib/{nodetracker.rb → pubsub/nodetracker.rb} +0 -0
- data/lib/pubsub/publisher.rb +118 -0
- data/lib/pubsub/subscriber.rb +52 -0
- metadata +12 -7
- data/lib/publisher.rb +0 -95
data/Manifest
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Manifest
|
2
2
|
README.rdoc
|
3
3
|
Rakefile
|
4
|
-
c3s
|
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/
|
13
|
-
lib/
|
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
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
|
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{
|
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
|
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
data/lib/c3s_logger.rb
CHANGED
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.
|
188
|
+
jid = (iq.is_a?(Jabber::Iq)) ? iq.from.to_s : iq
|
102
189
|
if changed
|
103
|
-
pub = Publisher.new(self,
|
104
|
-
pub.create_nodes("
|
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 =
|
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
|
|
data/lib/component_connection.rb
CHANGED
@@ -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(
|
15
|
-
puts "Reading configurations from
|
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 "
|
56
|
-
|
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
|
-
|
12
|
-
|
13
|
-
@config = YAML::load_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
|
data/lib/databaseadapter.rb
CHANGED
@@ -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(
|
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 =>
|
17
|
+
:database => db_file, # TODO works only for sqlite3 dbs!
|
15
18
|
:encoding => config['encoding']
|
16
19
|
)
|
17
20
|
end
|
data/lib/pubsub/node.rb
ADDED
@@ -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
|
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:
|
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/
|
32
|
-
- lib/
|
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
|
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/
|
46
|
-
- lib/
|
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
|