1
- local encode = require " cjson.safe" . encode
1
+ local json = require " cjson.safe"
2
2
local bit = bit
3
3
local gmatch = string.gmatch
4
4
local ipairs = ipairs
@@ -15,6 +15,15 @@ local ngx_var = ngx.var
15
15
local string_format = string.format
16
16
local xpcall = xpcall
17
17
local spawn = ngx .thread .spawn
18
+ local ngx_req = ngx .req
19
+ local decode = json .decode
20
+ local encode = json .encode
21
+ local get_post_args = ngx .req .get_post_args
22
+ local read_body = ngx .req .read_body
23
+ local get_body_data = ngx .req .get_body_data
24
+ local assert = assert
25
+ local rawget = rawget
26
+ local setmetatable = setmetatable
18
27
19
28
local method_bitmask = {
20
29
GET = 1 , -- 2^0
@@ -351,100 +360,131 @@ function Router:emit(event_key, ...)
351
360
end
352
361
end
353
362
363
+ local Response = {
364
+ header = ngx_header ,
365
+ get_headers = ngx_req .get_headers ,
366
+ }
367
+ Response .__index = Response
368
+
369
+ local Context = {
370
+ yield = coroutine.yield
371
+ }
372
+ --- @private
373
+ function Context .__index (self , key )
374
+ if Context [key ] ~= nil then
375
+ return Context [key ]
376
+ elseif ngx_req [key ] ~= nil then
377
+ return ngx_req [key ]
378
+ elseif key == ' response' then
379
+ return setmetatable ({}, Response )
380
+ elseif key == ' query' then
381
+ self .query = ngx_req .get_uri_args ()
382
+ return rawget (self , ' query' )
383
+ else
384
+ return nil
385
+ end
386
+ end
387
+
354
388
--- @return table
355
389
function Router :create_context ()
356
- return setmetatable ({ yield = coroutine.yield }, ngx . req )
390
+ return setmetatable ({}, Context )
357
391
end
358
392
359
393
--- @param path string
360
394
--- @param method string
361
395
--- @return boolean
362
396
--- @overload fun ( string , string ): boolean
363
397
function Router :dispatch (path , method )
364
- local handler , params_or_code = self :match (path , method )
365
- if handler == nil then
366
- return self :fail (' match route failed' , {}, params_or_code )
367
- end
368
-
398
+ -- before plugins
369
399
local ctx = self :create_context ()
370
- if params_or_code then
371
- ctx .params = params_or_code
372
- end
373
-
374
400
for _ , plugin in ipairs (self .plugins ) do
375
401
local co = coroutine.create (function ()
376
402
plugin (ctx )
377
403
end )
378
404
local ok , err = resume (co )
379
405
if not ok then
380
- return self :fail (err , ctx , 500 )
406
+ return self :fail (ctx , err )
381
407
end
382
408
if coroutine.status (co ) == " suspended" then
383
409
ctx [# ctx + 1 ] = co
384
410
end
385
411
end
386
-
412
+ -- match route
413
+ local handler , params_or_code = self :match (path , method )
414
+ if handler == nil then
415
+ return self :fail (ctx , ' match route failed' , params_or_code )
416
+ end
417
+ if params_or_code then
418
+ ctx .params = params_or_code
419
+ end
387
420
if type (handler ) == ' string' then
388
- return self :ok (handler , ctx )
421
+ return self :ok (ctx , handler )
389
422
else
390
423
--- @diagnostic disable-next-line : param-type-mismatch
391
- local ok , result , err = xpcall (handler , trace_back , ctx )
424
+ local ok , result , err_or_okcode , errcode = xpcall (handler , trace_back , ctx )
392
425
if not ok then
393
- return self :fail (result , ctx , 500 )
426
+ return self :fail (ctx , result )
394
427
elseif result == nil then
395
- return self :fail (err , ctx , 500 )
428
+ if err_or_okcode ~= nil then
429
+ return self :fail (ctx , err_or_okcode , errcode )
430
+ elseif rawget (ctx , ' response' ) then
431
+ local code = ctx .response .status or 200
432
+ return self :finish (ctx , code , ngx .exit , code )
433
+ else
434
+ return self :fail (ctx , ' no response' )
435
+ end
396
436
else
397
437
local resp_type = type (result )
398
438
if resp_type == ' table' or resp_type == ' boolean' or resp_type == ' number' then
399
- local json , encode_err = encode (result )
400
- if not json then
401
- return self :fail (encode_err , ctx )
439
+ local response_json , encode_err = encode (result )
440
+ if not response_json then
441
+ return self :fail (ctx , encode_err )
402
442
else
403
443
ngx_header .content_type = ' application/json; charset=utf-8'
404
- return self :ok (json , ctx )
444
+ return self :ok (ctx , response_json , err_or_okcode )
405
445
end
406
446
elseif resp_type == ' string' then
407
447
if byte (result ) == 60 then -- 60 is ASCII value of '<'
408
448
ngx_header .content_type = ' text/html; charset=utf-8'
409
449
else
410
450
ngx_header .content_type = ' text/plain; charset=utf-8'
411
451
end
412
- return self :ok (result , ctx )
452
+ return self :ok (ctx , result , err_or_okcode )
413
453
elseif type (result ) == ' function' then
414
- ok , result , err = xpcall (result , trace_back )
454
+ ok , result , err_or_okcode , errcode = xpcall (result , trace_back , ctx )
415
455
if not ok then
416
- return self :fail (result , ctx , 500 )
456
+ return self :fail (ctx , result )
417
457
elseif result == nil then
418
- return self :fail ( err , ctx , 500 )
458
+ return self :finish ( ctx , 500 , ngx . exit , 500 )
419
459
else
420
- return self :finish (200 , ctx )
460
+ return self :finish (ctx , 200 , ngx . exit , 200 )
421
461
end
422
462
else
423
- return self :fail (' invalid response type: ' .. resp_type )
463
+ return self :fail (ctx , ' invalid response type: ' .. resp_type )
424
464
end
425
465
end
426
466
end
427
467
end
428
468
429
- function Router :ok (body , ctx , code )
469
+ function Router :ok (ctx , body , code )
430
470
ngx_print (body )
431
471
code = code or 200
432
- return self :finish (code , ctx , ngx .exit , code )
472
+ return self :finish (ctx , code , ngx .exit , code )
433
473
end
434
474
435
- function Router :fail (err , ctx , code )
475
+ function Router :fail (ctx , err , code )
436
476
ngx_print (err )
437
477
code = code or 500
438
- return self :finish (code , ctx , ngx .exit , code )
478
+ return self :finish (ctx , code , ngx .exit , code )
439
479
end
440
480
441
481
function Router :redirect (ctx , uri , code )
442
482
code = code or 302
443
- return self :finish (code , ctx , ngx .redirect , uri , code )
483
+ return self :finish (ctx , code , ngx .redirect , uri , code )
444
484
end
445
485
446
- function Router :exec (uri , args , ctx )
447
- return self :finish (200 , ctx , ngx .exec , uri , args )
486
+ function Router :exec (ctx , uri , args )
487
+ return self :finish (ctx , ngx . OK , ngx .exec , uri , args )
448
488
end
449
489
450
490
local function get_event_key (events , code )
@@ -467,7 +507,7 @@ local function get_event_key(events, code)
467
507
end
468
508
end
469
509
470
- function Router :finish (code , ctx , ngx_func , ...)
510
+ function Router :finish (ctx , code , ngx_func , ...)
471
511
local events = self .events
472
512
if events [code ] then
473
513
self :emit (code , ctx )
@@ -485,4 +525,8 @@ function Router:finish(code, ctx, ngx_func, ...)
485
525
return ngx_func (... )
486
526
end
487
527
528
+ function Router :run ()
529
+ return self :dispatch (ngx_var .document_uri , ngx_var .request_method )
530
+ end
531
+
488
532
return Router
0 commit comments