c3s 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest +12 -0
- data/README.rdoc +0 -0
- data/Rakefile +14 -0
- data/c3s.gemspec +30 -0
- data/lib/c3s.rb +17 -0
- data/lib/c3s_logger.rb +23 -0
- data/lib/component.rb +80 -0
- data/lib/component_connection.rb +72 -0
- data/lib/configreader.rb +46 -0
- data/lib/databaseadapter.rb +19 -0
- data/lib/nodetracker.rb +27 -0
- data/lib/publisher.rb +80 -0
- metadata +79 -0
data/Manifest
ADDED
data/README.rdoc
ADDED
File without changes
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'echoe'
|
4
|
+
|
5
|
+
Echoe.new('c3s', '0.2.0') do |p|
|
6
|
+
p.description = "C3s library gem."
|
7
|
+
p.url = "http://github.com/rikas/c3s"
|
8
|
+
p.author = "Ricardo Otero"
|
9
|
+
p.email = "oterosantos@gmail.com"
|
10
|
+
p.ignore_pattern = ["tmp/*", "script/*"]
|
11
|
+
p.development_dependencies = []
|
12
|
+
end
|
13
|
+
|
14
|
+
Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
|
data/c3s.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{c3s}
|
5
|
+
s.version = "0.2.0"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Ricardo Otero"]
|
9
|
+
s.date = %q{2009-11-30}
|
10
|
+
s.description = %q{C3s library gem.}
|
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/nodetracker.rb", "lib/publisher.rb"]
|
13
|
+
s.files = ["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/nodetracker.rb", "lib/publisher.rb", "Manifest"]
|
14
|
+
s.homepage = %q{http://github.com/rikas/c3s}
|
15
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "C3s", "--main", "README.rdoc"]
|
16
|
+
s.require_paths = ["lib"]
|
17
|
+
s.rubyforge_project = %q{c3s}
|
18
|
+
s.rubygems_version = %q{1.3.5}
|
19
|
+
s.summary = %q{C3s library gem.}
|
20
|
+
|
21
|
+
if s.respond_to? :specification_version then
|
22
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
23
|
+
s.specification_version = 3
|
24
|
+
|
25
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
26
|
+
else
|
27
|
+
end
|
28
|
+
else
|
29
|
+
end
|
30
|
+
end
|
data/lib/c3s.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'component_connection'
|
2
|
+
require 'component'
|
3
|
+
require 'configreader'
|
4
|
+
require 'databaseadapter'
|
5
|
+
require 'c3s_logger'
|
6
|
+
|
7
|
+
module C3s
|
8
|
+
def self.included(base)
|
9
|
+
base.extend ClassMethods
|
10
|
+
end
|
11
|
+
|
12
|
+
def ensure_unique(name)
|
13
|
+
begin
|
14
|
+
self[name] = yield
|
15
|
+
end while self.class.exists?(name => self[name])
|
16
|
+
end
|
17
|
+
end
|
data/lib/c3s_logger.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'time'
|
3
|
+
|
4
|
+
module C3s
|
5
|
+
class C3sLogger
|
6
|
+
attr_accessor :logger
|
7
|
+
|
8
|
+
def initialize(log_file)
|
9
|
+
logger = Logger.new(log_file, "weekly")
|
10
|
+
logger.formatter = C3sLogFormatter.new
|
11
|
+
self.logger = logger
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
##
|
17
|
+
# Formats log messages
|
18
|
+
class C3sLogFormatter < Logger::Formatter
|
19
|
+
def call(severity, time, program_name, message)
|
20
|
+
datetime = time.strftime("%Y-%m-%d %H:%M")
|
21
|
+
"\n#{severity[0..2]} [#{datetime}] #{String(message)}"
|
22
|
+
end
|
23
|
+
end
|
data/lib/component.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'thread'
|
2
|
+
begin
|
3
|
+
require 'xmpp4r'
|
4
|
+
rescue Exception => e
|
5
|
+
puts "Fatal Error: #{e}"
|
6
|
+
puts "Please install xmpp4r gem with 'sudo gem install xmpp4r'"
|
7
|
+
exit
|
8
|
+
end
|
9
|
+
require 'xmpp4r/discovery'
|
10
|
+
require 'xmpp4r/pubsub/helper/nodebrowser'
|
11
|
+
require 'publisher'
|
12
|
+
|
13
|
+
module C3s
|
14
|
+
class Component < Jabber::Component
|
15
|
+
##
|
16
|
+
# Component configuration hash
|
17
|
+
attr_accessor :config
|
18
|
+
|
19
|
+
##
|
20
|
+
# Initializes the jabber component
|
21
|
+
#
|
22
|
+
# config:: [Hash] configuration hash
|
23
|
+
def initialize(config)
|
24
|
+
super(config['jid'])
|
25
|
+
self.config = config
|
26
|
+
Jabber::debug = config['debug'].to_s.eql?"true"
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Connects component to jabber server
|
31
|
+
#
|
32
|
+
# Throws ClientAuthenticationFailure
|
33
|
+
def connect
|
34
|
+
super(config['url'], config['port'])
|
35
|
+
if is_connected?
|
36
|
+
auth(config['password'])
|
37
|
+
else
|
38
|
+
raise Exception, "Can't connect"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# Starts listening for packets and waits for activity. Also
|
44
|
+
# provides a callback named handle_iq for especific components
|
45
|
+
# to use.
|
46
|
+
def start
|
47
|
+
super()
|
48
|
+
|
49
|
+
Thread.abort_on_exception = true
|
50
|
+
|
51
|
+
add_iq_callback do |iq|
|
52
|
+
t = Thread.new do
|
53
|
+
handle_iq(iq)
|
54
|
+
end
|
55
|
+
t.join
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
##
|
60
|
+
# Sends an error response to a received IQ packet.
|
61
|
+
# iq:: [Jabber::IQ] the received IQ packet
|
62
|
+
# error:: [Array] an array with error type and error message. The error types should be valid.
|
63
|
+
#
|
64
|
+
# Look at XEP-0086 for explanation:
|
65
|
+
# http://www.xmpp.org/extensions/xep-0086.html
|
66
|
+
def send_error(iq, err)
|
67
|
+
reply = iq.answer
|
68
|
+
reply.type = :error
|
69
|
+
error = Jabber::ErrorResponse.new(err.first, err.last)
|
70
|
+
reply.add error
|
71
|
+
|
72
|
+
send(reply) if iq.type != :error
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
Signal.trap('INT') do
|
77
|
+
puts "Got termination signal"
|
78
|
+
exit!
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module C3s
|
2
|
+
class ComponentConnection
|
3
|
+
##
|
4
|
+
# The configuration file
|
5
|
+
CONFIG_FILE = "component.yml"
|
6
|
+
|
7
|
+
def initialize(componentclass)
|
8
|
+
if !componentclass.superclass.eql?(C3s::Component)
|
9
|
+
puts "ERROR: #{componentclass} is not a valid C3s::Component!"
|
10
|
+
exit
|
11
|
+
end
|
12
|
+
|
13
|
+
reader = C3s::ConfigReader.new(CONFIG_FILE)
|
14
|
+
puts "Reading configurations from '#{CONFIG_FILE}'..."
|
15
|
+
@server_config = reader.section('server')
|
16
|
+
@client_config = reader.section('client')
|
17
|
+
|
18
|
+
# a jid parameter is usefull, so lets merge it on client configuration
|
19
|
+
@client_config.merge!('jid' => @client_config['name']+"."+@server_config['url'])
|
20
|
+
@db_config = reader.section('db')
|
21
|
+
|
22
|
+
puts "Creating new location component with jid '#{@client_config['jid']}'..."
|
23
|
+
@component = componentclass.new(@server_config.merge(@client_config))
|
24
|
+
end
|
25
|
+
|
26
|
+
def start
|
27
|
+
puts "Connecting to database '#{@db_config['database']}'"
|
28
|
+
begin
|
29
|
+
# activerecord connection
|
30
|
+
DatabaseAdapter.new(@db_config)
|
31
|
+
# raises exception if not connected
|
32
|
+
ActiveRecord::Base.retrieve_connection
|
33
|
+
rescue Exception => e
|
34
|
+
puts "Error: #{e}"
|
35
|
+
exit
|
36
|
+
end
|
37
|
+
connect()
|
38
|
+
end
|
39
|
+
|
40
|
+
def connect
|
41
|
+
puts "Connecting to #{@server_config['url']} (port #{@server_config['port']})..."
|
42
|
+
|
43
|
+
begin
|
44
|
+
@component.connect
|
45
|
+
rescue Jabber::ComponentAuthenticationFailure => e
|
46
|
+
puts "Could not authenticate on #{@server_config['url']}: #{e}"
|
47
|
+
exit
|
48
|
+
rescue Errno::ECONNREFUSED => e
|
49
|
+
puts "Connection refused on #{@server_config['url']} (port #{@server_config['port']})"
|
50
|
+
exit
|
51
|
+
rescue Exception => e
|
52
|
+
puts "Error do fim do mundo!"
|
53
|
+
puts e.message
|
54
|
+
exit
|
55
|
+
end
|
56
|
+
puts "External component #{@client_config['jid']} connected successfully."
|
57
|
+
|
58
|
+
@component.on_exception do |e, component, where|
|
59
|
+
$LOG.error "FATAL ERROR"
|
60
|
+
$LOG.error e.message
|
61
|
+
$LOG.error e.backtrace.join("\n")
|
62
|
+
end
|
63
|
+
|
64
|
+
puts "Starting messaging loop..."
|
65
|
+
@component.start()
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.stop
|
69
|
+
puts "Stop aqui!!"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/configreader.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module C3s
|
4
|
+
##
|
5
|
+
# The configuration sections on a standard component yml file
|
6
|
+
SECTIONS = ['client', 'server', 'db']
|
7
|
+
|
8
|
+
class ConfigReader
|
9
|
+
##
|
10
|
+
# Reads the configuration file
|
11
|
+
# file::[String] the configuration file
|
12
|
+
def initialize(file)
|
13
|
+
@config = YAML::load_file(File.join(file))
|
14
|
+
check_config
|
15
|
+
rescue Exception => e
|
16
|
+
fatal_error("Could not find the configuration file '#{file}'")
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# Returns the client configuration for a given section
|
21
|
+
# section::[String] the section to read (client, server or db)
|
22
|
+
def section(section)
|
23
|
+
if !SECTIONS.include?(section)
|
24
|
+
fatal_error("Trying to read invalid section '#{section}'")
|
25
|
+
end
|
26
|
+
config_hash = {}
|
27
|
+
@config[section].each do |key, val|
|
28
|
+
config_hash.merge!({key.to_s => val.to_s})
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
def check_config
|
34
|
+
SECTIONS.each do |section|
|
35
|
+
if !@config[section]
|
36
|
+
fatal_error("Configuration file must contain a '#{section}' section.")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def fatal_error(message)
|
42
|
+
$stderr.puts "Error: #{message}"
|
43
|
+
exit
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
module C3s
|
4
|
+
class DatabaseAdapter
|
5
|
+
def initialize(config)
|
6
|
+
ActiveRecord::Base.colorize_logging = false
|
7
|
+
ActiveRecord::Base.logger = Logger.new(File.open('logs/database.log', 'a'))
|
8
|
+
|
9
|
+
ActiveRecord::Base.establish_connection(
|
10
|
+
:adapter => config['adapter'],
|
11
|
+
:host => config['host'],
|
12
|
+
:username => config['username'],
|
13
|
+
:password => config['password'],
|
14
|
+
:database => config['database'],
|
15
|
+
:encoding => config['encoding']
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/nodetracker.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
module C3s
|
2
|
+
class NodeTracker
|
3
|
+
##
|
4
|
+
# The existing nodes that node tracker knows of
|
5
|
+
@@existing_nodes = []
|
6
|
+
|
7
|
+
##
|
8
|
+
# Adds a node to the existing nodes
|
9
|
+
# node::[String] the node name
|
10
|
+
def self.add_node(node)
|
11
|
+
@@existing_nodes << node
|
12
|
+
end
|
13
|
+
|
14
|
+
##
|
15
|
+
# Checks if a node already exists on node list
|
16
|
+
# node::[String] the node name
|
17
|
+
def self.include?(node)
|
18
|
+
@@existing_nodes.include?(node)
|
19
|
+
end
|
20
|
+
|
21
|
+
##
|
22
|
+
# Returns the existing nodes
|
23
|
+
def self.nodes
|
24
|
+
@@existing_nodes
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/publisher.rb
ADDED
@@ -0,0 +1,80 @@
|
|
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
|
+
@pubsub.create_collection_node(name, config)
|
42
|
+
end
|
43
|
+
|
44
|
+
##
|
45
|
+
# Creates a leaf node to publish if needed
|
46
|
+
# This node must be associated with the collection node
|
47
|
+
# name:: [String] the name of the leaf node
|
48
|
+
# collection:: [String] the collection node that contains the node
|
49
|
+
def create_leaf_node(name, collection)
|
50
|
+
config = Jabber::PubSub::NodeConfig.new
|
51
|
+
config.options = config.options.merge({'pubsub#collection' => collection})
|
52
|
+
@pubsub.create_node(name, config)
|
53
|
+
end
|
54
|
+
|
55
|
+
##
|
56
|
+
# Publishes content to the leaf node
|
57
|
+
# node:: [String] the node to plublish to
|
58
|
+
# content:: [REXML::Element] content xml to publish into node
|
59
|
+
def publish(node, content)
|
60
|
+
item = Jabber::PubSub::Item.new
|
61
|
+
item.add(content)
|
62
|
+
node = [@client.config['name'], node].join(":")
|
63
|
+
@pubsub.publish_item_to(node, item)
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# Checks for existance of a node with a given name. This
|
68
|
+
# node can be a leaf or a collection
|
69
|
+
# name:: [String] the node name
|
70
|
+
def node_exists?(name)
|
71
|
+
return true if NodeTracker.include?(name)
|
72
|
+
nodebrowser = Jabber::PubSub::NodeBrowser.new(@client)
|
73
|
+
nodebrowser.get_info(@service, name)
|
74
|
+
NodeTracker.add_node(name)
|
75
|
+
true
|
76
|
+
rescue Jabber::ServerError => error
|
77
|
+
return false if error.to_s.include?("item-not-found")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: c3s
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ricardo Otero
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-11-30 00:00:00 +00:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: C3s library gem.
|
17
|
+
email: oterosantos@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.rdoc
|
24
|
+
- lib/c3s.rb
|
25
|
+
- lib/c3s_logger.rb
|
26
|
+
- lib/component.rb
|
27
|
+
- lib/component_connection.rb
|
28
|
+
- lib/configreader.rb
|
29
|
+
- lib/databaseadapter.rb
|
30
|
+
- lib/nodetracker.rb
|
31
|
+
- lib/publisher.rb
|
32
|
+
files:
|
33
|
+
- README.rdoc
|
34
|
+
- Rakefile
|
35
|
+
- c3s.gemspec
|
36
|
+
- lib/c3s.rb
|
37
|
+
- lib/c3s_logger.rb
|
38
|
+
- lib/component.rb
|
39
|
+
- lib/component_connection.rb
|
40
|
+
- lib/configreader.rb
|
41
|
+
- lib/databaseadapter.rb
|
42
|
+
- lib/nodetracker.rb
|
43
|
+
- lib/publisher.rb
|
44
|
+
- Manifest
|
45
|
+
has_rdoc: true
|
46
|
+
homepage: http://github.com/rikas/c3s
|
47
|
+
licenses: []
|
48
|
+
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options:
|
51
|
+
- --line-numbers
|
52
|
+
- --inline-source
|
53
|
+
- --title
|
54
|
+
- C3s
|
55
|
+
- --main
|
56
|
+
- README.rdoc
|
57
|
+
require_paths:
|
58
|
+
- lib
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: "1.2"
|
70
|
+
version:
|
71
|
+
requirements: []
|
72
|
+
|
73
|
+
rubyforge_project: c3s
|
74
|
+
rubygems_version: 1.3.5
|
75
|
+
signing_key:
|
76
|
+
specification_version: 3
|
77
|
+
summary: C3s library gem.
|
78
|
+
test_files: []
|
79
|
+
|