resourcemq 0.0.1.alpha

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/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: []