c3s 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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
+