c3s 0.2.0

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 ADDED
@@ -0,0 +1,12 @@
1
+ Manifest
2
+ README.rdoc
3
+ Rakefile
4
+ c3s.gemspec
5
+ lib/c3s.rb
6
+ lib/c3s_logger.rb
7
+ lib/component.rb
8
+ lib/component_connection.rb
9
+ lib/configreader.rb
10
+ lib/databaseadapter.rb
11
+ lib/nodetracker.rb
12
+ lib/publisher.rb
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
@@ -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
@@ -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
+