jetra 1.2.0 → 1.3.0
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.
- checksums.yaml +4 -4
- data/lib/jetra.rb +1 -1
- data/lib/jetra/adapter/grpc.rb +71 -71
- data/lib/jetra/adapter/grpc/jetra_pb.rb +28 -28
- data/lib/jetra/adapter/grpc/jetra_services_pb.rb +24 -24
- data/lib/jetra/adapter/rack.rb +62 -62
- data/lib/jetra/adapter/thrift.rb +110 -110
- data/lib/jetra/adapter/thrift/jetra_constants.rb +10 -10
- data/lib/jetra/adapter/thrift/jetra_types.rb +46 -46
- data/lib/jetra/adapter/thrift/service.rb +81 -81
- data/lib/jetra/application.rb +9 -9
- data/lib/jetra/base.rb +311 -311
- data/lib/jetra/builder.rb +50 -50
- data/lib/jetra/combiner.rb +52 -52
- data/lib/jetra/middleware/sample.rb +29 -29
- data/lib/jetra/middleware/validater.rb +36 -36
- data/lib/jetra/version.rb +4 -4
- metadata +3 -4
@@ -1,10 +1,10 @@
|
|
1
|
-
#
|
2
|
-
# Autogenerated by Thrift Compiler (0.10.0)
|
3
|
-
#
|
4
|
-
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
5
|
-
#
|
6
|
-
|
7
|
-
module Jetra
|
8
|
-
module Thrift
|
9
|
-
end
|
10
|
-
end
|
1
|
+
#
|
2
|
+
# Autogenerated by Thrift Compiler (0.10.0)
|
3
|
+
#
|
4
|
+
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
5
|
+
#
|
6
|
+
|
7
|
+
module Jetra
|
8
|
+
module Thrift
|
9
|
+
end
|
10
|
+
end
|
@@ -1,46 +1,46 @@
|
|
1
|
-
#
|
2
|
-
# Autogenerated by Thrift Compiler (0.10.0)
|
3
|
-
#
|
4
|
-
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
5
|
-
#
|
6
|
-
|
7
|
-
module Jetra
|
8
|
-
module Thrift
|
9
|
-
class Request
|
10
|
-
include ::Thrift::Struct, ::Thrift::Struct_Union
|
11
|
-
ROUTE = 1
|
12
|
-
PARAMS = 2
|
13
|
-
|
14
|
-
FIELDS = {
|
15
|
-
ROUTE => {:type => ::Thrift::Types::STRING, :name => 'route'},
|
16
|
-
PARAMS => {:type => ::Thrift::Types::STRING, :name => 'params'}
|
17
|
-
}
|
18
|
-
|
19
|
-
def struct_fields; FIELDS; end
|
20
|
-
|
21
|
-
def validate
|
22
|
-
end
|
23
|
-
|
24
|
-
::Thrift::Struct.generate_accessors self
|
25
|
-
end
|
26
|
-
|
27
|
-
class Response
|
28
|
-
include ::Thrift::Struct, ::Thrift::Struct_Union
|
29
|
-
STATUS = 1
|
30
|
-
BODY = 2
|
31
|
-
|
32
|
-
FIELDS = {
|
33
|
-
STATUS => {:type => ::Thrift::Types::I32, :name => 'status'},
|
34
|
-
BODY => {:type => ::Thrift::Types::STRING, :name => 'body'}
|
35
|
-
}
|
36
|
-
|
37
|
-
def struct_fields; FIELDS; end
|
38
|
-
|
39
|
-
def validate
|
40
|
-
end
|
41
|
-
|
42
|
-
::Thrift::Struct.generate_accessors self
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
46
|
-
end
|
1
|
+
#
|
2
|
+
# Autogenerated by Thrift Compiler (0.10.0)
|
3
|
+
#
|
4
|
+
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
5
|
+
#
|
6
|
+
|
7
|
+
module Jetra
|
8
|
+
module Thrift
|
9
|
+
class Request
|
10
|
+
include ::Thrift::Struct, ::Thrift::Struct_Union
|
11
|
+
ROUTE = 1
|
12
|
+
PARAMS = 2
|
13
|
+
|
14
|
+
FIELDS = {
|
15
|
+
ROUTE => {:type => ::Thrift::Types::STRING, :name => 'route'},
|
16
|
+
PARAMS => {:type => ::Thrift::Types::STRING, :name => 'params'}
|
17
|
+
}
|
18
|
+
|
19
|
+
def struct_fields; FIELDS; end
|
20
|
+
|
21
|
+
def validate
|
22
|
+
end
|
23
|
+
|
24
|
+
::Thrift::Struct.generate_accessors self
|
25
|
+
end
|
26
|
+
|
27
|
+
class Response
|
28
|
+
include ::Thrift::Struct, ::Thrift::Struct_Union
|
29
|
+
STATUS = 1
|
30
|
+
BODY = 2
|
31
|
+
|
32
|
+
FIELDS = {
|
33
|
+
STATUS => {:type => ::Thrift::Types::I32, :name => 'status'},
|
34
|
+
BODY => {:type => ::Thrift::Types::STRING, :name => 'body'}
|
35
|
+
}
|
36
|
+
|
37
|
+
def struct_fields; FIELDS; end
|
38
|
+
|
39
|
+
def validate
|
40
|
+
end
|
41
|
+
|
42
|
+
::Thrift::Struct.generate_accessors self
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -1,81 +1,81 @@
|
|
1
|
-
#
|
2
|
-
# Autogenerated by Thrift Compiler (0.10.0)
|
3
|
-
#
|
4
|
-
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
5
|
-
#
|
6
|
-
|
7
|
-
module Jetra
|
8
|
-
module Thrift
|
9
|
-
|
10
|
-
module Service
|
11
|
-
|
12
|
-
class Client
|
13
|
-
include ::Thrift::Client
|
14
|
-
|
15
|
-
def call(request)
|
16
|
-
send_call(request)
|
17
|
-
return recv_call()
|
18
|
-
end
|
19
|
-
|
20
|
-
def send_call(request)
|
21
|
-
send_message('call', Call_args, :request => request)
|
22
|
-
end
|
23
|
-
|
24
|
-
def recv_call()
|
25
|
-
result = receive_message(Call_result)
|
26
|
-
return result.success unless result.success.nil?
|
27
|
-
raise ::Thrift::ApplicationException.new(::Thrift::ApplicationException::MISSING_RESULT, 'call failed: unknown result')
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
class Processor
|
33
|
-
include ::Thrift::Processor
|
34
|
-
|
35
|
-
def process_call(seqid, iprot, oprot)
|
36
|
-
args = read_args(iprot, Call_args)
|
37
|
-
result = Call_result.new()
|
38
|
-
result.success = @handler.call(args.request)
|
39
|
-
write_result(result, oprot, 'call', seqid)
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|
43
|
-
|
44
|
-
# HELPER FUNCTIONS AND STRUCTURES
|
45
|
-
|
46
|
-
class Call_args
|
47
|
-
include ::Thrift::Struct, ::Thrift::Struct_Union
|
48
|
-
REQUEST = 1
|
49
|
-
|
50
|
-
FIELDS = {
|
51
|
-
REQUEST => {:type => ::Thrift::Types::STRUCT, :name => 'request', :class => ::Jetra::Thrift::Request}
|
52
|
-
}
|
53
|
-
|
54
|
-
def struct_fields; FIELDS; end
|
55
|
-
|
56
|
-
def validate
|
57
|
-
end
|
58
|
-
|
59
|
-
::Thrift::Struct.generate_accessors self
|
60
|
-
end
|
61
|
-
|
62
|
-
class Call_result
|
63
|
-
include ::Thrift::Struct, ::Thrift::Struct_Union
|
64
|
-
SUCCESS = 0
|
65
|
-
|
66
|
-
FIELDS = {
|
67
|
-
SUCCESS => {:type => ::Thrift::Types::STRUCT, :name => 'success', :class => ::Jetra::Thrift::Response}
|
68
|
-
}
|
69
|
-
|
70
|
-
def struct_fields; FIELDS; end
|
71
|
-
|
72
|
-
def validate
|
73
|
-
end
|
74
|
-
|
75
|
-
::Thrift::Struct.generate_accessors self
|
76
|
-
end
|
77
|
-
|
78
|
-
end
|
79
|
-
|
80
|
-
end
|
81
|
-
end
|
1
|
+
#
|
2
|
+
# Autogenerated by Thrift Compiler (0.10.0)
|
3
|
+
#
|
4
|
+
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
5
|
+
#
|
6
|
+
|
7
|
+
module Jetra
|
8
|
+
module Thrift
|
9
|
+
|
10
|
+
module Service
|
11
|
+
|
12
|
+
class Client
|
13
|
+
include ::Thrift::Client
|
14
|
+
|
15
|
+
def call(request)
|
16
|
+
send_call(request)
|
17
|
+
return recv_call()
|
18
|
+
end
|
19
|
+
|
20
|
+
def send_call(request)
|
21
|
+
send_message('call', Call_args, :request => request)
|
22
|
+
end
|
23
|
+
|
24
|
+
def recv_call()
|
25
|
+
result = receive_message(Call_result)
|
26
|
+
return result.success unless result.success.nil?
|
27
|
+
raise ::Thrift::ApplicationException.new(::Thrift::ApplicationException::MISSING_RESULT, 'call failed: unknown result')
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
class Processor
|
33
|
+
include ::Thrift::Processor
|
34
|
+
|
35
|
+
def process_call(seqid, iprot, oprot)
|
36
|
+
args = read_args(iprot, Call_args)
|
37
|
+
result = Call_result.new()
|
38
|
+
result.success = @handler.call(args.request)
|
39
|
+
write_result(result, oprot, 'call', seqid)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
# HELPER FUNCTIONS AND STRUCTURES
|
45
|
+
|
46
|
+
class Call_args
|
47
|
+
include ::Thrift::Struct, ::Thrift::Struct_Union
|
48
|
+
REQUEST = 1
|
49
|
+
|
50
|
+
FIELDS = {
|
51
|
+
REQUEST => {:type => ::Thrift::Types::STRUCT, :name => 'request', :class => ::Jetra::Thrift::Request}
|
52
|
+
}
|
53
|
+
|
54
|
+
def struct_fields; FIELDS; end
|
55
|
+
|
56
|
+
def validate
|
57
|
+
end
|
58
|
+
|
59
|
+
::Thrift::Struct.generate_accessors self
|
60
|
+
end
|
61
|
+
|
62
|
+
class Call_result
|
63
|
+
include ::Thrift::Struct, ::Thrift::Struct_Union
|
64
|
+
SUCCESS = 0
|
65
|
+
|
66
|
+
FIELDS = {
|
67
|
+
SUCCESS => {:type => ::Thrift::Types::STRUCT, :name => 'success', :class => ::Jetra::Thrift::Response}
|
68
|
+
}
|
69
|
+
|
70
|
+
def struct_fields; FIELDS; end
|
71
|
+
|
72
|
+
def validate
|
73
|
+
end
|
74
|
+
|
75
|
+
::Thrift::Struct.generate_accessors self
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
data/lib/jetra/application.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
module Jetra
|
2
|
-
|
3
|
-
class Application
|
4
|
-
|
5
|
-
def initialize(app)
|
6
|
-
@app = app
|
7
|
-
end
|
8
|
-
|
9
|
-
end
|
1
|
+
module Jetra
|
2
|
+
|
3
|
+
class Application
|
4
|
+
|
5
|
+
def initialize(app)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
10
10
|
end
|
data/lib/jetra/base.rb
CHANGED
@@ -1,312 +1,312 @@
|
|
1
|
-
require "jetra/application"
|
2
|
-
|
3
|
-
module Jetra
|
4
|
-
|
5
|
-
class NotFoundException < Exception ; end
|
6
|
-
|
7
|
-
class Halt < Exception ; end
|
8
|
-
|
9
|
-
class Request
|
10
|
-
|
11
|
-
attr_accessor :route, :params, :headers, :body
|
12
|
-
|
13
|
-
def initialize(route=nil, params=nil, headers=nil, body=nil)
|
14
|
-
@route = route || ""
|
15
|
-
@params = params
|
16
|
-
@headers = headers
|
17
|
-
@body = body
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
class Response
|
22
|
-
|
23
|
-
attr_accessor :status, :body, :headers
|
24
|
-
|
25
|
-
def initialize(status=nil, body=nil, headers=nil)
|
26
|
-
@status = status.to_i
|
27
|
-
@body = body
|
28
|
-
@headers = headers
|
29
|
-
end
|
30
|
-
|
31
|
-
def finish
|
32
|
-
self.freeze
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
class Base
|
37
|
-
|
38
|
-
Settings = {}
|
39
|
-
Settings[:env] = "development"
|
40
|
-
|
41
|
-
attr_accessor :request, :response, :params
|
42
|
-
|
43
|
-
def call(route=nil, params=nil, headers=nil, body=nil)
|
44
|
-
request = Request.new(route, params, headers, body)
|
45
|
-
dup.call!(request)
|
46
|
-
end
|
47
|
-
|
48
|
-
def call!(request)
|
49
|
-
|
50
|
-
@request = request
|
51
|
-
@response = Response.new
|
52
|
-
|
53
|
-
@params = request.params
|
54
|
-
|
55
|
-
invoke { dispatch! }
|
56
|
-
|
57
|
-
@response.finish
|
58
|
-
end
|
59
|
-
|
60
|
-
def current_class
|
61
|
-
self.class
|
62
|
-
end
|
63
|
-
|
64
|
-
def invoke
|
65
|
-
res = catch(Halt) { yield }
|
66
|
-
|
67
|
-
if Array === res
|
68
|
-
res = res.dup
|
69
|
-
|
70
|
-
if status = res.shift
|
71
|
-
response.status = status
|
72
|
-
end
|
73
|
-
|
74
|
-
if body = res.shift
|
75
|
-
response.body = body
|
76
|
-
end
|
77
|
-
else
|
78
|
-
if res
|
79
|
-
response.body = res
|
80
|
-
end
|
81
|
-
end
|
82
|
-
nil
|
83
|
-
end
|
84
|
-
|
85
|
-
def dispatch!
|
86
|
-
filter! :before
|
87
|
-
route!
|
88
|
-
rescue ::Exception => boom
|
89
|
-
gotError = true
|
90
|
-
handle_exception!(boom)
|
91
|
-
ensure
|
92
|
-
begin
|
93
|
-
filter! :after
|
94
|
-
rescue ::Exception => boom
|
95
|
-
handle_exception!(boom) unless gotError
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
def handle_exception!(boom)
|
100
|
-
|
101
|
-
response.status = -1
|
102
|
-
|
103
|
-
error_block!(boom.class, boom)
|
104
|
-
|
105
|
-
raise boom
|
106
|
-
end
|
107
|
-
|
108
|
-
def halt(*response)
|
109
|
-
response = response.first if response.length == 1
|
110
|
-
throw Halt, response
|
111
|
-
end
|
112
|
-
|
113
|
-
def filter!(type)
|
114
|
-
current_class.filters[type].each do |args|
|
115
|
-
processRoute(*args)
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
def route!
|
120
|
-
|
121
|
-
if block = current_class.routes[@request.route.to_sym]
|
122
|
-
processRoute do |*args|
|
123
|
-
routeEval { block[*args] }
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
route_missing
|
128
|
-
end
|
129
|
-
|
130
|
-
def error_block!(errorClass, *blockParams)
|
131
|
-
|
132
|
-
if errorBlocks = current_class.errors[errorClass]
|
133
|
-
errorBlocks.reverse_each do |errorBlock|
|
134
|
-
args = [errorBlock]
|
135
|
-
args += [blockParams]
|
136
|
-
resp = processRoute(*args)
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
if errorClass.respond_to? :superclass and errorClass.superclass <= Exception
|
141
|
-
error_block!(errorClass.superclass, *blockParams)
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
def routeEval
|
146
|
-
throw Halt, yield
|
147
|
-
end
|
148
|
-
|
149
|
-
def processRoute(block=nil,values=[])
|
150
|
-
block ? block[self,values] : yield(self,values)
|
151
|
-
end
|
152
|
-
|
153
|
-
def route_missing
|
154
|
-
raise NotFoundException.new("route not found")
|
155
|
-
end
|
156
|
-
|
157
|
-
def success_response(body, status=0)
|
158
|
-
|
159
|
-
raise "status code must >= 0 when success" if status < 0
|
160
|
-
|
161
|
-
response.body = body
|
162
|
-
response.status = status
|
163
|
-
end
|
164
|
-
|
165
|
-
def failure_response(body, status=-1)
|
166
|
-
|
167
|
-
raise "status code must <= -1 when failure" if status > -1
|
168
|
-
|
169
|
-
response.body = body
|
170
|
-
response.status = status
|
171
|
-
end
|
172
|
-
|
173
|
-
def halt_success(body, status=0)
|
174
|
-
success_response(body, status)
|
175
|
-
halt
|
176
|
-
end
|
177
|
-
|
178
|
-
def halt_failure(body, status=-1)
|
179
|
-
failure_response(body, status)
|
180
|
-
halt
|
181
|
-
end
|
182
|
-
|
183
|
-
class << self
|
184
|
-
|
185
|
-
attr_accessor :routes, :filters, :errors
|
186
|
-
|
187
|
-
def prototype
|
188
|
-
@prototype ||= new
|
189
|
-
end
|
190
|
-
|
191
|
-
def call(route=nil, params=nil, headers=nil, body=nil)
|
192
|
-
prototype.call(route, params, headers, body)
|
193
|
-
end
|
194
|
-
|
195
|
-
def before(&block)
|
196
|
-
add_filter(:before, &block)
|
197
|
-
end
|
198
|
-
|
199
|
-
def after(&block)
|
200
|
-
add_filter(:after, &block)
|
201
|
-
end
|
202
|
-
|
203
|
-
def add_filter(type, &block)
|
204
|
-
@filters[type] << compile!(&block)
|
205
|
-
end
|
206
|
-
|
207
|
-
def route(string, &block)
|
208
|
-
symbol = string.to_sym
|
209
|
-
block ||= Proc.new { method(symbol).call }
|
210
|
-
@routes[symbol] = compile!(&block)
|
211
|
-
end
|
212
|
-
|
213
|
-
def error(*codes, &block)
|
214
|
-
codes = codes.map { |c| Array(c) }.flatten
|
215
|
-
codes << Exception if codes.empty?
|
216
|
-
codes.each { |c| (@errors[c] ||= []) << compile!(&block) }
|
217
|
-
end
|
218
|
-
|
219
|
-
def generateUnboundMethod(&block)
|
220
|
-
methodName = :id #any symbol is ok.
|
221
|
-
define_method(methodName, &block)
|
222
|
-
method = instance_method methodName
|
223
|
-
remove_method methodName
|
224
|
-
method
|
225
|
-
end
|
226
|
-
|
227
|
-
def compile!(&block)
|
228
|
-
|
229
|
-
unboundMethod = generateUnboundMethod(&block)
|
230
|
-
|
231
|
-
block.arity != 0 ?
|
232
|
-
proc { |a,p| unboundMethod.bind(a).call(*p) } :
|
233
|
-
proc { |a,p| unboundMethod.bind(a).call }
|
234
|
-
end
|
235
|
-
|
236
|
-
def inherited(subclass)
|
237
|
-
|
238
|
-
subclass.routes = copy_routes
|
239
|
-
subclass.filters = copy_filters
|
240
|
-
subclass.errors = copy_errors
|
241
|
-
|
242
|
-
super
|
243
|
-
end
|
244
|
-
|
245
|
-
def copy_routes
|
246
|
-
newRoutes = {}
|
247
|
-
@routes.each do |key, value|
|
248
|
-
newRoutes[key] = value
|
249
|
-
end
|
250
|
-
newRoutes
|
251
|
-
end
|
252
|
-
|
253
|
-
def copy_filters
|
254
|
-
newFilters = {}
|
255
|
-
@filters.each do |key, values|
|
256
|
-
newValues = []
|
257
|
-
values.each do |value|
|
258
|
-
newValues << value
|
259
|
-
end
|
260
|
-
newFilters[key] = newValues
|
261
|
-
end
|
262
|
-
newFilters
|
263
|
-
end
|
264
|
-
|
265
|
-
def copy_errors
|
266
|
-
newErrors = {}
|
267
|
-
@errors.each do |key, values|
|
268
|
-
newValues = []
|
269
|
-
values.each do |value|
|
270
|
-
newValues << value
|
271
|
-
end
|
272
|
-
newErrors[key] = newValues
|
273
|
-
end
|
274
|
-
newErrors
|
275
|
-
end
|
276
|
-
|
277
|
-
def to_app
|
278
|
-
|
279
|
-
newApp = Jetra::Application.new(self)
|
280
|
-
@routes.each_key do |route|
|
281
|
-
eval("newApp.define_singleton_method(route) do |params={}| ; @app.call(route, params) ; end ")
|
282
|
-
end
|
283
|
-
|
284
|
-
eval("newApp.define_singleton_method(:method_missing) do |methodName, params={}| ; @app.call(methodName, params) ; end ")
|
285
|
-
|
286
|
-
newApp
|
287
|
-
end
|
288
|
-
|
289
|
-
end
|
290
|
-
|
291
|
-
@routes = {}
|
292
|
-
@filters = {:before => [], :after => []}
|
293
|
-
@errors = {}
|
294
|
-
|
295
|
-
error do |boom|
|
296
|
-
|
297
|
-
raise boom #TODO 因为服务类型不同,错误返回就不同,没法统一默认异常返回结果
|
298
|
-
|
299
|
-
boommsg = "#{boom.class} - #{boom.message}"
|
300
|
-
|
301
|
-
if boom.class == Jetra::NotFoundException
|
302
|
-
trace = []
|
303
|
-
else
|
304
|
-
trace = boom.backtrace
|
305
|
-
trace.unshift boommsg
|
306
|
-
end
|
307
|
-
response.body = {msg: boommsg, class: boom.class.to_s, route: request.route, params: params, trace: trace}
|
308
|
-
halt
|
309
|
-
end
|
310
|
-
|
311
|
-
end
|
1
|
+
require "jetra/application"
|
2
|
+
|
3
|
+
module Jetra
|
4
|
+
|
5
|
+
class NotFoundException < Exception ; end
|
6
|
+
|
7
|
+
class Halt < Exception ; end
|
8
|
+
|
9
|
+
class Request
|
10
|
+
|
11
|
+
attr_accessor :route, :params, :headers, :body
|
12
|
+
|
13
|
+
def initialize(route=nil, params=nil, headers=nil, body=nil)
|
14
|
+
@route = route || ""
|
15
|
+
@params = params
|
16
|
+
@headers = headers
|
17
|
+
@body = body
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Response
|
22
|
+
|
23
|
+
attr_accessor :status, :body, :headers
|
24
|
+
|
25
|
+
def initialize(status=nil, body=nil, headers=nil)
|
26
|
+
@status = status.to_i
|
27
|
+
@body = body
|
28
|
+
@headers = headers
|
29
|
+
end
|
30
|
+
|
31
|
+
def finish
|
32
|
+
self.freeze
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class Base
|
37
|
+
|
38
|
+
Settings = {}
|
39
|
+
Settings[:env] = "development"
|
40
|
+
|
41
|
+
attr_accessor :request, :response, :params
|
42
|
+
|
43
|
+
def call(route=nil, params=nil, headers=nil, body=nil)
|
44
|
+
request = Request.new(route, params, headers, body)
|
45
|
+
dup.call!(request)
|
46
|
+
end
|
47
|
+
|
48
|
+
def call!(request)
|
49
|
+
|
50
|
+
@request = request
|
51
|
+
@response = Response.new
|
52
|
+
|
53
|
+
@params = request.params
|
54
|
+
|
55
|
+
invoke { dispatch! }
|
56
|
+
|
57
|
+
@response.finish
|
58
|
+
end
|
59
|
+
|
60
|
+
def current_class
|
61
|
+
self.class
|
62
|
+
end
|
63
|
+
|
64
|
+
def invoke
|
65
|
+
res = catch(Halt) { yield }
|
66
|
+
|
67
|
+
if Array === res
|
68
|
+
res = res.dup
|
69
|
+
|
70
|
+
if status = res.shift
|
71
|
+
response.status = status
|
72
|
+
end
|
73
|
+
|
74
|
+
if body = res.shift
|
75
|
+
response.body = body
|
76
|
+
end
|
77
|
+
else
|
78
|
+
if res
|
79
|
+
response.body = res
|
80
|
+
end
|
81
|
+
end
|
82
|
+
nil
|
83
|
+
end
|
84
|
+
|
85
|
+
def dispatch!
|
86
|
+
filter! :before
|
87
|
+
route!
|
88
|
+
rescue ::Exception => boom
|
89
|
+
gotError = true
|
90
|
+
handle_exception!(boom)
|
91
|
+
ensure
|
92
|
+
begin
|
93
|
+
filter! :after
|
94
|
+
rescue ::Exception => boom
|
95
|
+
handle_exception!(boom) unless gotError
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def handle_exception!(boom)
|
100
|
+
|
101
|
+
response.status = -1
|
102
|
+
|
103
|
+
error_block!(boom.class, boom)
|
104
|
+
|
105
|
+
raise boom
|
106
|
+
end
|
107
|
+
|
108
|
+
def halt(*response)
|
109
|
+
response = response.first if response.length == 1
|
110
|
+
throw Halt, response
|
111
|
+
end
|
112
|
+
|
113
|
+
def filter!(type)
|
114
|
+
current_class.filters[type].each do |args|
|
115
|
+
processRoute(*args)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def route!
|
120
|
+
|
121
|
+
if block = current_class.routes[@request.route.to_sym]
|
122
|
+
processRoute do |*args|
|
123
|
+
routeEval { block[*args] }
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
route_missing
|
128
|
+
end
|
129
|
+
|
130
|
+
def error_block!(errorClass, *blockParams)
|
131
|
+
|
132
|
+
if errorBlocks = current_class.errors[errorClass]
|
133
|
+
errorBlocks.reverse_each do |errorBlock|
|
134
|
+
args = [errorBlock]
|
135
|
+
args += [blockParams]
|
136
|
+
resp = processRoute(*args)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
if errorClass.respond_to? :superclass and errorClass.superclass <= Exception
|
141
|
+
error_block!(errorClass.superclass, *blockParams)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def routeEval
|
146
|
+
throw Halt, yield
|
147
|
+
end
|
148
|
+
|
149
|
+
def processRoute(block=nil,values=[])
|
150
|
+
block ? block[self,values] : yield(self,values)
|
151
|
+
end
|
152
|
+
|
153
|
+
def route_missing
|
154
|
+
raise NotFoundException.new("route not found")
|
155
|
+
end
|
156
|
+
|
157
|
+
def success_response(body, status=0)
|
158
|
+
|
159
|
+
raise "status code must >= 0 when success" if status < 0
|
160
|
+
|
161
|
+
response.body = body
|
162
|
+
response.status = status
|
163
|
+
end
|
164
|
+
|
165
|
+
def failure_response(body, status=-1)
|
166
|
+
|
167
|
+
raise "status code must <= -1 when failure" if status > -1
|
168
|
+
|
169
|
+
response.body = body
|
170
|
+
response.status = status
|
171
|
+
end
|
172
|
+
|
173
|
+
def halt_success(body, status=0)
|
174
|
+
success_response(body, status)
|
175
|
+
halt
|
176
|
+
end
|
177
|
+
|
178
|
+
def halt_failure(body, status=-1)
|
179
|
+
failure_response(body, status)
|
180
|
+
halt
|
181
|
+
end
|
182
|
+
|
183
|
+
class << self
|
184
|
+
|
185
|
+
attr_accessor :routes, :filters, :errors
|
186
|
+
|
187
|
+
def prototype
|
188
|
+
@prototype ||= new
|
189
|
+
end
|
190
|
+
|
191
|
+
def call(route=nil, params=nil, headers=nil, body=nil)
|
192
|
+
prototype.call(route, params, headers, body)
|
193
|
+
end
|
194
|
+
|
195
|
+
def before(&block)
|
196
|
+
add_filter(:before, &block)
|
197
|
+
end
|
198
|
+
|
199
|
+
def after(&block)
|
200
|
+
add_filter(:after, &block)
|
201
|
+
end
|
202
|
+
|
203
|
+
def add_filter(type, &block)
|
204
|
+
@filters[type] << compile!(&block)
|
205
|
+
end
|
206
|
+
|
207
|
+
def route(string, &block)
|
208
|
+
symbol = string.to_sym
|
209
|
+
block ||= Proc.new { method(symbol).call }
|
210
|
+
@routes[symbol] = compile!(&block)
|
211
|
+
end
|
212
|
+
|
213
|
+
def error(*codes, &block)
|
214
|
+
codes = codes.map { |c| Array(c) }.flatten
|
215
|
+
codes << Exception if codes.empty?
|
216
|
+
codes.each { |c| (@errors[c] ||= []) << compile!(&block) }
|
217
|
+
end
|
218
|
+
|
219
|
+
def generateUnboundMethod(&block)
|
220
|
+
methodName = :id #any symbol is ok.
|
221
|
+
define_method(methodName, &block)
|
222
|
+
method = instance_method methodName
|
223
|
+
remove_method methodName
|
224
|
+
method
|
225
|
+
end
|
226
|
+
|
227
|
+
def compile!(&block)
|
228
|
+
|
229
|
+
unboundMethod = generateUnboundMethod(&block)
|
230
|
+
|
231
|
+
block.arity != 0 ?
|
232
|
+
proc { |a,p| unboundMethod.bind(a).call(*p) } :
|
233
|
+
proc { |a,p| unboundMethod.bind(a).call }
|
234
|
+
end
|
235
|
+
|
236
|
+
def inherited(subclass)
|
237
|
+
|
238
|
+
subclass.routes = copy_routes
|
239
|
+
subclass.filters = copy_filters
|
240
|
+
subclass.errors = copy_errors
|
241
|
+
|
242
|
+
super
|
243
|
+
end
|
244
|
+
|
245
|
+
def copy_routes
|
246
|
+
newRoutes = {}
|
247
|
+
@routes.each do |key, value|
|
248
|
+
newRoutes[key] = value
|
249
|
+
end
|
250
|
+
newRoutes
|
251
|
+
end
|
252
|
+
|
253
|
+
def copy_filters
|
254
|
+
newFilters = {}
|
255
|
+
@filters.each do |key, values|
|
256
|
+
newValues = []
|
257
|
+
values.each do |value|
|
258
|
+
newValues << value
|
259
|
+
end
|
260
|
+
newFilters[key] = newValues
|
261
|
+
end
|
262
|
+
newFilters
|
263
|
+
end
|
264
|
+
|
265
|
+
def copy_errors
|
266
|
+
newErrors = {}
|
267
|
+
@errors.each do |key, values|
|
268
|
+
newValues = []
|
269
|
+
values.each do |value|
|
270
|
+
newValues << value
|
271
|
+
end
|
272
|
+
newErrors[key] = newValues
|
273
|
+
end
|
274
|
+
newErrors
|
275
|
+
end
|
276
|
+
|
277
|
+
def to_app
|
278
|
+
|
279
|
+
newApp = Jetra::Application.new(self)
|
280
|
+
@routes.each_key do |route|
|
281
|
+
eval("newApp.define_singleton_method(route) do |params={}| ; @app.call(route, params) ; end ")
|
282
|
+
end
|
283
|
+
|
284
|
+
eval("newApp.define_singleton_method(:method_missing) do |methodName, params={}| ; @app.call(methodName, params) ; end ")
|
285
|
+
|
286
|
+
newApp
|
287
|
+
end
|
288
|
+
|
289
|
+
end
|
290
|
+
|
291
|
+
@routes = {}
|
292
|
+
@filters = {:before => [], :after => []}
|
293
|
+
@errors = {}
|
294
|
+
|
295
|
+
error do |boom|
|
296
|
+
|
297
|
+
raise boom #TODO 因为服务类型不同,错误返回就不同,没法统一默认异常返回结果
|
298
|
+
|
299
|
+
boommsg = "#{boom.class} - #{boom.message}"
|
300
|
+
|
301
|
+
if boom.class == Jetra::NotFoundException
|
302
|
+
trace = []
|
303
|
+
else
|
304
|
+
trace = boom.backtrace
|
305
|
+
trace.unshift boommsg
|
306
|
+
end
|
307
|
+
response.body = {msg: boommsg, class: boom.class.to_s, route: request.route, params: params, trace: trace}
|
308
|
+
halt
|
309
|
+
end
|
310
|
+
|
311
|
+
end
|
312
312
|
end
|