magent 0.0.1

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/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ === 0.0.1 2009-10-02
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
data/Manifest.txt ADDED
@@ -0,0 +1,17 @@
1
+ History.txt
2
+ Manifest.txt
3
+ PostInstall.txt
4
+ README.rdoc
5
+ Rakefile
6
+ bin/magent
7
+ examples/simple/bot.rb
8
+ lib/magent.rb
9
+ lib/magent/actor.rb
10
+ lib/magent/channel.rb
11
+ lib/magent/processor.rb
12
+ lib/magent/push.rb
13
+ lib/magent/utils.rb
14
+ magent.gemspec
15
+ script/console
16
+ test/test_helper.rb
17
+ test/test_magent.rb
data/PostInstall.txt ADDED
File without changes
data/README.rdoc ADDED
@@ -0,0 +1,48 @@
1
+ = magent
2
+
3
+ * http://github.com/dcu/magent
4
+
5
+ == DESCRIPTION:
6
+
7
+ Simple job queue system based on mongodb
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ == SYNOPSIS:
12
+
13
+ see examples/
14
+
15
+ == REQUIREMENTS:
16
+
17
+ * mongodb-ruby-driver
18
+
19
+ == INSTALL:
20
+
21
+ * rake gem
22
+ * sudo gem install pkg/*.gem
23
+
24
+ == LICENSE:
25
+
26
+ (The MIT License)
27
+
28
+ Copyright (c) 2009 David Cuadrado
29
+
30
+ Permission is hereby granted, free of charge, to any person obtaining
31
+ a copy of this software and associated documentation files (the
32
+ 'Software'), to deal in the Software without restriction, including
33
+ without limitation the rights to use, copy, modify, merge, publish,
34
+ distribute, sublicense, and/or sell copies of the Software, and to
35
+ permit persons to whom the Software is furnished to do so, subject to
36
+ the following conditions:
37
+
38
+ The above copyright notice and this permission notice shall be
39
+ included in all copies or substantial portions of the Software.
40
+
41
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
42
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
43
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
44
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
45
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
46
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
47
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
48
+
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ require 'rubygems'
2
+ gem 'hoe', '>= 2.1.0'
3
+ require 'hoe'
4
+ require 'fileutils'
5
+ require './lib/magent'
6
+
7
+ Hoe.plugin :newgem
8
+ # Hoe.plugin :website
9
+ # Hoe.plugin :cucumberfeatures
10
+
11
+ # Generate all the Rake tasks
12
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
13
+ $hoe = Hoe.spec 'magent' do
14
+ self.developer 'David Cuadrado', 'krawek@gmail.com'
15
+ self.post_install_message = 'PostInstall.txt'
16
+ self.rubyforge_name = self.name
17
+ self.extra_deps = [['mongodb-mongo','>= 0.14']]
18
+
19
+ end
20
+
21
+ require 'newgem/tasks'
22
+ Dir['tasks/**/*.rake'].each { |t| load t }
23
+
24
+ # TODO - want other tests/tasks run by default? Add them to the list
25
+ # remove_task :default
26
+ # task :default => [:spec, :features]
27
+
data/bin/magent ADDED
@@ -0,0 +1,139 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.dirname(__FILE__)+"/../lib/"
4
+ require 'magent'
5
+ require 'optparse'
6
+ require 'fileutils'
7
+
8
+ def usage(option_parser, error = nil)
9
+ $stderr.puts error if error
10
+ $stderr.puts option_parser
11
+ exit 1
12
+ end
13
+
14
+ options = {}
15
+
16
+ optparser = OptionParser.new do |opts|
17
+ opts.banner = "Usage: #{$0} [options] <start|stop|restart>\n\nExample: magent -t carl1 -a /path/to/agent.rb -d -P /tmp restart\n\nOptions:"
18
+
19
+ opts.on("-a PATH", "--agent=PATH", "Path to agent") do |o|
20
+ options[:agent] = o
21
+ end
22
+
23
+ opts.on("-t ID", "--identifier=ID", "Identifier") do |o|
24
+ options[:identifier] = o
25
+ end
26
+
27
+ opts.on("-d", "--daemonize", "Run agent as a daemon") do |o|
28
+ options[:daemonize] = true
29
+ end
30
+
31
+ opts.on("-l", "--log-path=PATH", "Log path") do |o|
32
+ options[:log_path] = o
33
+ end
34
+
35
+ opts.on("-P", "--piddir=PATH", "PID dir to use (if daemonized)", "Default: #{options[:piddir]}") do |o|
36
+ options[:piddir] = o
37
+ end
38
+
39
+ opts.on_tail("-h", "--help", "Show this help message.") do
40
+ puts opts
41
+ exit
42
+ end
43
+ end
44
+
45
+ args = []
46
+ begin
47
+ args = optparser.parse!
48
+ rescue => e
49
+ $stderr.puts e
50
+ $stderr.puts optparser
51
+ exit 0
52
+ end
53
+
54
+ if !options[:agent]
55
+ usage(optparser, "Error: --agent is required")
56
+ end
57
+
58
+ load options[:agent]
59
+
60
+ if Magent.current_actor.nil?
61
+ usage(optparser, "Use Magent.register(YourActor.new) to register an actor")
62
+ end
63
+
64
+ class Controller
65
+ def initialize(actor, opts)
66
+ @options = opts
67
+ @actor = actor
68
+
69
+ @options[:log_path] ||= Dir.getwd
70
+
71
+ @identity = @options[:identifier] || Magent::Utils.underscore(actor.class.to_s)
72
+ @identity << "-#{Socket.gethostname.split('.')[0]}"
73
+ end
74
+
75
+ def start
76
+ if @options[:daemonize] && @options[:piddir]
77
+ run_as_daemon
78
+ else
79
+ Magent::Processor.new(@actor).run!
80
+ end
81
+ end
82
+
83
+ def stop
84
+ begin
85
+ pid = File.read(pid_file).to_i
86
+ Process.kill("TERM", pid)
87
+ Process.kill(0, pid)
88
+ Process.wait
89
+ rescue Errno::ECHILD, Errno::ESRCH => e
90
+ $stdout.puts "Process #{pid} has stopped"
91
+ rescue Errno::ENOENT => e
92
+ $stdout.puts "Warning: #{e}"
93
+ ensure
94
+ File.unlink(pid_file) if File.exist?(pid_file)
95
+ end
96
+ end
97
+
98
+ def restart
99
+ begin
100
+ stop
101
+ rescue => e
102
+ $stderr.puts "Warning: #{e}"
103
+ end
104
+ start
105
+ end
106
+
107
+ private
108
+ def run_as_daemon
109
+ daemonize
110
+
111
+ FileUtils.mkpath(@options[:piddir])
112
+ if @options[:piddir]
113
+ File.open(pid_file, "w") do |f|
114
+ f.write(Process.pid)
115
+ end
116
+ end
117
+
118
+ Magent::Processor.new(@actor).run!
119
+ end
120
+
121
+ def pid_file
122
+ @pid_file ||= File.join(@options[:piddir], "magent.#{@identity}.pid")
123
+ end
124
+
125
+ def daemonize
126
+ exit if fork
127
+ Process.setsid
128
+ exit if fork
129
+
130
+ STDIN.reopen "/dev/null"
131
+ STDOUT.reopen "#{@options[:log_path]}/magent.#{@identity}.out", "a"
132
+ STDERR.reopen "#{@options[:log_path]}/magent.#{@identity}.err", "a"
133
+
134
+ STDERR.sync = true
135
+ STDOUT.sync = true
136
+ end
137
+ end
138
+
139
+ Controller.new(Magent.current_actor, options).send(args.shift)
@@ -0,0 +1,32 @@
1
+ $:.unshift File.dirname(__FILE__)+"/../../lib/"
2
+ require 'magent'
3
+
4
+ # Use: magent /path/to/this/file
5
+
6
+ Magent.push("/bot", :echo, "hello, world")
7
+ Magent.push("/bot", :do_task, "File", :exist?, "/etc/passwd")
8
+ Magent.push("/bot", :echo, "Press ctrl+c to close")
9
+
10
+ class Bot
11
+ include Magent::Actor
12
+
13
+ expose :echo, :do_task
14
+
15
+ def echo(payload)
16
+ $stderr.puts payload.inspect
17
+ end
18
+
19
+ def do_task(payload)
20
+ klass, *args = payload
21
+
22
+ result = Object.module_eval(klass).send(*args)
23
+ $stderr.puts "RESULT: #{result}"
24
+ end
25
+
26
+ end
27
+
28
+ Magent.register(Bot.new)
29
+
30
+ if $0 == __FILE__
31
+ Magent::Processor.new(Magent.current_actor).run!
32
+ end
data/lib/magent.rb ADDED
@@ -0,0 +1,32 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'mongo'
5
+ require 'set'
6
+ require 'magent/utils'
7
+ require 'magent/channel'
8
+ require 'magent/push'
9
+ require 'magent/actor'
10
+ require 'magent/processor'
11
+
12
+ module Magent
13
+ VERSION = '0.0.1'
14
+
15
+ def self.connection
16
+ @@connection ||= Mongo::Connection.new
17
+ end
18
+
19
+ def self.connection=(new_connection)
20
+ @@connection = new_connection
21
+ end
22
+
23
+ def self.database=(name)
24
+ @@database = Magent.connection.db(name)
25
+ end
26
+
27
+ def self.database
28
+ @@database
29
+ end
30
+ end
31
+
32
+ Magent.database = 'magent'
@@ -0,0 +1,41 @@
1
+ module Magent
2
+ module Actor
3
+ def self.included(klass)
4
+ klass.class_eval do
5
+ extend Actor::ClassMethods
6
+ end
7
+ end
8
+
9
+ module ClassMethods
10
+ def expose(*methods)
11
+ methods.each do |m|
12
+ actions << m.to_s
13
+ end
14
+ end
15
+
16
+ def actions
17
+ @actions ||= Set.new
18
+ end
19
+
20
+ def can_handle?(action)
21
+ return false if @actions.nil?
22
+ @actions.include?(action.to_s)
23
+ end
24
+
25
+ def channel
26
+ @channel ||= begin
27
+ channel_name = "/"+Magent::Utils.underscore(self.name)
28
+ Channel.new(channel_name)
29
+ end
30
+ end
31
+ end
32
+ end # Actor
33
+
34
+ def self.register(actor)
35
+ @current_actor = actor
36
+ end
37
+
38
+ def self.current_actor
39
+ @current_actor
40
+ end
41
+ end
@@ -0,0 +1,45 @@
1
+ module Magent
2
+ class Channel
3
+ def initialize(name)
4
+ @name = name
5
+
6
+ if !collection.find_one({:_id => @name}, {:fields => [:_id]})
7
+ collection.save({:_id => @name, :messages => []})
8
+ end
9
+ end
10
+
11
+ def enqueue(message, args)
12
+ collection.update({:_id => @name}, {:$push => {:messages => [message, args]}}, :repsert => true)
13
+ end
14
+
15
+ def dequeue
16
+ Magent.database.eval(%@
17
+ function dequeue() {
18
+ return db.eval(function() {
19
+ var q = db.channels.findOne({_id: '#{@name}'});
20
+ var m = q.messages.shift();
21
+ db.channels.save(q); //slow
22
+ return m;
23
+ });
24
+ }
25
+ @)
26
+ end
27
+
28
+ def collection
29
+ self.class.collection
30
+ end
31
+
32
+ def self.collection
33
+ @collection ||= Magent.database.collection("channels")
34
+ end
35
+
36
+ def self.all(&block)
37
+ cursor = collection.find({}, :fields => [:_id])
38
+ if block_given?
39
+ cursor.map {|c| name = c["_id"]; yield name; name }
40
+ else
41
+ cursor.map {|c| c["_id"] }
42
+ end
43
+ end
44
+ end # Channel
45
+ end
@@ -0,0 +1,32 @@
1
+ module Magent
2
+ class Processor
3
+ attr_reader :actor
4
+
5
+ def initialize(actor)
6
+ @actor = actor
7
+
8
+ @actor.class.actions.each do |action|
9
+ if !@actor.respond_to?(action)
10
+ raise ArgumentError, "action '#{action}' is not defined"
11
+ end
12
+ end
13
+ end
14
+
15
+ def run!
16
+ delay = 0
17
+ loop do
18
+ method, payload = @actor.class.channel.dequeue
19
+
20
+ if method.nil?
21
+ delay += 0.1 if delay <= 5
22
+ else
23
+ delay = 0
24
+ $stderr.puts "#{@actor.class}##{method}(#{payload.inspect})"
25
+ @actor.send(method, payload) # TODO: what if method is not defined?
26
+ end
27
+
28
+ sleep delay
29
+ end
30
+ end
31
+ end #Processor
32
+ end
@@ -0,0 +1,13 @@
1
+ module Magent
2
+ def self.push(channel_name, method, *args)
3
+ self.channel(channel_name.to_s).enqueue(method, args)
4
+ end
5
+
6
+ def self.channel(name)
7
+ self.channels[name] ||= Channel.new(name)
8
+ end
9
+
10
+ def self.channels
11
+ @channels ||= {}
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Magent
2
+ module Utils
3
+ def self.underscore(word)
4
+ word.to_s.gsub(/::/, '/').
5
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
6
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').tr("-", "_").downcase
7
+ end
8
+
9
+ def self.camelize(word)
10
+ word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
11
+ end
12
+ end
13
+ end
data/magent.gemspec ADDED
@@ -0,0 +1,40 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{magent}
5
+ s.version = "0.0.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["David Cuadrado"]
9
+ s.date = %q{2009-10-03}
10
+ s.default_executable = %q{magent}
11
+ s.description = %q{Simple job queue system based on mongodb}
12
+ s.email = ["krawek@gmail.com"]
13
+ s.executables = ["magent"]
14
+ s.extra_rdoc_files = ["History.txt", "Manifest.txt", "PostInstall.txt"]
15
+ s.files = ["History.txt", "Manifest.txt", "PostInstall.txt", "README.rdoc", "Rakefile", "bin/magent", "examples/simple/bot.rb", "lib/magent.rb", "lib/magent/actor.rb", "lib/magent/channel.rb", "lib/magent/processor.rb", "lib/magent/push.rb", "lib/magent/utils.rb", "magent.gemspec", "script/console", "test/test_helper.rb", "test/test_magent.rb"]
16
+ s.homepage = %q{http://github.com/dcu/magent}
17
+ s.post_install_message = %q{PostInstall.txt}
18
+ s.rdoc_options = ["--main", "README.rdoc"]
19
+ s.require_paths = ["lib"]
20
+ s.rubyforge_project = %q{magent}
21
+ s.rubygems_version = %q{1.3.5}
22
+ s.summary = %q{Simple job queue system based on mongodb}
23
+ s.test_files = ["test/test_helper.rb", "test/test_magent.rb"]
24
+
25
+ if s.respond_to? :specification_version then
26
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
27
+ s.specification_version = 3
28
+
29
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
30
+ s.add_runtime_dependency(%q<mongodb-mongo>, [">= 0.14"])
31
+ s.add_development_dependency(%q<hoe>, [">= 2.3.3"])
32
+ else
33
+ s.add_dependency(%q<mongodb-mongo>, [">= 0.14"])
34
+ s.add_dependency(%q<hoe>, [">= 2.3.3"])
35
+ end
36
+ else
37
+ s.add_dependency(%q<mongodb-mongo>, [">= 0.14"])
38
+ s.add_dependency(%q<hoe>, [">= 2.3.3"])
39
+ end
40
+ end
data/script/console ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ #libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/init.rb'}"
7
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/magent.rb'}"
8
+ puts "Loading magent gem"
9
+ exec "#{irb} #{libs} --simple-prompt"
@@ -0,0 +1,3 @@
1
+ require 'stringio'
2
+ require 'test/unit'
3
+ require File.dirname(__FILE__) + '/../lib/magent'
@@ -0,0 +1,11 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestMagent < Test::Unit::TestCase
4
+
5
+ def setup
6
+ end
7
+
8
+ def test_truth
9
+ assert true
10
+ end
11
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: magent
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - David Cuadrado
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-04 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: mongodb-mongo
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0.14"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: hoe
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 2.3.3
34
+ version:
35
+ description: Simple job queue system based on mongodb
36
+ email:
37
+ - krawek@gmail.com
38
+ executables:
39
+ - magent
40
+ extensions: []
41
+
42
+ extra_rdoc_files:
43
+ - History.txt
44
+ - Manifest.txt
45
+ - PostInstall.txt
46
+ files:
47
+ - History.txt
48
+ - Manifest.txt
49
+ - PostInstall.txt
50
+ - README.rdoc
51
+ - Rakefile
52
+ - bin/magent
53
+ - examples/simple/bot.rb
54
+ - lib/magent.rb
55
+ - lib/magent/actor.rb
56
+ - lib/magent/channel.rb
57
+ - lib/magent/processor.rb
58
+ - lib/magent/push.rb
59
+ - lib/magent/utils.rb
60
+ - magent.gemspec
61
+ - script/console
62
+ - test/test_helper.rb
63
+ - test/test_magent.rb
64
+ has_rdoc: true
65
+ homepage: http://github.com/dcu/magent
66
+ licenses: []
67
+
68
+ post_install_message: PostInstall.txt
69
+ rdoc_options:
70
+ - --main
71
+ - README.rdoc
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: "0"
79
+ version:
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: "0"
85
+ version:
86
+ requirements: []
87
+
88
+ rubyforge_project: magent
89
+ rubygems_version: 1.3.5
90
+ signing_key:
91
+ specification_version: 3
92
+ summary: Simple job queue system based on mongodb
93
+ test_files:
94
+ - test/test_helper.rb
95
+ - test/test_magent.rb