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.
@@ -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