resourcemq 0.0.1.alpha

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2013 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,3 @@
1
+ = ResoureMQ
2
+
3
+ This project rocks and uses MIT-LICENSE.
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'ResourceMQ'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+
18
+
19
+
20
+ Bundler::GemHelper.install_tasks
21
+
data/lib/resourcemq.rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'ffi-rzmq'
2
+ require 'active_model_serializers'
3
+ require 'virtus'
4
+
5
+ require 'resourcemq/version'
6
+ require 'resourcemq/engine'
7
+ require 'resourcemq/service'
8
+ require 'resourcemq/resource'
9
+ require 'resourcemq/response'
10
+ require 'resourcemq/connection'
11
+ require 'resourcemq/exceptions'
12
+ require 'resourcemq/backend/test'
13
+ require 'resourcemq/backend/zeromq/resource'
14
+ require 'resourcemq/backend/zeromq/server'
15
+
16
+ module ResourceMQ
17
+ end
@@ -0,0 +1,19 @@
1
+ module ResourceMQ
2
+ module Backend
3
+ class Test
4
+ class << self
5
+ def call(service, action, params = {}, headers = {})
6
+ service = "#{service.camelize}Service".constantize.new(params, headers)
7
+ response = service.call(action).map(&:to_json)
8
+
9
+ code, headers, body = response
10
+ [code, JSON.parse(headers), JSON.parse(body)]
11
+ end
12
+
13
+ def reconnect
14
+
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,31 @@
1
+ module ResourceMQ
2
+ module Backend
3
+ class ZeroMQ
4
+ class Resource
5
+ class << self
6
+ def context
7
+ @context ||= ZMQ::Context.new
8
+ end
9
+
10
+ def call(service, action, params = {}, headers = {})
11
+ client.send_message('default', [service, action, params, headers].to_json)
12
+
13
+ code, headers, body = client.receive_message
14
+
15
+ [code, JSON.parse(headers), JSON.parse(body)]
16
+ end
17
+
18
+ def reconnect
19
+ client.connect_to_broker
20
+ end
21
+
22
+ protected
23
+
24
+ def client
25
+ @client ||= ResourceMQ::Client.new('tcp://0.0.0.0:5555', context)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,41 @@
1
+ module ResourceMQ
2
+ module Backend
3
+ class ZeroMQ
4
+ class Server
5
+ class << self
6
+ def context
7
+ @context ||= ZMQ::Context.new
8
+ end
9
+
10
+ def run
11
+ loop do
12
+ begin
13
+ message = worker.receive_message(reply_to = '')
14
+ service, action, params, headers = JSON.parse(message.first)
15
+
16
+ service = "#{service.camelize}Service".constantize.new(params, headers)
17
+ response = service.call(action).map(&:to_json)
18
+
19
+ worker.send_message(response, reply_to)
20
+ rescue ActiveRecord::RecordNotFound => e
21
+ worker.send_message([404, {}, {}].map(&:to_json), reply_to)
22
+ rescue Exception => e
23
+ worker.send_message([500, {}, e.message].map(&:to_json), reply_to)
24
+ end
25
+ end
26
+ end
27
+
28
+ def reconnect
29
+ client.connect_to_broker
30
+ end
31
+
32
+ protected
33
+
34
+ def worker
35
+ @worker ||= ResourceMQ::Worker.new('tcp://0.0.0.0:5555', 'default', context)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,46 @@
1
+ module ResourceMQ
2
+ class Connection
3
+ def initialize(refresh = false)
4
+ backend.reconnect if refresh
5
+ end
6
+
7
+ def call(service, action, params = {}, headers = {})
8
+ response = backend.call(service, action, params, headers)
9
+
10
+ handle_response(Response.new(*response))
11
+ end
12
+
13
+ def backend(env = Rails.env)
14
+ if env == 'test'
15
+ Backend::Test
16
+ else
17
+ Backend::ZeroMQ::Resource
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def handle_response(response)
24
+ case response.code.to_i
25
+ when 200...400
26
+ response
27
+ when 400
28
+ raise(BadRequest.new(response))
29
+ when 401
30
+ raise(UnauthorizedAccess.new(response))
31
+ when 403
32
+ raise(ForbiddenAccess.new(response))
33
+ when 404
34
+ raise(ResourceNotFound.new(response))
35
+ when 422
36
+ raise(ResourceInvalid.new(response))
37
+ when 401...500
38
+ raise(ClientError.new(response))
39
+ when 500...600
40
+ raise(ServerError.new(response))
41
+ else
42
+ raise(ConnectionError.new(response, "Unknown response code: #{response.code}"))
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,31 @@
1
+ require 'ffi-rzmq'
2
+
3
+ module ResourceMQ
4
+ class Controller
5
+ attr_accessor :params, :headers, :body, :code
6
+
7
+ def initialize(params, headers)
8
+ @params = params.with_indifferent_access
9
+ @headers = headers
10
+ end
11
+
12
+ def render(resource, options = {})
13
+ serializer = if options[:serializer]
14
+ options[:serializer].new(resource)
15
+ elsif resource.respond_to?(:active_model_serializer)
16
+ resource.active_model_serializer.new(resource)
17
+ else
18
+ resource
19
+ end
20
+
21
+ @code = options[:status] ? Rack::Utils.status_code(options[:status]) : 200
22
+ @body = serializer
23
+ end
24
+
25
+ def call(action)
26
+ send(action)
27
+
28
+ [code, headers, body]
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,5 @@
1
+ module ResourceMQ
2
+ class Engine < ::Rails::Engine
3
+
4
+ end
5
+ end
@@ -0,0 +1,31 @@
1
+ module ResourceMQ
2
+ class ConnectionError < StandardError # :nodoc:
3
+ attr_reader :response
4
+
5
+ def initialize(response, message = nil)
6
+ @response = response
7
+ @message = message
8
+ end
9
+ end
10
+
11
+ class BadRequest < ConnectionError
12
+ end
13
+ class UnauthorizedAccess < ConnectionError
14
+ end
15
+ class ForbiddenAccess < ConnectionError
16
+ end
17
+ class ResourceNotFound < ConnectionError
18
+ end
19
+ class MethodNotAllowed < ConnectionError
20
+ end
21
+ class ResourceConflict < ConnectionError
22
+ end
23
+ class ResourceGone < ConnectionError
24
+ end
25
+ class ResourceInvalid < ConnectionError
26
+ end
27
+ class ClientError < ConnectionError
28
+ end
29
+ class ServerError < ConnectionError
30
+ end
31
+ end
@@ -0,0 +1,158 @@
1
+ module ResourceMQ
2
+ class Resource
3
+ extend ActiveModel::Naming
4
+ include Virtus
5
+ include ActiveModel::Conversion
6
+ include ActiveModel::Serializers::JSON
7
+
8
+ attribute :id
9
+
10
+ class << self
11
+ def headers
12
+ Thread.current["#{self.name}_headers"] ||= {}
13
+ end
14
+
15
+ attr_writer :element_name
16
+
17
+ def element_name
18
+ @element_name ||= model_name.element
19
+ end
20
+
21
+ attr_writer :collection_name
22
+
23
+ def collection_name
24
+ @collection_name ||= ActiveSupport::Inflector.pluralize(element_name)
25
+ end
26
+
27
+ def create(attributes)
28
+ self.new(attributes).tap { |resource| resource.save }
29
+ end
30
+
31
+ def find(id)
32
+ instantiate_record(call_action('show', id: id).body, true)
33
+ end
34
+
35
+ def all
36
+ instantiate_collection(call_action('index').body)
37
+ end
38
+
39
+ def delete(id)
40
+ call_action('destroy', id: id)
41
+ end
42
+
43
+ def call_action(action, params = {})
44
+ connection.call(collection_name, action, params, headers)
45
+ end
46
+
47
+ def human_attribute_name(attr, options = {})
48
+ attr
49
+ end
50
+
51
+ def lookup_ancestors
52
+ [self]
53
+ end
54
+
55
+ protected
56
+
57
+ def connection(refresh = false)
58
+ ResourceMQ::Connection.new(refresh)
59
+ end
60
+
61
+ def instantiate_collection(collection)
62
+ collection.collect! { |record| instantiate_record(record) }
63
+ end
64
+
65
+ def instantiate_record(record, remove_root = false)
66
+ new(record, true, remove_root)
67
+ end
68
+ end
69
+ cattr_accessor :logger
70
+
71
+ attr_reader :errors
72
+
73
+ def initialize(attributes = {}, persisted = false, remove_root = false)
74
+ @attributes = {}.with_indifferent_access
75
+ @persisted = persisted
76
+ @errors = ActiveModel::Errors.new(self)
77
+ load(attributes, remove_root)
78
+ end
79
+
80
+ def new?
81
+ !persisted?
82
+ end
83
+
84
+ alias :new_record? :new?
85
+
86
+ def persisted?
87
+ @persisted
88
+ end
89
+
90
+ def ==(other)
91
+ other.equal?(self) || (other.instance_of?(self.class) && other.id == id)
92
+ end
93
+
94
+ def save
95
+ new? ? create : update
96
+ end
97
+
98
+ def save!
99
+ save || raise(ResourceInvalid.new(self))
100
+ end
101
+
102
+ def destroy
103
+ self.class.call_action('destroy', id: id)
104
+ end
105
+
106
+ def update_attributes(attributes)
107
+ load(attributes, false) && save
108
+ end
109
+
110
+ protected
111
+
112
+ def load_errors(attributes)
113
+ attributes[:errors].each do |key, values|
114
+ values.each do |value|
115
+ @errors.add(key.to_sym, value)
116
+ end
117
+ end
118
+ end
119
+
120
+ def params
121
+ params = {self.class.element_name.to_sym => attributes.except(:id)}
122
+ params.merge!(id: id) unless new_record?
123
+ params
124
+ end
125
+
126
+ def load(attributes, remove_root = false)
127
+ raise ArgumentError, "expected an attributes Hash, got #{attributes.inspect}" unless attributes.is_a?(Hash)
128
+
129
+ attributes = attributes[self.class.element_name] if remove_root
130
+
131
+ self.id ||= attributes.delete('id')
132
+ self.attributes = attributes
133
+ self
134
+ end
135
+
136
+ def update
137
+ self.class.call_action('update', params).tap do |response|
138
+ load(response.body, true)
139
+ @persisted = true
140
+ end
141
+ rescue ResourceInvalid => error
142
+ load_errors(error.response.body.with_indifferent_access)
143
+ @persisted = true
144
+ false
145
+ end
146
+
147
+ def create
148
+ self.class.call_action('create', params).tap do |response|
149
+ load(response.body, true)
150
+ @persisted = true
151
+ end
152
+ rescue ResourceInvalid => error
153
+ load_errors(error.response.body.with_indifferent_access)
154
+ @persisted = false
155
+ false
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,11 @@
1
+ module ResourceMQ
2
+ class Response
3
+ attr_accessor :code, :headers, :body
4
+
5
+ def initialize(code, headers, body)
6
+ @code = code
7
+ @headers = headers
8
+ @body = body
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module ResourceMQ
2
+ VERSION = '0.0.1.alpha'
3
+ end
metadata ADDED
@@ -0,0 +1,155 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: resourcemq
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.alpha
5
+ prerelease: 6
6
+ platform: ruby
7
+ authors:
8
+ - Benoist Claassen
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-06-29 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 4.0.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 4.0.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: virtus
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: ffi-rzmq
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: librmdp
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: active_model_serializers
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: sqlite3
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ description: A client server Resource API with message queues
111
+ email:
112
+ - benoist.claassen@gmail.com
113
+ executables: []
114
+ extensions: []
115
+ extra_rdoc_files: []
116
+ files:
117
+ - lib/resourcemq/backend/test.rb
118
+ - lib/resourcemq/backend/zeromq/resource.rb
119
+ - lib/resourcemq/backend/zeromq/server.rb
120
+ - lib/resourcemq/connection.rb
121
+ - lib/resourcemq/controller.rb
122
+ - lib/resourcemq/engine.rb
123
+ - lib/resourcemq/exceptions.rb
124
+ - lib/resourcemq/resource.rb
125
+ - lib/resourcemq/response.rb
126
+ - lib/resourcemq/version.rb
127
+ - lib/resourcemq.rb
128
+ - MIT-LICENSE
129
+ - Rakefile
130
+ - README.rdoc
131
+ homepage: https://github.com/benoist/resourcemq
132
+ licenses: []
133
+ post_install_message:
134
+ rdoc_options: []
135
+ require_paths:
136
+ - lib
137
+ required_ruby_version: !ruby/object:Gem::Requirement
138
+ none: false
139
+ requirements:
140
+ - - ! '>='
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ required_rubygems_version: !ruby/object:Gem::Requirement
144
+ none: false
145
+ requirements:
146
+ - - ! '>'
147
+ - !ruby/object:Gem::Version
148
+ version: 1.3.1
149
+ requirements: []
150
+ rubyforge_project:
151
+ rubygems_version: 1.8.25
152
+ signing_key:
153
+ specification_version: 3
154
+ summary: A client server Resource API with message queues
155
+ test_files: []