cylons 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/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +101 -0
- data/Rakefile +1 -0
- data/bin/cylons +38 -0
- data/cylons.gemspec +40 -0
- data/lib/cylons.rb +57 -0
- data/lib/cylons/active_record_extensions.rb +59 -0
- data/lib/cylons/associations.rb +40 -0
- data/lib/cylons/attributes.rb +31 -0
- data/lib/cylons/configuration.rb +38 -0
- data/lib/cylons/connection.rb +44 -0
- data/lib/cylons/errors.rb +11 -0
- data/lib/cylons/interface.rb +8 -0
- data/lib/cylons/local_registry.rb +30 -0
- data/lib/cylons/railtie.rb +38 -0
- data/lib/cylons/registry_adapter.rb +22 -0
- data/lib/cylons/remote.rb +29 -0
- data/lib/cylons/remote_discovery.rb +39 -0
- data/lib/cylons/remote_proxy.rb +99 -0
- data/lib/cylons/remote_registry.rb +49 -0
- data/lib/cylons/remote_schema.rb +12 -0
- data/lib/cylons/rpc.rb +86 -0
- data/lib/cylons/service.rb +12 -0
- data/lib/cylons/service_manager.rb +44 -0
- data/lib/cylons/version.rb +3 -0
- data/spec/lib/cylons/registry_adapter_spec.rb +9 -0
- data/spec/lib/cylons/remote_registry.rb +7 -0
- data/spec/lib/cylons/service_manager_spec.rb +9 -0
- data/spec/spec_helper.rb +12 -0
- metadata +360 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'cylons'
|
2
|
+
|
3
|
+
module Cylons
|
4
|
+
class Connection
|
5
|
+
class << self
|
6
|
+
@connected ||= false
|
7
|
+
attr_accessor :connected
|
8
|
+
|
9
|
+
alias_method :connected?, :connected
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.validate_configuration
|
13
|
+
raise ::Cylons::RemoteNamespaceNotSet unless ::Cylons.configuration.remote_namespace.present?
|
14
|
+
end
|
15
|
+
|
16
|
+
#todo: FixMe
|
17
|
+
#super hacky.. pass in SKIP_CYLONS=true when running rake tasks for now, ew
|
18
|
+
def self.connect?
|
19
|
+
ENV['SKIP_CYLONS'].present?
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.connect
|
23
|
+
return if connect?
|
24
|
+
validate_configuration
|
25
|
+
::Cylons.logger.info "STARTING DCELL FOR #{::Cylons.configuration.remote_namespace} NOW"
|
26
|
+
|
27
|
+
::Cylons.logger.info "Cylons attempting to connect to registry at #{node_address}"
|
28
|
+
|
29
|
+
::DCell.start :id => ::Cylons.configuration.remote_namespace,
|
30
|
+
:addr => node_address,
|
31
|
+
:registry => registry_hash
|
32
|
+
|
33
|
+
@connected = true
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.node_address
|
37
|
+
"tcp://#{::Cylons.configuration.address}:#{::Cylons.configuration.port}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.registry_hash
|
41
|
+
::Cylons.configuration.registry
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Cylons
|
2
|
+
class CylonsError < StandardError; end
|
3
|
+
class CylonsConfigurationError < CylonsError; end
|
4
|
+
class CylonsRemoteError < CylonsError; end
|
5
|
+
class CylonsRemoteProxyError < CylonsError; end
|
6
|
+
class CylonsRecordNotFound < CylonsRemoteError; end
|
7
|
+
class InvalidRegistryAdapter < CylonsConfigurationError; end
|
8
|
+
class CouldNotConnectToRegistry < CylonsConfigurationError; end
|
9
|
+
class RemoteNamespaceNotSet < CylonsConfigurationError; end
|
10
|
+
class HowDoYouKillThatWhichHasNoLife < CylonsRemoteProxyError; end
|
11
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'dcell'
|
2
|
+
require 'cylons/remote_schema'
|
3
|
+
require 'cylons/remote_registry'
|
4
|
+
|
5
|
+
module Cylons
|
6
|
+
class LocalRegistry
|
7
|
+
|
8
|
+
@remotes ||= []
|
9
|
+
@loaded_remotes ||= []
|
10
|
+
|
11
|
+
class << self
|
12
|
+
attr_accessor :remotes, :loaded_remotes
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.register(klass)
|
16
|
+
@remotes << klass
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.register_class?(namespaced_class_name)
|
20
|
+
!defined?(namespaced_class_name.constantize)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.register_remote_schemas
|
24
|
+
@remotes.each do |remote|
|
25
|
+
::Cylons::RemoteRegistry.register_remote_schema(remote)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'cylons'
|
2
|
+
require 'rails'
|
3
|
+
require 'rails/railtie'
|
4
|
+
require 'active_record'
|
5
|
+
require 'ransack'
|
6
|
+
require 'ransack/search'
|
7
|
+
require 'ransack/adapters/active_record/base'
|
8
|
+
require 'will_paginate'
|
9
|
+
|
10
|
+
module Cylons
|
11
|
+
class Railtie < ::Rails::Railtie
|
12
|
+
config.after_initialize do
|
13
|
+
::Cylons::RemoteDiscovery.load_remotes unless ::Cylons.silence? || ::Cylons::RemoteDiscovery.loaded?
|
14
|
+
end
|
15
|
+
|
16
|
+
::ActiveSupport.on_load(:cylons) do
|
17
|
+
::Cylons::Connection.connect unless ::Cylons.silence? || ::Cylons::RemoteDiscovery.loaded? || ::Cylons::Connection.connected?
|
18
|
+
::Cylons::RemoteDiscovery.load_remotes unless ::Cylons.silence? || ::Cylons::RemoteDiscovery.loaded?
|
19
|
+
end
|
20
|
+
|
21
|
+
#todo: overwrite ransack search method to auto paginate by default, or pull ransack out..
|
22
|
+
::ActiveSupport.on_load(:active_record) do
|
23
|
+
::ActiveRecord::Base.extend ::Ransack::Adapters::ActiveRecord::Base
|
24
|
+
require 'will_paginate/active_record'
|
25
|
+
|
26
|
+
case ::ActiveRecord::VERSION::STRING
|
27
|
+
when /^3\.0\./
|
28
|
+
require 'ransack/adapters/active_record/3.0/context'
|
29
|
+
when /^3\.1\./
|
30
|
+
require 'ransack/adapters/active_record/3.1/context'
|
31
|
+
when /^3\.2\./
|
32
|
+
require 'ransack/adapters/active_record/3.2/context'
|
33
|
+
else
|
34
|
+
require 'ransack/adapters/active_record/context'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'cylons'
|
2
|
+
require 'cylons/interface'
|
3
|
+
|
4
|
+
module Cylons
|
5
|
+
class RegistryAdapter
|
6
|
+
|
7
|
+
VALID_REGISTRY_ADAPTERS = [:zk, :redis].freeze
|
8
|
+
|
9
|
+
#TODO: Add redis adapter support... maybe..
|
10
|
+
|
11
|
+
def self.zk_defaults
|
12
|
+
{:adapter => 'zk', :port => '2181', :server => ::Cylons::Interface.primary}
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.zk(options = {})
|
16
|
+
zk_registry_hash = zk_defaults.dup
|
17
|
+
zk_registry_hash[:server] = ::Cylons.configuration.registry_address if ::Cylons.configuration.registry_address
|
18
|
+
zk_registry_hash[:server] = ::Cylons.configuration.registry_port if ::Cylons.configuration.registry_port
|
19
|
+
zk_registry_hash
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'cylons/remote_registry'
|
2
|
+
require 'cylons/active_record_extensions'
|
3
|
+
|
4
|
+
#todo: fix
|
5
|
+
#think RemoteRegistry needs to be split into a local registry, which the remote registry
|
6
|
+
#is pushed information to, or pulls information from, because the damn dcell wont stop
|
7
|
+
#trying to connect or throwing not configured errors when rake tasks and what not,
|
8
|
+
#need complete separation of local/remote
|
9
|
+
#update, think I mostly fixed issue but leaving note here becaue better separation
|
10
|
+
#still needs to be done.
|
11
|
+
module Cylons
|
12
|
+
module Remote
|
13
|
+
|
14
|
+
def self.included(klass)
|
15
|
+
klass.class_eval do
|
16
|
+
@remote_associations ||= []
|
17
|
+
|
18
|
+
class << self
|
19
|
+
attr_accessor :remote_associations
|
20
|
+
end
|
21
|
+
|
22
|
+
extend ::Cylons::ActiveRecordExtensions::ClassMethods
|
23
|
+
extend ::Cylons::Associations::ClassMethods
|
24
|
+
|
25
|
+
::Cylons::RemoteRegistry.register(klass)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'dcell'
|
2
|
+
require 'cylons/remote_proxy'
|
3
|
+
module Cylons
|
4
|
+
class RemoteDiscovery
|
5
|
+
class << self
|
6
|
+
@loaded = false
|
7
|
+
attr_accessor :loaded, :loaded_remote_class_names
|
8
|
+
alias_method :loaded?, :loaded
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.load_remotes
|
12
|
+
::DCell::Node.all.each do |node|
|
13
|
+
if node.id != ::Cylons.configuration.remote_namespace
|
14
|
+
namespace = node.id
|
15
|
+
remote_class_names = node.actors - [:node_manager, :dcell_server, :info]
|
16
|
+
remote_class_names.select{|name| name.to_s.include?("Service") }.each do |remote_class_name|
|
17
|
+
puts "Building Remote For: #{remote_class_name}"
|
18
|
+
build_remote(namespace, remote_class_name)
|
19
|
+
end if remote_class_names.any?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
@loaded = true
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.build_remote(namespace, remote_class_name)
|
27
|
+
proxy_class_name = remote_class_name.to_s.gsub('Service', '')
|
28
|
+
Object.const_set(proxy_class_name, Class.new(Cylons::RemoteProxy))
|
29
|
+
|
30
|
+
proxy_class = proxy_class_name.constantize
|
31
|
+
proxy_class.load_schema
|
32
|
+
proxy_class.remote = ::DCell::Node[namespace][remote_class_name]
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.remote_proxy_class_name(namespace, remote_class_name)
|
36
|
+
"#{namespace}::#{remote_class_name.to_s}".gsub('Service', '')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'cylons/associations'
|
2
|
+
|
3
|
+
module Cylons
|
4
|
+
|
5
|
+
#this is the local application remote which is dynamically built, from the registry
|
6
|
+
class RemoteProxy
|
7
|
+
include ::ActiveModel::Dirty
|
8
|
+
include ::ActiveModel::AttributeMethods
|
9
|
+
include ActiveAttr::Model
|
10
|
+
include ActiveAttr::MassAssignment
|
11
|
+
include ::Cylons::Attributes
|
12
|
+
extend ::Cylons::Associations::ClassMethods
|
13
|
+
|
14
|
+
def self.load_schema
|
15
|
+
@schema = ::Cylons::RemoteRegistry.get_remote_schema(self.name.downcase)
|
16
|
+
|
17
|
+
@schema.remote_attributes.each do |remote_attribute|
|
18
|
+
attribute remote_attribute.to_sym
|
19
|
+
end
|
20
|
+
|
21
|
+
@schema.remote_associations.each do |association_hash|
|
22
|
+
__send__("build_remote_#{association_hash[:association_type]}_association", association_hash)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class << self
|
27
|
+
attr_accessor :remote, :schema
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_accessor :errors
|
31
|
+
|
32
|
+
def destroy
|
33
|
+
return unless self.attributes["id"]
|
34
|
+
result = self.class.remote.destroy(self.attributes["id"])
|
35
|
+
end
|
36
|
+
|
37
|
+
#have to manually update attributes if id wasnt set, i believe attr_accessible oddity so maybe can rip out later
|
38
|
+
def save
|
39
|
+
if self.attributes["id"]
|
40
|
+
result = self.class.remote.save(self.attributes["id"], self.attributes.with_indifferent_access.slice(*self.changed))
|
41
|
+
self.changed_attributes.clear
|
42
|
+
else
|
43
|
+
result = self.class.remote.save(nil, self.attributes.with_indifferent_access.slice(*self.changed))
|
44
|
+
|
45
|
+
if result.errors.messages.present?
|
46
|
+
self.assign_attributes({:errors => result.errors})
|
47
|
+
else
|
48
|
+
self.assign_attributes(result.attributes)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
result
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.all
|
56
|
+
remote.all
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.count
|
60
|
+
remote.count
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.first
|
64
|
+
remote.first
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.find(id)
|
68
|
+
remote.find(id)
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.last
|
72
|
+
remote.last
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.create(params)
|
76
|
+
remote.create(params)
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.search(params)
|
80
|
+
remote.search(params)
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.scope_by(params)
|
84
|
+
remote.scope_by(params)
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.first_or_create(params)
|
88
|
+
result = remote.scope_by(params).first
|
89
|
+
result = remote.create(params) unless result.present?
|
90
|
+
result
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.first_or_initialize(params)
|
94
|
+
result = remote.scope_by(params).first
|
95
|
+
result ||= remote.new(params) unless result.present?
|
96
|
+
result
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'dcell'
|
2
|
+
require 'cylons/remote_schema'
|
3
|
+
|
4
|
+
module Cylons
|
5
|
+
class RemoteRegistry
|
6
|
+
@remotes ||= []
|
7
|
+
@loaded_remotes ||= []
|
8
|
+
@remote_schemas ||= {}
|
9
|
+
|
10
|
+
class << self
|
11
|
+
attr_accessor :remotes, :loaded_remotes
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.clear_registry
|
15
|
+
::DCell.registry.instance_variable_get("@global_registry").clear
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.register(klass)
|
19
|
+
@remotes << klass
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.register_class?(namespaced_class_name)
|
23
|
+
!defined?(namespaced_class_name.constantize)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.register_schemas
|
27
|
+
@remotes.each do |remote|
|
28
|
+
::Cylons.logger.info remote
|
29
|
+
register_remote_schema(remote)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.remote_schemas
|
34
|
+
::DCell::Global.keys
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.register_remote_schema(klass)
|
38
|
+
::DCell::Global["#{klass.name.downcase}_schema".to_sym] = ::Cylons::RemoteSchema.new(klass)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.remote_schema?(name)
|
42
|
+
::DCell::Global.has_key? "#{name}_schema".to_sym
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.get_remote_schema(name)
|
46
|
+
::DCell::Global["#{name}_schema".to_sym]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Cylons
|
2
|
+
class RemoteSchema
|
3
|
+
attr_accessor :remote_associations, :remote_attributes, :remote_search_scopes, :remote_klass
|
4
|
+
|
5
|
+
def initialize(klass)
|
6
|
+
@remote_attributes ||= klass.attribute_names
|
7
|
+
@remote_associations ||= klass.remote_associations
|
8
|
+
@remote_search_scopes ||= []
|
9
|
+
@remote_klass ||= klass.name.downcase.to_sym
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/cylons/rpc.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'ransack'
|
2
|
+
module Cylons
|
3
|
+
module RPC
|
4
|
+
extend ::ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
include ::ActiveModel::Dirty
|
8
|
+
include ::Cylons::Attributes
|
9
|
+
|
10
|
+
def all
|
11
|
+
execute(:all)
|
12
|
+
end
|
13
|
+
|
14
|
+
def create(params)
|
15
|
+
execute(:create, params)
|
16
|
+
end
|
17
|
+
|
18
|
+
def destroy(id)
|
19
|
+
execute(:destroy, id)
|
20
|
+
end
|
21
|
+
|
22
|
+
def execute(rpc_method, request_params = {})
|
23
|
+
begin
|
24
|
+
@last_response = self.class.model.send(rpc_method.to_sym, request_params)
|
25
|
+
rescue => e
|
26
|
+
puts e.inspect
|
27
|
+
@last_response = {:error => e.message}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def execute_with_args(rpc_method, *args)
|
32
|
+
begin
|
33
|
+
@last_response = self.class.model.send(rpc_method.to_sym, *args)
|
34
|
+
rescue => e
|
35
|
+
puts e.inspect
|
36
|
+
puts e.message
|
37
|
+
puts @last_response.inspect
|
38
|
+
@last_response = {:error => e.message}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def find(id)
|
43
|
+
execute(:find, id)
|
44
|
+
end
|
45
|
+
|
46
|
+
def first
|
47
|
+
execute(:first)
|
48
|
+
end
|
49
|
+
|
50
|
+
def first_or_create(params)
|
51
|
+
execute(:first_or_create, params)
|
52
|
+
end
|
53
|
+
|
54
|
+
def last
|
55
|
+
execute(:last)
|
56
|
+
end
|
57
|
+
|
58
|
+
#todo: Refactor this, hacky
|
59
|
+
def search(params)
|
60
|
+
response = execute(:search, params)
|
61
|
+
|
62
|
+
if response.respond_to?(:result)
|
63
|
+
return response.result.to_a
|
64
|
+
else
|
65
|
+
return response
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def scope_by(params)
|
70
|
+
execute(:scope_by, params).to_a
|
71
|
+
end
|
72
|
+
|
73
|
+
def save(id = nil, attributes)
|
74
|
+
if(id)
|
75
|
+
execute_with_args(:update, id, attributes)
|
76
|
+
else
|
77
|
+
execute(:create, attributes)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def update(attributes)
|
82
|
+
execute_with_args(:update, attributes.keys, attributes.values)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|