distribunaut 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2010 markbates
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,67 @@
1
+ ==Examples
2
+
3
+ ===Example #1
4
+
5
+ <pre>
6
+ <code>
7
+
8
+ # 'Server' application
9
+ require 'distribunaut'
10
+
11
+ configatron.distribunaut.app_name = :user_app
12
+
13
+ class User
14
+ include Distribunaut::Distributable
15
+
16
+ attr_accessor :username
17
+
18
+ def self.hi
19
+ 'hello!!!'
20
+ end
21
+
22
+ def save
23
+ puts "Saving: #{self.inspect}"
24
+ end
25
+
26
+ end
27
+
28
+ DRb.thread.join
29
+
30
+ </code>
31
+ </pre>
32
+ <pre>
33
+ <code>
34
+
35
+ # 'Client' application
36
+ require 'distribunaut'
37
+
38
+ puts Distribunaut::Distributed::User.hi
39
+
40
+ User = Distribunaut::Distributed::User
41
+
42
+ puts User.hi
43
+
44
+ user = User.new
45
+
46
+ puts user.inspect
47
+
48
+ user.username = 'markbates'
49
+
50
+ puts user.inspect
51
+
52
+ user.save
53
+
54
+ # Saving: #<User:0x18ef764 @username="markbates">
55
+
56
+ # hello!!!
57
+ # hello!!!
58
+ # #<DRb::DRbObject:0x192e6a8 @ref=13073330, @uri="druby://192.168.1.2:56836">|#<User:0x18ef764>
59
+ # #<DRb::DRbObject:0x192e6a8 @ref=13073330, @uri="druby://192.168.1.2:56836">|#<User:0x18ef764 @username="markbates">
60
+
61
+ </code>
62
+ </pre>
63
+
64
+ ===Contributors
65
+
66
+ * Mark Bates
67
+ * Josh Schairbaum
@@ -0,0 +1,33 @@
1
+ #!/usr/local/bin/ruby
2
+ # require 'rubygems'
3
+ require 'daemons'
4
+ require 'rinda/ring'
5
+ require 'rinda/tuplespace'
6
+ require 'fileutils'
7
+ require 'optparse'
8
+ require 'optparse/time'
9
+ require 'ostruct'
10
+
11
+ options = OpenStruct.new
12
+ opts = OptionParser.new do |opts|
13
+ opts.banner = <<-BANNER
14
+ Usage: distribunaut_ring_server <command>
15
+ Available commands are:
16
+
17
+ - start
18
+ - stop
19
+ - restart
20
+
21
+ BANNER
22
+ end
23
+
24
+ opts.parse!(ARGV)
25
+
26
+ FileUtils.mkdir_p(File.join("tmp", "pids"))
27
+
28
+ Daemons.run_proc('distribunaut_ring_server', {:dir_mode => :normal, :dir => File.join("tmp", "pids"), :monitor => true, :multiple => false}) do
29
+ puts 'Starting distribunaut_ring_server...'
30
+ DRb.start_service
31
+ Rinda::RingServer.new(Rinda::TupleSpace.new)
32
+ DRb.thread.join
33
+ end
@@ -0,0 +1,22 @@
1
+ require 'configatron'
2
+ require 'drb/drb'
3
+ require 'drb/acl'
4
+ require 'rinda/ring'
5
+ require 'rinda/tuplespace'
6
+ require 'addressable/uri'
7
+ require 'active_support/i18n'
8
+ require 'active_support/inflector'
9
+
10
+ base = File.join(File.dirname(__FILE__), 'distribunaut')
11
+
12
+ configatron.distribunaut.set_default(:app_name, nil)
13
+ configatron.distribunaut.set_default(:timeout, 0)
14
+
15
+ # load *.rb files
16
+ Dir.glob(File.join(base, "**", "*.rb")).each do |f|
17
+ require(f)
18
+ end
19
+
20
+ # Make sure no one can call eval() and related
21
+ # methods remotely!
22
+ $SAFE = 1 unless $SAFE > 0
@@ -0,0 +1,57 @@
1
+ module Distribunaut # :nodoc:
2
+ # Include this module into any class it will instantly register that class with
3
+ # the distribunaut_ring_server. The class will be registered with the name of the class
4
+ # and the distribunaut.distributed_app_name configured in your config/configatron/*.rb file.
5
+ # If the distribunaut.distributed_app_name configuration parameter is nil it will raise
6
+ # an Distribunaut::Distributed::Errors::ApplicationNameUndefined exception.
7
+ #
8
+ # Example:
9
+ # class User
10
+ # include Distribunaut::Distributable
11
+ # def name
12
+ # "mark"
13
+ # end
14
+ # end
15
+ #
16
+ # Distribunaut::Distributed::User.new.name # => "mark"
17
+ module Distributable
18
+
19
+ def self.included(base) # :nodoc:
20
+ raise Distribunaut::Distributed::Errors::ApplicationNameUndefined.new if configatron.distribunaut.app_name.nil?
21
+ base.class_eval do
22
+ include ::DRbUndumped
23
+ end
24
+ c_name = base.name.gsub('::', '_')
25
+ eval %{
26
+ class ::Distribunaut::Distributed::#{c_name}Proxy
27
+ include Singleton
28
+ include DRbUndumped
29
+
30
+ def method_missing(sym, *args)
31
+ #{base}.send(sym, *args)
32
+ end
33
+
34
+ undef :id if method_defined?(:id)
35
+ undef :inspect if method_defined?(:inspect)
36
+ undef :to_s if method_defined?(:to_s)
37
+
38
+ def borrow(&block)
39
+ Distribunaut::Utils::Rinda.borrow(:space => :#{base},
40
+ :object => self,
41
+ :description => "#{base} Service",
42
+ :app_name => configatron.distribunaut.app_name.to_sym) do |tuple|
43
+ yield tuple.object
44
+ end
45
+ end
46
+
47
+ end
48
+ }
49
+ obj = "Distribunaut::Distributed::#{c_name}Proxy".constantize.instance
50
+ Distribunaut::Utils::Rinda.register_or_renew(:space => "#{base}".to_sym,
51
+ :object => obj,
52
+ :description => "#{base} Service",
53
+ :app_name => configatron.distribunaut.app_name.to_sym)
54
+ end
55
+
56
+ end # Distributable
57
+ end # Distribunaut
@@ -0,0 +1,24 @@
1
+ module Distribunaut # :nodoc:
2
+ module Distributed # :nodoc:
3
+
4
+ # Looks up and tries to find the missing constant using the ring server.
5
+ def self.const_missing(const)
6
+ Distribunaut::Utils::Rinda.read(:space => "#{const}".to_sym)
7
+ end
8
+
9
+ # Allows for the specific lookup of services on the ring server
10
+ #
11
+ # Examples:
12
+ # Distribunaut::Utils::Rinda.register_or_renew(:app_name => :app_1, :space => :Test, :object => "Hello World!")
13
+ # Distribunaut::Utils::Rinda.register_or_renew(:app_name => :app_2, :space => :Test, :object => "Hello WORLD!")
14
+ # Distribunaut::Distributed.lookup("distributed://app_1/Test") # => "Hello World!"
15
+ # Distribunaut::Distributed.lookup("distributed://app_2/Test") # => "Hello WORLD!"
16
+ def self.lookup(address)
17
+ uri = Addressable::URI.parse(address)
18
+ path = uri.path[1..uri.path.size] # remove the first slash
19
+ host = uri.host
20
+ Distribunaut::Utils::Rinda.read(:space => path.to_sym, :app_name => host.to_sym)
21
+ end
22
+
23
+ end # Distributed
24
+ end # Distribunaut
@@ -0,0 +1,26 @@
1
+ module Distribunaut
2
+ module Distributed # :nodoc:
3
+ module Errors # :nodoc:
4
+
5
+ # Raised when an unknown distributed application is referenced.
6
+ class UnknownApplication < StandardError
7
+ # Takes the application name.
8
+ def initialize(app_name)
9
+ super("APPLICATION: #{app_name} is not a known/registered distributed application.")
10
+ end
11
+ end
12
+
13
+ # Raised when an application doesn't declare it's application name for use in a distributed system.
14
+ class ApplicationNameUndefined < StandardError
15
+ end
16
+
17
+ # Raised when the distributed path is not a well formed addressable format
18
+ class InvalidAddressableURIFormat < StandardError
19
+ def inititalize(msg)
20
+ super("Invalid addressable format: #{msg}")
21
+ end
22
+ end
23
+
24
+ end # Errors
25
+ end # Distributed
26
+ end # Distribunaut
@@ -0,0 +1,15 @@
1
+ module DRb # :nodoc:
2
+ class DRbObject # :nodoc:
3
+
4
+ alias_method :_original_inspect, :inspect unless method_defined?(:_original_inspect)
5
+
6
+ def inspect
7
+ "#{_original_inspect}|#{method_missing(:inspect)}"
8
+ end
9
+
10
+ undef :id if method_defined?(:id)
11
+ undef :kind_of? if method_defined?(:kind_of?)
12
+ undef :is_a? if method_defined?(:is_a?)
13
+
14
+ end
15
+ end
@@ -0,0 +1,34 @@
1
+ require 'rinda/ring'
2
+ namespace :distribunaut do
3
+ namespace :ring_server do
4
+
5
+ desc "Start the Rinda ring server"
6
+ task :start do
7
+ `distribunaut_ring_server start`
8
+ end
9
+
10
+ desc "Stop the Rinda ring server"
11
+ task :stop do
12
+ `distribunaut_ring_server stop`
13
+ end
14
+
15
+ desc "Restart the Rinda ring server"
16
+ task :restart => [:stop, :start]
17
+
18
+ namespace :services do
19
+
20
+ desc "Lists all services on the ring server"
21
+ task :list do
22
+ require 'distribunaut'
23
+ puts "Services on #{Distribunaut::Utils::Rinda.ring_server.__drburi}"
24
+ services = Distribunaut::Utils::Rinda.available_services
25
+ services.each do |service|
26
+ # puts "#{service[0]}: #{service[1]} on #{service[2].__drburi} - #{service[3]}"
27
+ puts "#{service.app_name}: #{service.space} on #{service.object.__drburi} - #{service.description}"
28
+ end
29
+ end
30
+
31
+ end # services
32
+
33
+ end # ring_server
34
+ end # distribunaut
@@ -0,0 +1,42 @@
1
+ module Distribunaut # :nodoc:
2
+ class Tuple
3
+
4
+ attr_accessor :app_name
5
+ attr_accessor :space
6
+ attr_accessor :object
7
+ attr_accessor :description
8
+ attr_accessor :timeout
9
+
10
+ def initialize(values = {})
11
+ values.each do |k, v|
12
+ self.send("#{k}=", v)
13
+ end
14
+ end
15
+
16
+ def to_array
17
+ [self.app_name, self.space, self.object, self.description]
18
+ end
19
+
20
+ def to_search_array
21
+ [self.app_name, self.space, nil, nil]
22
+ end
23
+
24
+ def to_s
25
+ self.to_array.inspect
26
+ end
27
+
28
+ class << self
29
+
30
+ def from_array(ar)
31
+ tuple = Distribunaut::Tuple.new
32
+ tuple.app_name = ar[0]
33
+ tuple.space = ar[1]
34
+ tuple.object = ar[2]
35
+ tuple.description = ar[3]
36
+ return tuple
37
+ end
38
+
39
+ end
40
+
41
+ end # Tuple
42
+ end # Distribunaut
@@ -0,0 +1,83 @@
1
+ module Distribunaut
2
+ module Utils # :nodoc:
3
+ module Rinda
4
+
5
+ class << self
6
+
7
+ def register_or_renew(values = {})
8
+ tuple = build_tuple(values)
9
+ begin
10
+ ring_server.take(tuple.to_search_array, tuple.timeout)
11
+ rescue ::Rinda::RequestExpiredError => e
12
+ # it's ok that it expired. It could be that it was never registered.
13
+ end
14
+ register(values)
15
+ end
16
+
17
+ def register(values = {})
18
+ tuple = build_tuple(values)
19
+ ring_server.write(tuple.to_array, ::Rinda::SimpleRenewer.new)
20
+ end
21
+
22
+ def ring_server
23
+ if configatron.distribunaut.retrieve(:acl, nil)
24
+ acl = ACL.new(configatron.distribunaut.acl)
25
+ DRb.install_acl(acl)
26
+ end
27
+ ::DRb.start_service
28
+ rs = ::Rinda::RingFinger.primary
29
+ rs
30
+ end
31
+
32
+ def read(values = {})
33
+ tuple = build_tuple(values)
34
+ results = ring_server.read(tuple.to_array, tuple.timeout)
35
+ tuple = Distribunaut::Tuple.from_array(results)
36
+ tuple.object
37
+ end
38
+
39
+ def borrow(values = {}, &block)
40
+ tuple = build_tuple(values)
41
+ results = ring_server.take(tuple.to_array, tuple.timeout)
42
+ tuple = Distribunaut::Tuple.from_array(results)
43
+ tuple.space = "#{tuple.space}-onloan-#{Time.now}".to_sym
44
+ register(tuple)
45
+ begin
46
+ yield tuple if block_given?
47
+ rescue Exception => e
48
+ raise e
49
+ ensure
50
+ # (.+)-onloan-.+$
51
+ tuple.space.to_s.match(/(.+)-onloan-.+$/)
52
+ tuple.space = $1.to_sym
53
+ register(tuple)
54
+ end
55
+ end
56
+
57
+ def available_services
58
+ ring_server = self.ring_server
59
+ all = ring_server.read_all([nil, nil, nil, nil])
60
+ services = []
61
+ all.each do |service|
62
+ services << Distribunaut::Tuple.from_array(service)
63
+ end
64
+ services
65
+ end
66
+
67
+ def remove_all_services!
68
+ available_services.each do |service|
69
+ ring_server.take(service.to_array)
70
+ end
71
+ end
72
+
73
+ private
74
+ def build_tuple(values = {})
75
+ return values if values.is_a?(Distribunaut::Tuple)
76
+ Distribunaut::Tuple.new({:timeout => configatron.distribunaut.timeout}.merge(values))
77
+ end
78
+
79
+ end # class << self
80
+
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,4 @@
1
+ # load tasks
2
+ Dir.glob(File.join(File.dirname(__FILE__), 'distribunaut', 'tasks', '*.rake')).each do |f|
3
+ load(f)
4
+ end
metadata ADDED
@@ -0,0 +1,149 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: distribunaut
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 3
8
+ - 0
9
+ version: 0.3.0
10
+ platform: ruby
11
+ authors:
12
+ - markbates
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-12-09 00:00:00 -05:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: configatron
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 2
29
+ - 3
30
+ - 0
31
+ version: 2.3.0
32
+ type: :runtime
33
+ prerelease: false
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: addressable
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ segments:
43
+ - 2
44
+ - 0
45
+ - 0
46
+ version: 2.0.0
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: daemons
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ segments:
58
+ - 1
59
+ - 0
60
+ - 10
61
+ version: 1.0.10
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: *id003
65
+ - !ruby/object:Gem::Dependency
66
+ name: activesupport
67
+ requirement: &id004 !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ segments:
73
+ - 3
74
+ - 0
75
+ - 3
76
+ version: 3.0.3
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: *id004
80
+ - !ruby/object:Gem::Dependency
81
+ name: i18n
82
+ requirement: &id005 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ segments:
88
+ - 0
89
+ version: "0"
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: *id005
93
+ description: "distribunaut was developed by: markbates"
94
+ email: mark+github@markbates.com
95
+ executables:
96
+ - distribunaut_ring_server
97
+ extensions: []
98
+
99
+ extra_rdoc_files:
100
+ - README
101
+ - LICENSE
102
+ files:
103
+ - lib/distribunaut/distributable.rb
104
+ - lib/distribunaut/distributed.rb
105
+ - lib/distribunaut/errors/errors.rb
106
+ - lib/distribunaut/extensions/drb_object.rb
107
+ - lib/distribunaut/tasks/ring_server_tasks.rake
108
+ - lib/distribunaut/tuple.rb
109
+ - lib/distribunaut/utils/rinda.rb
110
+ - lib/distribunaut.rb
111
+ - lib/distribunaut_tasks.rb
112
+ - README
113
+ - LICENSE
114
+ - bin/distribunaut_ring_server
115
+ has_rdoc: true
116
+ homepage: http://www.metabates.com
117
+ licenses: []
118
+
119
+ post_install_message:
120
+ rdoc_options: []
121
+
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ none: false
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ hash: 875812335140152363
130
+ segments:
131
+ - 0
132
+ version: "0"
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ none: false
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ segments:
139
+ - 0
140
+ version: "0"
141
+ requirements: []
142
+
143
+ rubyforge_project:
144
+ rubygems_version: 1.3.7
145
+ signing_key:
146
+ specification_version: 3
147
+ summary: distribunaut
148
+ test_files: []
149
+