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.
@@ -0,0 +1,10 @@
1
+
2
+
3
+
4
+ class TestService
5
+
6
+ def test_string string
7
+ "Server got:[#{string}]"
8
+ end
9
+
10
+ end
data/example/client.rb ADDED
@@ -0,0 +1,11 @@
1
+ $:<<File.expand_path(File.dirname( __FILE__) + "/../lib/")
2
+ require 'rubygems'
3
+ require 'rack'
4
+ require 'rack/ext/direct'
5
+
6
+ class Test < Rack::Ext::Direct::Client
7
+ end_point_url "http://localhost:9292"
8
+ end
9
+
10
+
11
+ puts Test.test_string "test"
@@ -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,4 @@
1
+ module Rack::Ext::Direct
2
+ class RemoteError < RuntimeError
3
+ end
4
+ 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.2
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