shift-nanite 0.4.1.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/LICENSE +201 -0
- data/README.rdoc +430 -0
- data/Rakefile +76 -0
- data/TODO +24 -0
- data/bin/nanite-admin +65 -0
- data/bin/nanite-agent +79 -0
- data/bin/nanite-mapper +50 -0
- data/lib/nanite.rb +74 -0
- data/lib/nanite/actor.rb +71 -0
- data/lib/nanite/actor_registry.rb +26 -0
- data/lib/nanite/admin.rb +138 -0
- data/lib/nanite/agent.rb +264 -0
- data/lib/nanite/amqp.rb +58 -0
- data/lib/nanite/cluster.rb +250 -0
- data/lib/nanite/config.rb +112 -0
- data/lib/nanite/console.rb +39 -0
- data/lib/nanite/daemonize.rb +13 -0
- data/lib/nanite/identity.rb +16 -0
- data/lib/nanite/job.rb +104 -0
- data/lib/nanite/local_state.rb +38 -0
- data/lib/nanite/log.rb +66 -0
- data/lib/nanite/log/formatter.rb +39 -0
- data/lib/nanite/mapper.rb +309 -0
- data/lib/nanite/mapper_proxy.rb +67 -0
- data/lib/nanite/nanite_dispatcher.rb +92 -0
- data/lib/nanite/packets.rb +365 -0
- data/lib/nanite/pid_file.rb +52 -0
- data/lib/nanite/reaper.rb +39 -0
- data/lib/nanite/security/cached_certificate_store_proxy.rb +24 -0
- data/lib/nanite/security/certificate.rb +55 -0
- data/lib/nanite/security/certificate_cache.rb +66 -0
- data/lib/nanite/security/distinguished_name.rb +34 -0
- data/lib/nanite/security/encrypted_document.rb +46 -0
- data/lib/nanite/security/rsa_key_pair.rb +53 -0
- data/lib/nanite/security/secure_serializer.rb +68 -0
- data/lib/nanite/security/signature.rb +46 -0
- data/lib/nanite/security/static_certificate_store.rb +35 -0
- data/lib/nanite/security_provider.rb +47 -0
- data/lib/nanite/serializer.rb +52 -0
- data/lib/nanite/state.rb +168 -0
- data/lib/nanite/streaming.rb +125 -0
- data/lib/nanite/util.rb +58 -0
- data/spec/actor_registry_spec.rb +60 -0
- data/spec/actor_spec.rb +77 -0
- data/spec/agent_spec.rb +240 -0
- data/spec/cached_certificate_store_proxy_spec.rb +34 -0
- data/spec/certificate_cache_spec.rb +49 -0
- data/spec/certificate_spec.rb +27 -0
- data/spec/cluster_spec.rb +622 -0
- data/spec/distinguished_name_spec.rb +24 -0
- data/spec/encrypted_document_spec.rb +21 -0
- data/spec/job_spec.rb +251 -0
- data/spec/local_state_spec.rb +130 -0
- data/spec/nanite_dispatcher_spec.rb +136 -0
- data/spec/packet_spec.rb +220 -0
- data/spec/rsa_key_pair_spec.rb +33 -0
- data/spec/secure_serializer_spec.rb +41 -0
- data/spec/serializer_spec.rb +107 -0
- data/spec/signature_spec.rb +30 -0
- data/spec/spec_helper.rb +33 -0
- data/spec/static_certificate_store_spec.rb +30 -0
- data/spec/util_spec.rb +63 -0
- metadata +129 -0
data/Rakefile
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
require "spec/rake/spectask"
|
4
|
+
begin; require 'rubygems'; rescue LoadError; end
|
5
|
+
begin
|
6
|
+
require 'hanna/rdoctask'
|
7
|
+
rescue LoadError
|
8
|
+
require 'rake/rdoctask'
|
9
|
+
end
|
10
|
+
require 'rake/clean'
|
11
|
+
require 'lib/nanite'
|
12
|
+
|
13
|
+
GEM = "nanite"
|
14
|
+
AUTHOR = "Ezra Zygmuntowicz"
|
15
|
+
EMAIL = "ezra@engineyard.com"
|
16
|
+
HOMEPAGE = "http://github.com/ezmobius/nanite"
|
17
|
+
SUMMARY = "self assembling fabric of ruby daemons"
|
18
|
+
|
19
|
+
Dir.glob('tasks/*.rake').each { |r| Rake.application.add_import r }
|
20
|
+
|
21
|
+
spec = Gem::Specification.new do |s|
|
22
|
+
|
23
|
+
s.name = GEM
|
24
|
+
s.version = Nanite::VERSION
|
25
|
+
s.platform = Gem::Platform::RUBY
|
26
|
+
s.has_rdoc = true
|
27
|
+
s.extra_rdoc_files = ["README.rdoc", "LICENSE", 'TODO']
|
28
|
+
s.summary = SUMMARY
|
29
|
+
s.description = s.summary
|
30
|
+
s.author = AUTHOR
|
31
|
+
s.email = EMAIL
|
32
|
+
s.homepage = HOMEPAGE
|
33
|
+
|
34
|
+
s.bindir = "bin"
|
35
|
+
s.executables = %w( nanite-agent nanite-mapper nanite-admin )
|
36
|
+
|
37
|
+
s.add_dependency('amqp', '>= 0.6.0')
|
38
|
+
|
39
|
+
s.require_path = 'lib'
|
40
|
+
s.files = %w(LICENSE README.rdoc Rakefile TODO) + Dir.glob("{lib,bin,specs}/**/*")
|
41
|
+
end
|
42
|
+
|
43
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
44
|
+
pkg.gem_spec = spec
|
45
|
+
end
|
46
|
+
|
47
|
+
task :default => :spec
|
48
|
+
|
49
|
+
task :install => [:package] do
|
50
|
+
sh %{sudo gem install pkg/#{GEM}-#{Nanite::VERSION}}
|
51
|
+
end
|
52
|
+
|
53
|
+
desc "Run unit specs"
|
54
|
+
Spec::Rake::SpecTask.new do |t|
|
55
|
+
t.spec_opts = ["--format", "specdoc", "--colour"]
|
56
|
+
t.spec_files = FileList["spec/**/*_spec.rb"]
|
57
|
+
end
|
58
|
+
|
59
|
+
desc 'Generate RDoc documentation'
|
60
|
+
Rake::RDocTask.new do |rd|
|
61
|
+
rd.title = spec.name
|
62
|
+
rd.rdoc_dir = 'rdoc'
|
63
|
+
rd.main = "README.rdoc"
|
64
|
+
rd.rdoc_files.include("lib/**/*.rb", *spec.extra_rdoc_files)
|
65
|
+
end
|
66
|
+
CLOBBER.include(:clobber_rdoc)
|
67
|
+
|
68
|
+
desc 'Generate and open documentation'
|
69
|
+
task :docs => :rdoc do
|
70
|
+
case RUBY_PLATFORM
|
71
|
+
when /darwin/ ; sh 'open rdoc/index.html'
|
72
|
+
when /mswin|mingw/ ; sh 'start rdoc\index.html'
|
73
|
+
else
|
74
|
+
sh 'firefox rdoc/index.html'
|
75
|
+
end
|
76
|
+
end
|
data/TODO
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
TODO:
|
2
|
+
|
3
|
+
- The examples/crew.rb file is pointing towards a hard coded user dir. Needs to be
|
4
|
+
documented as part of a working example.
|
5
|
+
- examples/async_rack_front/async_rack_front.ru needs to be documented and verified working.
|
6
|
+
|
7
|
+
Ian:
|
8
|
+
- Sync Mapper/Agent#start with nanite-mapper/agent
|
9
|
+
- Update docs for Agent#start and Mapper#start
|
10
|
+
- Update docs in nanite-agent and nanite-mapper
|
11
|
+
- Ensure file transfer works
|
12
|
+
- Check secure stuff still works
|
13
|
+
- Check custom status_proc works
|
14
|
+
- Check documentation, only document public methods
|
15
|
+
- ensure the removal of threaded_actors option doesn't cause shit to block
|
16
|
+
|
17
|
+
- Look into using EM deferables for actors dispatch.
|
18
|
+
- Integration specs that spawn a small cluster of nanites
|
19
|
+
- Rename Ping to Status
|
20
|
+
- request/push should take *args for payload?
|
21
|
+
|
22
|
+
Maybe:
|
23
|
+
- Make mapper queue durable and Results respect :persistent flag on the request
|
24
|
+
- Add a global result received callback
|
data/bin/nanite-admin
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# To work without being installed as a gem:
|
4
|
+
libdir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
5
|
+
$:.unshift libdir unless $:.include? libdir
|
6
|
+
|
7
|
+
require 'nanite'
|
8
|
+
require 'nanite/admin'
|
9
|
+
require 'eventmachine'
|
10
|
+
require 'thin'
|
11
|
+
# IMPORTANT!
|
12
|
+
# You need raggi's patched async version of Thin at the moment to use
|
13
|
+
# the nanite-admin tool.
|
14
|
+
#
|
15
|
+
# raggi's Git repo contains a branch called 'async_for_rack' which contains the
|
16
|
+
# version of Thin you want to install. raggi has apparently removed the 'master'
|
17
|
+
# branch of his Git repo so you may see a warning like that shown below.
|
18
|
+
#
|
19
|
+
# git clone git://github.com/raggi/thin.git thin-raggi-async
|
20
|
+
# ...
|
21
|
+
# warning: remote HEAD refers to nonexistent ref, unable to checkout. <<== IGNORE THIS
|
22
|
+
#
|
23
|
+
# cd thin-raggi-async/
|
24
|
+
# git checkout --track -b async_for_rack origin/async_for_rack
|
25
|
+
# warning: You appear to be on a branch yet to be born. <<== IGNORE THIS
|
26
|
+
# warning: Forcing checkout of origin/async_for_rack. <<== IGNORE THIS
|
27
|
+
# Branch async_for_rack set up to track remote branch refs/remotes/origin/async_for_rack.
|
28
|
+
# Switched to a new branch "async_for_rack"
|
29
|
+
|
30
|
+
# run : 'rake install' to build and install the Thin gem
|
31
|
+
# cd <NANITE>
|
32
|
+
# ./bin/nanite-admin
|
33
|
+
|
34
|
+
# When you need to update this Thin install you should be able to do a 'git pull' on the
|
35
|
+
# "async_for_rack" branch.
|
36
|
+
|
37
|
+
require File.dirname(__FILE__) + '/../lib/nanite'
|
38
|
+
require 'yaml'
|
39
|
+
require "optparse"
|
40
|
+
|
41
|
+
include Nanite::CommonConfig
|
42
|
+
|
43
|
+
options = {}
|
44
|
+
|
45
|
+
opts = OptionParser.new do |opts|
|
46
|
+
opts.banner = "Usage: nanite-admin [-flags] [argument]"
|
47
|
+
opts.define_head "Nanite Admin: a basic control interface for your nanite cluster."
|
48
|
+
opts.separator '*'*80
|
49
|
+
|
50
|
+
setup_mapper_options(opts, options)
|
51
|
+
|
52
|
+
opts.on("--thin-debug", "Set the equivalent of the '--debug' flag on the Thin webserver.") do
|
53
|
+
options[:thin_debug] = true
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
opts.parse!
|
58
|
+
|
59
|
+
EM.run do
|
60
|
+
Nanite.start_mapper(options)
|
61
|
+
Nanite::Log.info "starting nanite-admin"
|
62
|
+
Rack::Handler::Thin.run(Nanite::Admin.new(Nanite.mapper), :Port => 4000) do
|
63
|
+
Thin::Logging.debug = options[:thin_debug]
|
64
|
+
end
|
65
|
+
end
|
data/bin/nanite-agent
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.dirname(__FILE__) + '/../lib/nanite'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
include Nanite::CommonConfig
|
7
|
+
|
8
|
+
options = {}
|
9
|
+
|
10
|
+
opts = OptionParser.new do |opts|
|
11
|
+
opts.banner = "Usage: nanite-agent [-flag] [argument]"
|
12
|
+
opts.define_head "Nanite Agent: ruby process that acts upon messages passed to it by a mapper."
|
13
|
+
opts.separator '*'*80
|
14
|
+
|
15
|
+
setup_common_options(opts, options, 'agent')
|
16
|
+
|
17
|
+
opts.on("-n", "--nanite NANITE_ROOT", "Specify the root of your nanite agent project.") do |nanite|
|
18
|
+
options[:root] = nanite
|
19
|
+
end
|
20
|
+
|
21
|
+
opts.on("--ping-time PINGTIME", "Specify how often the agents contacts the mapper") do |ping|
|
22
|
+
options[:ping_time] = ping
|
23
|
+
end
|
24
|
+
|
25
|
+
opts.on("--actors-dir DIR", "Path to directory containing actors (NANITE_ROOT/actors by default)") do |dir|
|
26
|
+
options[:actors_dir] = dir
|
27
|
+
end
|
28
|
+
|
29
|
+
opts.on("--actors ACTORS", "Comma separated list of actors to load (all ruby files in actors directory by default)") do |a|
|
30
|
+
options[:actors] = a.split(',')
|
31
|
+
end
|
32
|
+
|
33
|
+
opts.on("--initrb FILE", "Path to agent initialization file (NANITE_ROOT/init.rb by default)") do |initrb|
|
34
|
+
options[:initrb] = initrb
|
35
|
+
end
|
36
|
+
|
37
|
+
opts.on("--single-threaded", "Run all operations in one thread") do
|
38
|
+
options[:single_threaded] = true
|
39
|
+
end
|
40
|
+
|
41
|
+
opts.on("--threadpool COUNT", Integer, "Number of threads to run all operations in") do |tps|
|
42
|
+
options[:threadpool_size] = tps
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
opts.parse!
|
48
|
+
|
49
|
+
if ARGV[0] == 'stop' || ARGV[0] == 'status'
|
50
|
+
agent = Nanite::Agent.new(options)
|
51
|
+
pid_file = Nanite::PidFile.new(agent.identity, agent.options)
|
52
|
+
unless pid = pid_file.read_pid
|
53
|
+
puts "#{pid_file} not found"
|
54
|
+
exit
|
55
|
+
end
|
56
|
+
if ARGV[0] == 'stop'
|
57
|
+
puts "Stopping nanite agent #{agent.identity} (pid #{pid})"
|
58
|
+
begin
|
59
|
+
Process.kill('TERM', pid)
|
60
|
+
rescue Errno::ESRCH
|
61
|
+
puts "Process does not exist (pid #{pid})"
|
62
|
+
exit
|
63
|
+
end
|
64
|
+
puts 'Done.'
|
65
|
+
else
|
66
|
+
if Process.getpgid(pid) != -1
|
67
|
+
psdata = `ps up #{pid}`.split("\n").last.split
|
68
|
+
memory = (psdata[5].to_i / 1024)
|
69
|
+
puts "The agent is alive, using #{memory}MB of memory"
|
70
|
+
else
|
71
|
+
puts "The agent is not running but has a stale pid file at #{pid_file}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
exit
|
75
|
+
end
|
76
|
+
|
77
|
+
EM.run do
|
78
|
+
Nanite.start_agent(options)
|
79
|
+
end
|
data/bin/nanite-mapper
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.dirname(__FILE__) + '/../lib/nanite'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
include Nanite::CommonConfig
|
7
|
+
|
8
|
+
options = {}
|
9
|
+
|
10
|
+
opts = OptionParser.new do |opts|
|
11
|
+
opts.banner = "Usage: nanite-mapper [-flags] [argument]"
|
12
|
+
opts.define_head "Nanite Mapper: clustered head unit for self assembling cluster of ruby processes."
|
13
|
+
opts.separator '*'*80
|
14
|
+
|
15
|
+
setup_mapper_options(opts, options)
|
16
|
+
end
|
17
|
+
|
18
|
+
opts.parse!
|
19
|
+
|
20
|
+
if ARGV[0] == 'stop' || ARGV[0] == 'status'
|
21
|
+
mapper = Nanite::Mapper.new(options)
|
22
|
+
pid_file = Nanite::PidFile.new(mapper.identity, mapper.options)
|
23
|
+
unless pid = pid_file.read_pid
|
24
|
+
puts "#{pid_file} not found"
|
25
|
+
exit
|
26
|
+
end
|
27
|
+
if ARGV[0] == 'stop'
|
28
|
+
puts "Stopping nanite mapper #{mapper.identity} (pid #{pid})"
|
29
|
+
begin
|
30
|
+
Process.kill('TERM', pid)
|
31
|
+
rescue Errno::ESRCH
|
32
|
+
puts "Process does not exist (pid #{pid})"
|
33
|
+
exit
|
34
|
+
end
|
35
|
+
puts 'Done.'
|
36
|
+
else
|
37
|
+
if Process.getpgid(pid) != -1
|
38
|
+
psdata = `ps up #{pid}`.split("\n").last.split
|
39
|
+
memory = (psdata[5].to_i / 1024)
|
40
|
+
puts "The mapper is alive, using #{memory}MB of memory"
|
41
|
+
else
|
42
|
+
puts "The mapper is not running but has a stale pid file at #{pid_file}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
exit
|
46
|
+
end
|
47
|
+
|
48
|
+
EM.run do
|
49
|
+
Nanite.start_mapper(options)
|
50
|
+
end
|
data/lib/nanite.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'amqp'
|
3
|
+
require 'mq'
|
4
|
+
require 'json'
|
5
|
+
require 'logger'
|
6
|
+
require 'yaml'
|
7
|
+
require 'openssl'
|
8
|
+
|
9
|
+
$:.unshift File.dirname(__FILE__)
|
10
|
+
require 'nanite/amqp'
|
11
|
+
require 'nanite/util'
|
12
|
+
require 'nanite/config'
|
13
|
+
require 'nanite/packets'
|
14
|
+
require 'nanite/identity'
|
15
|
+
require 'nanite/console'
|
16
|
+
require 'nanite/daemonize'
|
17
|
+
require 'nanite/pid_file'
|
18
|
+
require 'nanite/job'
|
19
|
+
require 'nanite/mapper'
|
20
|
+
require 'nanite/actor'
|
21
|
+
require 'nanite/actor_registry'
|
22
|
+
require 'nanite/streaming'
|
23
|
+
require 'nanite/nanite_dispatcher'
|
24
|
+
require 'nanite/agent'
|
25
|
+
require 'nanite/cluster'
|
26
|
+
require 'nanite/reaper'
|
27
|
+
require 'nanite/log'
|
28
|
+
require 'nanite/mapper_proxy'
|
29
|
+
require 'nanite/security_provider'
|
30
|
+
require 'nanite/security/cached_certificate_store_proxy'
|
31
|
+
require 'nanite/security/certificate'
|
32
|
+
require 'nanite/security/certificate_cache'
|
33
|
+
require 'nanite/security/distinguished_name'
|
34
|
+
require 'nanite/security/encrypted_document'
|
35
|
+
require 'nanite/security/rsa_key_pair'
|
36
|
+
require 'nanite/security/secure_serializer'
|
37
|
+
require 'nanite/security/signature'
|
38
|
+
require 'nanite/security/static_certificate_store'
|
39
|
+
require 'nanite/serializer'
|
40
|
+
|
41
|
+
module Nanite
|
42
|
+
VERSION = '0.4.1.2' unless defined?(Nanite::VERSION)
|
43
|
+
|
44
|
+
class MapperNotRunning < StandardError; end
|
45
|
+
|
46
|
+
class << self
|
47
|
+
attr_reader :mapper, :agent
|
48
|
+
|
49
|
+
def start_agent(options = {})
|
50
|
+
@agent = Nanite::Agent.start(options)
|
51
|
+
end
|
52
|
+
|
53
|
+
def start_mapper(options = {})
|
54
|
+
@mapper = Nanite::Mapper.start(options)
|
55
|
+
end
|
56
|
+
|
57
|
+
def request(*args, &blk)
|
58
|
+
ensure_mapper
|
59
|
+
@mapper.request(*args, &blk)
|
60
|
+
end
|
61
|
+
|
62
|
+
def push(*args)
|
63
|
+
ensure_mapper
|
64
|
+
@mapper.push(*args)
|
65
|
+
end
|
66
|
+
|
67
|
+
def ensure_mapper
|
68
|
+
@mapper ||= MapperProxy.instance
|
69
|
+
unless @mapper
|
70
|
+
raise MapperNotRunning.new('A mapper needs to be started via Nanite.start_mapper')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/nanite/actor.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
module Nanite
|
2
|
+
# This mixin provides Nanite actor functionality.
|
3
|
+
#
|
4
|
+
# To use it simply include it your class containing the functionality to be exposed:
|
5
|
+
#
|
6
|
+
# class Foo
|
7
|
+
# include Nanite::Actor
|
8
|
+
# expose :bar
|
9
|
+
#
|
10
|
+
# def bar(payload)
|
11
|
+
# # ...
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# end
|
15
|
+
module Actor
|
16
|
+
|
17
|
+
def self.included(base)
|
18
|
+
base.class_eval do
|
19
|
+
include Nanite::Actor::InstanceMethods
|
20
|
+
extend Nanite::Actor::ClassMethods
|
21
|
+
end # base.class_eval
|
22
|
+
end # self.included
|
23
|
+
|
24
|
+
module ClassMethods
|
25
|
+
def default_prefix
|
26
|
+
to_s.to_const_path
|
27
|
+
end
|
28
|
+
|
29
|
+
def expose(*meths)
|
30
|
+
@exposed ||= []
|
31
|
+
meths.each do |meth|
|
32
|
+
@exposed << meth unless @exposed.include?(meth)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def provides_for(prefix)
|
37
|
+
return [] unless @exposed
|
38
|
+
@exposed.select do |meth|
|
39
|
+
if instance_methods.include?(meth.to_s) or instance_methods.include?(meth.to_sym)
|
40
|
+
true
|
41
|
+
else
|
42
|
+
Nanite::Log.warn("Exposing non-existing method #{meth} in actor #{name}")
|
43
|
+
false
|
44
|
+
end
|
45
|
+
end.map {|meth| "/#{prefix}/#{meth}".squeeze('/')}
|
46
|
+
end
|
47
|
+
|
48
|
+
def on_exception(proc = nil, &blk)
|
49
|
+
raise 'No callback provided for on_exception' unless proc || blk
|
50
|
+
@exception_callback = proc || blk
|
51
|
+
end
|
52
|
+
|
53
|
+
def exception_callback
|
54
|
+
@exception_callback
|
55
|
+
end
|
56
|
+
|
57
|
+
end # ClassMethods
|
58
|
+
|
59
|
+
module InstanceMethods
|
60
|
+
# send nanite request to another agent (through the mapper)
|
61
|
+
def request(*args, &blk)
|
62
|
+
MapperProxy.instance.request(*args, &blk)
|
63
|
+
end
|
64
|
+
|
65
|
+
def push(*args)
|
66
|
+
MapperProxy.instance.push(*args)
|
67
|
+
end
|
68
|
+
end # InstanceMethods
|
69
|
+
|
70
|
+
end # Actor
|
71
|
+
end # Nanite
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Nanite
|
2
|
+
class ActorRegistry
|
3
|
+
attr_reader :actors
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@actors = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def register(actor, prefix)
|
10
|
+
raise ArgumentError, "#{actor.inspect} is not a Nanite::Actor subclass instance" unless Nanite::Actor === actor
|
11
|
+
log_msg = "[actor] #{actor.class.to_s}"
|
12
|
+
log_msg += ", prefix #{prefix}" if prefix && !prefix.empty?
|
13
|
+
Nanite::Log.info(log_msg)
|
14
|
+
prefix ||= actor.class.default_prefix
|
15
|
+
actors[prefix.to_s] = actor
|
16
|
+
end
|
17
|
+
|
18
|
+
def services
|
19
|
+
actors.map {|prefix, actor| actor.class.provides_for(prefix) }.flatten.uniq
|
20
|
+
end
|
21
|
+
|
22
|
+
def actor_for(prefix)
|
23
|
+
actor = actors[prefix]
|
24
|
+
end
|
25
|
+
end # ActorRegistry
|
26
|
+
end # Nanite
|