vvlad-rack_ext_direct 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/example/app/services/test_service.rb +10 -0
- data/example/client.rb +11 -0
- data/lib/rack/ext/direct/client.rb +68 -0
- data/lib/rack/ext/direct/dispatching.rb +18 -0
- data/lib/rack/ext/direct/remote_error.rb +4 -0
- data/lib/rack/ext/direct/remoting.rb +73 -0
- data/lib/rack/ext/direct/request.rb +20 -0
- data/lib/rack/ext/direct/response.rb +31 -0
- data/lib/rack/ext/direct/response_exception.rb +28 -0
- data/lib/rack/ext/direct.rb +14 -0
- data/lib/rack_ext_direct.rb +1 -0
- metadata +12 -1
data/example/client.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'activesupport'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'net/http'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module Rack
|
7
|
+
module Ext
|
8
|
+
module Direct
|
9
|
+
class Client
|
10
|
+
class_inheritable_accessor :service_url
|
11
|
+
class <<self
|
12
|
+
def end_point_url(url)
|
13
|
+
self.service_url= url
|
14
|
+
end
|
15
|
+
|
16
|
+
def next_tid
|
17
|
+
@tid ||=0
|
18
|
+
@tid += 1
|
19
|
+
end
|
20
|
+
|
21
|
+
def perform_request(id,*params,&block)
|
22
|
+
request = {
|
23
|
+
:action => self.name.demodulize,
|
24
|
+
:method => id,
|
25
|
+
:data => [*params],
|
26
|
+
:type => "rpc",
|
27
|
+
:tid => next_tid
|
28
|
+
}
|
29
|
+
|
30
|
+
|
31
|
+
url = URI.parse(self.service_url)
|
32
|
+
req = Net::HTTP::Post.new(url.path.empty? ? "/" : url.path)
|
33
|
+
req.body = request.to_json
|
34
|
+
req.content_type= "application/json"
|
35
|
+
res = Net::HTTP.new(url.host,url.port).start { |http|
|
36
|
+
http.request(req)
|
37
|
+
}
|
38
|
+
|
39
|
+
if res.is_a? Net::HTTPSuccess
|
40
|
+
response = JSON::load(res.body)
|
41
|
+
|
42
|
+
if response["type"] == "rpc"
|
43
|
+
return response["result"]
|
44
|
+
elsif response["type"] == "exception"
|
45
|
+
error = Rack::Ext::Direct::RemoteError.new(response["message"])
|
46
|
+
error.set_backtrace [caller,(response["where"])].flatten
|
47
|
+
raise error
|
48
|
+
else
|
49
|
+
raise RuntimeError,"Unknown response"
|
50
|
+
end
|
51
|
+
else
|
52
|
+
case res
|
53
|
+
when Net::HTTPNotFound
|
54
|
+
raise NameError, "No service with name `#{request[:action]}' on #{service_url}"
|
55
|
+
end
|
56
|
+
res.error!
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def method_missing(id,*params,&block)
|
61
|
+
perform_request(id,*params,&block)
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Rack
|
2
|
+
module Ext
|
3
|
+
module Direct
|
4
|
+
|
5
|
+
class Dispatching <Remoting
|
6
|
+
|
7
|
+
def initialize app,service_root="app/services/",options={}
|
8
|
+
super app,options.merge(
|
9
|
+
:service_root => service_root,
|
10
|
+
:remoting_path => /^\/$/
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'activesupport'
|
3
|
+
module Rack
|
4
|
+
module Ext
|
5
|
+
module Direct
|
6
|
+
class Remoting
|
7
|
+
|
8
|
+
def initialize(app,options={})
|
9
|
+
@app = app
|
10
|
+
@services_root = ::File.expand_path(options[:service_root])
|
11
|
+
@services = {}
|
12
|
+
@report_errors = options[:report_errors] || false
|
13
|
+
@remoting_path = options[:remoting_path]
|
14
|
+
raise "Services Directory `#{@services_root}' missing." unless ::File.directory? @services_root
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(env)
|
18
|
+
if env["PATH_INFO"] =~ @remoting_path and
|
19
|
+
(env['REQUEST_METHOD'] == 'POST' || (env['CONTENT_TYPE']||"").strip =~ /^application\/json/i)
|
20
|
+
handle_request(env)
|
21
|
+
else
|
22
|
+
[404, {"Content-Type" => "text/html"}, ["Not Found"]]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def handle_request(env)
|
27
|
+
request = build_request!(env) or return @app.call(env)
|
28
|
+
service_class = service_by_name(request.action) rescue nil
|
29
|
+
return @app.call(env) if service_class.nil?
|
30
|
+
|
31
|
+
response = begin
|
32
|
+
Response.new request,service_class.new.send(request.method.to_sym,request.data)
|
33
|
+
rescue => e
|
34
|
+
ResponseException.new request,e
|
35
|
+
end
|
36
|
+
|
37
|
+
[ 200 , {"Content-Type" => "application/json"}, [response.to_json]]
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
PROTOCOL_KEYS = [:action,:method,:data,:type,:tid]
|
44
|
+
|
45
|
+
def build_request! env
|
46
|
+
env["rack.input"].rewind
|
47
|
+
json_request = JSON::load(env["rack.input"].read)
|
48
|
+
if json_request
|
49
|
+
json_request.to_options!
|
50
|
+
json_request.assert_valid_keys PROTOCOL_KEYS
|
51
|
+
missing_keys = PROTOCOL_KEYS - json_request.keys
|
52
|
+
return nil if missing_keys.size > 0
|
53
|
+
return Request.new(json_request)
|
54
|
+
end
|
55
|
+
return nil
|
56
|
+
end
|
57
|
+
|
58
|
+
def service_by_name(service_name)
|
59
|
+
@services[service_name] ||= try_load_service(service_name)
|
60
|
+
end
|
61
|
+
|
62
|
+
def try_load_service(service_name)
|
63
|
+
service_name = service_name.underscore
|
64
|
+
service_file = "#{@services_root}/#{service_name}_service.rb"
|
65
|
+
return nil unless ::File.exists? service_file
|
66
|
+
require service_file
|
67
|
+
class_object = "#{service_name}_service".classify.constantize
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Rack::Ext::Direct
|
2
|
+
class Request
|
3
|
+
|
4
|
+
attr_accessor :action
|
5
|
+
attr_accessor :method
|
6
|
+
attr_accessor :data
|
7
|
+
attr_accessor :type
|
8
|
+
attr_accessor :tid
|
9
|
+
|
10
|
+
|
11
|
+
def initialize options={}
|
12
|
+
options.each do |k,v|
|
13
|
+
if respond_to? :"#{k}"
|
14
|
+
instance_variable_set("@#{k}",v)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Rack::Ext::Direct
|
2
|
+
class Response
|
3
|
+
attr_accessor :request
|
4
|
+
attr_accessor :result
|
5
|
+
|
6
|
+
def initialize request,result
|
7
|
+
@request = request
|
8
|
+
@result = result
|
9
|
+
end
|
10
|
+
|
11
|
+
[:action,:method,:tid,:type].each do |method|
|
12
|
+
define_method method do
|
13
|
+
@request.send method
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_json
|
18
|
+
{
|
19
|
+
:type => type,
|
20
|
+
:action => request.action,
|
21
|
+
:method => request.method,
|
22
|
+
:tid => request.tid,
|
23
|
+
:result => result
|
24
|
+
}.to_json
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Rack::Ext::Direct
|
2
|
+
class ResponseException < Response
|
3
|
+
|
4
|
+
def type
|
5
|
+
"exception"
|
6
|
+
end
|
7
|
+
|
8
|
+
def where
|
9
|
+
@result.backtrace rescue []
|
10
|
+
end
|
11
|
+
|
12
|
+
def message
|
13
|
+
"#{@result}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_json
|
17
|
+
{
|
18
|
+
:type => type,
|
19
|
+
:message => message,
|
20
|
+
:where => where,
|
21
|
+
:action => request.action,
|
22
|
+
:method => request.method,
|
23
|
+
:tid => request.tid
|
24
|
+
}.to_json
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rack'
|
2
|
+
module Rack
|
3
|
+
module Ext
|
4
|
+
module Direct
|
5
|
+
autoload :Dispatching, 'rack/ext/direct/dispatching'
|
6
|
+
autoload :Remoting, 'rack/ext/direct/remoting'
|
7
|
+
autoload :Client, 'rack/ext/direct/client'
|
8
|
+
autoload :Response, 'rack/ext/direct/response'
|
9
|
+
autoload :Request, 'rack/ext/direct/request'
|
10
|
+
autoload :ResponseException, 'rack/ext/direct/response_exception'
|
11
|
+
autoload :RemoteError, 'rack/ext/direct/remote_error'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'rack/ext/direct'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vvlad-rack_ext_direct
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Verestiuc Vlad Ovidiu
|
@@ -51,6 +51,17 @@ extensions: []
|
|
51
51
|
extra_rdoc_files:
|
52
52
|
- README
|
53
53
|
files:
|
54
|
+
- example/app/services/test_service.rb
|
55
|
+
- example/client.rb
|
56
|
+
- lib/rack/ext/direct/client.rb
|
57
|
+
- lib/rack/ext/direct/dispatching.rb
|
58
|
+
- lib/rack/ext/direct/remote_error.rb
|
59
|
+
- lib/rack/ext/direct/remoting.rb
|
60
|
+
- lib/rack/ext/direct/request.rb
|
61
|
+
- lib/rack/ext/direct/response.rb
|
62
|
+
- lib/rack/ext/direct/response_exception.rb
|
63
|
+
- lib/rack/ext/direct.rb
|
64
|
+
- lib/rack_ext_direct.rb
|
54
65
|
- README
|
55
66
|
- TODO
|
56
67
|
- CHANGELOG
|