vvlad-rack_ext_direct 0.0.2 → 0.0.3
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/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
|