rack-remote 1.0.1 → 1.1.0
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.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/lib/rack/remote.rb +62 -9
- data/lib/rack/remote/railtie.rb +7 -0
- data/lib/rack/remote/version.rb +1 -1
- data/spec/rack/remote_spec.rb +8 -2
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4fd96f00690a34791cdf740b05ceabb0b11c8e11
|
4
|
+
data.tar.gz: ad6625414ec22cc4bf3c2707c836703713f6642f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: af407c05bacc948152cf7c67597239a0bdd62a083b1b3f1b20759cdbc22890b7e7ba89a53504bc960afb215a8b28e90bad20513c0d0bcb232693f813e5a13039
|
7
|
+
data.tar.gz: 5cf6ad86343dade6b2cb27ff8a191bb696efec7cbc189ef5781f4cf41ca9c402a33f0f02d4c1c7aa587d06d3bdbc616afdb79da69b573e2a09b7d3226cca9758
|
data/Gemfile
CHANGED
data/lib/rack/remote.rb
CHANGED
@@ -3,12 +3,45 @@ require 'rack/request'
|
|
3
3
|
require 'multi_json'
|
4
4
|
|
5
5
|
module Rack
|
6
|
-
|
7
6
|
# Rack::Remote is a Rack middleware for intercepting calls
|
8
7
|
# and invoking remote calls. It can be used to call remote
|
9
8
|
# function for test instructions in distributed systems.
|
10
9
|
#
|
11
10
|
class Remote
|
11
|
+
require 'rack/remote/railtie' if defined?(Rails)
|
12
|
+
|
13
|
+
class ChainedError < StandardError
|
14
|
+
attr_reader :cause
|
15
|
+
|
16
|
+
def initialize(*attrs)
|
17
|
+
if attrs.last.is_a?(Hash) && attrs.last[:cause].is_a?(Exception)
|
18
|
+
@cause = attrs.last.delete(:cause)
|
19
|
+
attrs.pop if attrs.last.empty?
|
20
|
+
end
|
21
|
+
super *attrs
|
22
|
+
end
|
23
|
+
|
24
|
+
def set_backtrace(trace)
|
25
|
+
trace.is_a?(Array) ? trace.map!(&:to_s) : trace = trace.to_s.split("\n")
|
26
|
+
trace.map! { |line| " #{line}" }
|
27
|
+
if cause
|
28
|
+
trace << "caused by #{cause.class.name}: #{cause.message}"
|
29
|
+
trace += cause.backtrace.map! { |line| " #{line}" }
|
30
|
+
end
|
31
|
+
super trace
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class RemoteError < StandardError
|
36
|
+
def initialize(opts = {})
|
37
|
+
super "#{opts[:class]}: #{opts[:error]}"
|
38
|
+
set_backtrace opts[:backtrace]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class RemoteCallFailed < ChainedError
|
43
|
+
end
|
44
|
+
|
12
45
|
def initialize(app)
|
13
46
|
@app = app
|
14
47
|
end
|
@@ -20,14 +53,24 @@ module Rack
|
|
20
53
|
call = env['HTTP_X_RACK_REMOTE_CALL'].to_s
|
21
54
|
|
22
55
|
if (cb = self.class.calls[call])
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
56
|
+
begin
|
57
|
+
# First rewind request body before read
|
58
|
+
request.body.rewind
|
59
|
+
|
60
|
+
data = request.body.read
|
61
|
+
json = data.empty? ? {} : MultiJson.load(data)
|
62
|
+
|
63
|
+
response = cb.call(json, env, request)
|
64
|
+
if response.is_a?(Array) && response.size == 3
|
65
|
+
return response
|
66
|
+
else
|
67
|
+
[200, {'Content-Type' => 'application/json'}, StringIO.new(MultiJson.dump response) ]
|
68
|
+
end
|
69
|
+
rescue => err
|
70
|
+
[500, {'Content-Type' => 'application/json'}, StringIO.new(MultiJson.dump error: err.message, backtrace: err.backtrace, class: err.class.name) ]
|
28
71
|
end
|
29
72
|
else
|
30
|
-
[404, {'Content-Type' => 'application/json'}, StringIO.new(
|
73
|
+
[404, {'Content-Type' => 'application/json'}, StringIO.new(MultiJson.dump error: 'remote call not defined', calls: call, list: self.class.calls.keys) ]
|
31
74
|
end
|
32
75
|
end
|
33
76
|
|
@@ -88,13 +131,23 @@ module Rack
|
|
88
131
|
end
|
89
132
|
|
90
133
|
request['X-Rack-Remote-Call'] = call.to_s
|
91
|
-
request
|
134
|
+
request['Content-Type'] = 'application/json'
|
135
|
+
request.body = MultiJson.dump(params)
|
92
136
|
|
93
137
|
response = http.request request
|
138
|
+
if response.code.to_i == 500 and response['Content-Type'] == 'application/json'
|
139
|
+
json = MultiJson.load(response.body)
|
140
|
+
|
141
|
+
if json['error'] && json['backtrace'] && json['class']
|
142
|
+
remote_error = RemoteError.new class: json['class'], error: json['error'], backtrace: json['backtrace']
|
143
|
+
raise Rack::Remote::RemoteCallFailed.new("Remote call returned error code #{response.code}", cause: remote_error)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
94
147
|
raise StandardError, "Rack Remote Error Response: #{response.code}: #{response.body}" if response.code.to_i != 200
|
95
148
|
|
96
149
|
if response['Content-Type'] == 'application/json'
|
97
|
-
MultiJson.load
|
150
|
+
response.body.empty? ? {} : MultiJson.load(response.body)
|
98
151
|
else
|
99
152
|
response.body
|
100
153
|
end
|
data/lib/rack/remote/version.rb
CHANGED
data/spec/rack/remote_spec.rb
CHANGED
@@ -13,7 +13,7 @@ describe Rack::Remote do
|
|
13
13
|
before { Rack::Remote.register :factory_girl, &block }
|
14
14
|
|
15
15
|
context 'with intercept call' do
|
16
|
-
let(:request) { -> {
|
16
|
+
let(:request) { -> { post '/', {}, {'HTTP_X_RACK_REMOTE_CALL' => 'factory_girl'} }}
|
17
17
|
|
18
18
|
it 'should invoke registered call' do
|
19
19
|
expect(block).to receive(:call)
|
@@ -27,7 +27,7 @@ describe Rack::Remote do
|
|
27
27
|
end
|
28
28
|
|
29
29
|
context 'with non-rack-remote call' do
|
30
|
-
let(:request) { -> {
|
30
|
+
let(:request) { -> { post '/' }}
|
31
31
|
|
32
32
|
it 'should delegate request to inner app' do
|
33
33
|
expect(inner_app).to receive(:call).and_call_original
|
@@ -74,6 +74,12 @@ describe Rack::Remote do
|
|
74
74
|
ret = Rack::Remote.invoke :users, :factory_girl, param1: 'val1'
|
75
75
|
expect(ret).to eq({'id' => 1})
|
76
76
|
end
|
77
|
+
|
78
|
+
it 'should invoke remote call (2)' do
|
79
|
+
expect(block).to receive(:call).with({ 'param1' => ['val1', {'abc' => 'cde'}] }, kind_of(Hash), kind_of(Rack::Request)).and_return({id: 1})
|
80
|
+
ret = Rack::Remote.invoke :users, :factory_girl, param1: ['val1', {abc: :cde}]
|
81
|
+
expect(ret).to eq({'id' => 1})
|
82
|
+
end
|
77
83
|
end
|
78
84
|
end
|
79
85
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-remote
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan Graichen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-10-
|
11
|
+
date: 2013-10-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -68,6 +68,7 @@ files:
|
|
68
68
|
- README.md
|
69
69
|
- Rakefile
|
70
70
|
- lib/rack/remote.rb
|
71
|
+
- lib/rack/remote/railtie.rb
|
71
72
|
- lib/rack/remote/version.rb
|
72
73
|
- rack-remote.gemspec
|
73
74
|
- spec/rack/remote_spec.rb
|
@@ -99,3 +100,4 @@ summary: Small request intercepting rack middleware to invoke remote calls over
|
|
99
100
|
test_files:
|
100
101
|
- spec/rack/remote_spec.rb
|
101
102
|
- spec/spec_helper.rb
|
103
|
+
has_rdoc:
|