rack-remote 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|