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.
@@ -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