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 +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
|