cylons 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,8 @@
1
+ require 'socket'
2
+ module Cylons
3
+ class Interface
4
+ def self.primary
5
+ ::IPSocket.getaddress(::Socket.gethostname)
6
+ end
7
+ end
8
+ 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