Use nested module declaration
This commit is contained in:
parent
4edebcf8eb
commit
f7484d14d3
9 changed files with 176 additions and 160 deletions
|
@ -1,12 +1,14 @@
|
|||
# All loggers must inherit from `Kemal::BaseLogHandler`.
|
||||
class Kemal::BaseLogHandler < HTTP::Handler
|
||||
def initialize
|
||||
end
|
||||
module Kemal
|
||||
# All loggers must inherit from `Kemal::BaseLogHandler`.
|
||||
class Kemal::BaseLogHandler < HTTP::Handler
|
||||
def initialize
|
||||
end
|
||||
|
||||
def call(context)
|
||||
call_next context
|
||||
end
|
||||
def call(context)
|
||||
call_next context
|
||||
end
|
||||
|
||||
def write(message)
|
||||
def write(message)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,33 +1,35 @@
|
|||
class Kemal::CommonLogHandler < Kemal::BaseLogHandler
|
||||
@handler : IO::FileDescriptor
|
||||
getter handler
|
||||
module Kemal
|
||||
class CommonLogHandler < Kemal::BaseLogHandler
|
||||
@handler : IO::FileDescriptor
|
||||
getter handler
|
||||
|
||||
def initialize
|
||||
@handler = STDOUT
|
||||
end
|
||||
def initialize
|
||||
@handler = STDOUT
|
||||
end
|
||||
|
||||
def call(context)
|
||||
time = Time.now
|
||||
call_next(context)
|
||||
elapsed_text = elapsed_text(Time.now - time)
|
||||
@handler << time << " " << context.response.status_code << " " << context.request.method << " " << context.request.resource << " " << elapsed_text << "\n"
|
||||
context
|
||||
end
|
||||
def call(context)
|
||||
time = Time.now
|
||||
call_next(context)
|
||||
elapsed_text = elapsed_text(Time.now - time)
|
||||
@handler << time << " " << context.response.status_code << " " << context.request.method << " " << context.request.resource << " " << elapsed_text << "\n"
|
||||
context
|
||||
end
|
||||
|
||||
def write(message)
|
||||
@handler << message
|
||||
end
|
||||
def write(message)
|
||||
@handler << message
|
||||
end
|
||||
|
||||
private def elapsed_text(elapsed)
|
||||
minutes = elapsed.total_minutes
|
||||
return "#{minutes.round(2)}m" if minutes >= 1
|
||||
private def elapsed_text(elapsed)
|
||||
minutes = elapsed.total_minutes
|
||||
return "#{minutes.round(2)}m" if minutes >= 1
|
||||
|
||||
seconds = elapsed.total_seconds
|
||||
return "#{seconds.round(2)}s" if seconds >= 1
|
||||
seconds = elapsed.total_seconds
|
||||
return "#{seconds.round(2)}s" if seconds >= 1
|
||||
|
||||
millis = elapsed.total_milliseconds
|
||||
return "#{millis.round(2)}ms" if millis >= 1
|
||||
millis = elapsed.total_milliseconds
|
||||
return "#{millis.round(2)}ms" if millis >= 1
|
||||
|
||||
"#{(millis * 1000).round(2)}µs"
|
||||
"#{(millis * 1000).round(2)}µs"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
module Kemal::Middleware
|
||||
# This middleware adds SSL / TLS support.
|
||||
class SSL
|
||||
getter context
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# This is here to represent the logger corresponding to Null Object Pattern.
|
||||
class Kemal::NullLogHandler < Kemal::BaseLogHandler
|
||||
module Kemal
|
||||
# This is here to represent the logger corresponding to Null Object Pattern.
|
||||
class NullLogHandler < Kemal::BaseLogHandler
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,73 +1,75 @@
|
|||
require "json"
|
||||
|
||||
# ParamParser parses the request contents including query_params and body
|
||||
# and converts them into a params hash which you can within the environment
|
||||
# context.
|
||||
alias AllParamTypes = Nil | String | Int64 | Float64 | Bool | Hash(String, JSON::Type) | Array(JSON::Type)
|
||||
module Kemal
|
||||
# ParamParser parses the request contents including query_params and body
|
||||
# and converts them into a params hash which you can within the environment
|
||||
# context.
|
||||
alias AllParamTypes = Nil | String | Int64 | Float64 | Bool | Hash(String, JSON::Type) | Array(JSON::Type)
|
||||
|
||||
class Kemal::ParamParser
|
||||
URL_ENCODED_FORM = "application/x-www-form-urlencoded"
|
||||
APPLICATION_JSON = "application/json"
|
||||
class ParamParser
|
||||
URL_ENCODED_FORM = "application/x-www-form-urlencoded"
|
||||
APPLICATION_JSON = "application/json"
|
||||
|
||||
def initialize(@request : HTTP::Request)
|
||||
@url = {} of String => String
|
||||
@query = HTTP::Params.new({} of String => Array(String))
|
||||
@body = HTTP::Params.new({} of String => Array(String))
|
||||
@json = {} of String => AllParamTypes
|
||||
@url_parsed = false
|
||||
@query_parsed = false
|
||||
@body_parsed = false
|
||||
@json_parsed = false
|
||||
end
|
||||
def initialize(@request : HTTP::Request)
|
||||
@url = {} of String => String
|
||||
@query = HTTP::Params.new({} of String => Array(String))
|
||||
@body = HTTP::Params.new({} of String => Array(String))
|
||||
@json = {} of String => AllParamTypes
|
||||
@url_parsed = false
|
||||
@query_parsed = false
|
||||
@body_parsed = false
|
||||
@json_parsed = false
|
||||
end
|
||||
|
||||
{% for method in %w(url query body json) %}
|
||||
def {{method.id}}
|
||||
# check memoization
|
||||
return @{{method.id}} if @{{method.id}}_parsed
|
||||
{% for method in %w(url query body json) %}
|
||||
def {{method.id}}
|
||||
# check memoization
|
||||
return @{{method.id}} if @{{method.id}}_parsed
|
||||
|
||||
parse_{{method.id}}
|
||||
# memoize
|
||||
@{{method.id}}_parsed = true
|
||||
@{{method.id}}
|
||||
end
|
||||
{% end %}
|
||||
parse_{{method.id}}
|
||||
# memoize
|
||||
@{{method.id}}_parsed = true
|
||||
@{{method.id}}
|
||||
end
|
||||
{% end %}
|
||||
|
||||
def parse_body
|
||||
return if (@request.headers["Content-Type"]? =~ /#{URL_ENCODED_FORM}/).nil?
|
||||
@body = parse_part(@request.body)
|
||||
end
|
||||
def parse_body
|
||||
return if (@request.headers["Content-Type"]? =~ /#{URL_ENCODED_FORM}/).nil?
|
||||
@body = parse_part(@request.body)
|
||||
end
|
||||
|
||||
def parse_query
|
||||
@query = parse_part(@request.query)
|
||||
end
|
||||
def parse_query
|
||||
@query = parse_part(@request.query)
|
||||
end
|
||||
|
||||
def parse_url
|
||||
if params = @request.url_params
|
||||
params.each do |key, value|
|
||||
@url[key.as(String)] = value.as(String)
|
||||
def parse_url
|
||||
if params = @request.url_params
|
||||
params.each do |key, value|
|
||||
@url[key.as(String)] = value.as(String)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Parses JSON request body if Content-Type is `application/json`.
|
||||
# If request body is a JSON Hash then all the params are parsed and added into `params`.
|
||||
# If request body is a JSON Array it's added into `params` as `_json` and can be accessed
|
||||
# like params["_json"]
|
||||
def parse_json
|
||||
return unless @request.body && @request.headers["Content-Type"]? == APPLICATION_JSON
|
||||
# Parses JSON request body if Content-Type is `application/json`.
|
||||
# If request body is a JSON Hash then all the params are parsed and added into `params`.
|
||||
# If request body is a JSON Array it's added into `params` as `_json` and can be accessed
|
||||
# like params["_json"]
|
||||
def parse_json
|
||||
return unless @request.body && @request.headers["Content-Type"]? == APPLICATION_JSON
|
||||
|
||||
body = @request.body.as(String)
|
||||
case json = JSON.parse(body).raw
|
||||
when Hash
|
||||
json.each do |key, value|
|
||||
@json[key.as(String)] = value.as(AllParamTypes)
|
||||
body = @request.body.as(String)
|
||||
case json = JSON.parse(body).raw
|
||||
when Hash
|
||||
json.each do |key, value|
|
||||
@json[key.as(String)] = value.as(AllParamTypes)
|
||||
end
|
||||
when Array
|
||||
@json["_json"] = json
|
||||
end
|
||||
when Array
|
||||
@json["_json"] = json
|
||||
end
|
||||
end
|
||||
|
||||
def parse_part(part)
|
||||
HTTP::Params.parse(part || "")
|
||||
def parse_part(part)
|
||||
HTTP::Params.parse(part || "")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
# Route is the main building block of Kemal.
|
||||
# It takes 3 parameters: Method, path and a block to specify
|
||||
# what action to be done if the route is matched.
|
||||
class Kemal::Route
|
||||
getter handler
|
||||
@handler : HTTP::Server::Context -> String
|
||||
@method : String
|
||||
module Kemal
|
||||
# Route is the main building block of Kemal.
|
||||
# It takes 3 parameters: Method, path and a block to specify
|
||||
# what action to be done if the route is matched.
|
||||
class Route
|
||||
getter handler
|
||||
@handler : HTTP::Server::Context -> String
|
||||
@method : String
|
||||
|
||||
def initialize(@method, @path : String, &handler : HTTP::Server::Context -> _)
|
||||
@handler = ->(context : HTTP::Server::Context) { handler.call(context).to_s }
|
||||
def initialize(@method, @path : String, &handler : HTTP::Server::Context -> _)
|
||||
@handler = ->(context : HTTP::Server::Context) { handler.call(context).to_s }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,53 +1,54 @@
|
|||
require "http/server"
|
||||
require "radix"
|
||||
|
||||
# Kemal::RouteHandler is the main handler which handles all the HTTP requests. Routing, parsing, rendering e.g
|
||||
# are done in this handler.
|
||||
class Kemal::RouteHandler < HTTP::Handler
|
||||
INSTANCE = new
|
||||
module Kemal
|
||||
# Kemal::RouteHandler is the main handler which handles all the HTTP requests. Routing, parsing, rendering e.g
|
||||
# are done in this handler.
|
||||
class RouteHandler < HTTP::Handler
|
||||
INSTANCE = new
|
||||
|
||||
property tree
|
||||
property tree
|
||||
|
||||
def initialize
|
||||
@tree = Radix::Tree(Route).new
|
||||
end
|
||||
|
||||
def call(context)
|
||||
context.response.headers.add "X-Powered-By", "Kemal"
|
||||
context.response.content_type = "text/html" unless context.response.headers.has_key?("Content-Type")
|
||||
process_request(context)
|
||||
end
|
||||
|
||||
# Adds a given route to routing tree. As an exception each `GET` route additionaly defines
|
||||
# a corresponding `HEAD` route.
|
||||
def add_route(method, path, &handler : HTTP::Server::Context -> _)
|
||||
add_to_radix_tree method, path, Route.new(method, path, &handler)
|
||||
add_to_radix_tree("HEAD", path, Route.new("HEAD", path, &handler)) if method == "GET"
|
||||
end
|
||||
|
||||
# Check if a route is defined and returns the lookup
|
||||
def lookup_route(verb, path)
|
||||
@tree.find radix_path(verb, path)
|
||||
end
|
||||
|
||||
# Processes the route if it's a match. Otherwise renders 404.
|
||||
def process_request(context)
|
||||
raise Kemal::Exceptions::RouteNotFound.new(context) unless context.route_defined?
|
||||
route = context.route_lookup.payload.as(Route)
|
||||
content = route.handler.call(context)
|
||||
if Kemal.config.error_handlers.has_key?(context.response.status_code)
|
||||
raise Kemal::Exceptions::CustomException.new(context)
|
||||
def initialize
|
||||
@tree = Radix::Tree(Route).new
|
||||
end
|
||||
context.response.print(content)
|
||||
context
|
||||
end
|
||||
|
||||
private def radix_path(method : String, path)
|
||||
"/#{method.downcase}#{path}"
|
||||
end
|
||||
def call(context)
|
||||
context.response.headers.add "X-Powered-By", "Kemal"
|
||||
context.response.content_type = "text/html" unless context.response.headers.has_key?("Content-Type")
|
||||
process_request(context)
|
||||
end
|
||||
|
||||
private def add_to_radix_tree(method, path, route)
|
||||
node = radix_path method, path
|
||||
@tree.add node, route
|
||||
# Adds a given route to routing tree. As an exception each `GET` route additionaly defines
|
||||
# a corresponding `HEAD` route.
|
||||
def add_route(method, path, &handler : HTTP::Server::Context -> _)
|
||||
add_to_radix_tree method, path, Route.new(method, path, &handler)
|
||||
add_to_radix_tree("HEAD", path, Route.new("HEAD", path, &handler)) if method == "GET"
|
||||
end
|
||||
|
||||
# Check if a route is defined and returns the lookup
|
||||
def lookup_route(verb, path)
|
||||
@tree.find radix_path(verb, path)
|
||||
end
|
||||
|
||||
# Processes the route if it's a match. Otherwise renders 404.
|
||||
def process_request(context)
|
||||
raise Kemal::Exceptions::RouteNotFound.new(context) unless context.route_defined?
|
||||
route = context.route_lookup.payload.as(Route)
|
||||
content = route.handler.call(context)
|
||||
if Kemal.config.error_handlers.has_key?(context.response.status_code)
|
||||
raise Kemal::Exceptions::CustomException.new(context)
|
||||
end
|
||||
context.response.print(content)
|
||||
context
|
||||
end
|
||||
|
||||
private def radix_path(method : String, path)
|
||||
"/#{method.downcase}#{path}"
|
||||
end
|
||||
|
||||
private def add_to_radix_tree(method, path, route)
|
||||
node = radix_path method, path
|
||||
@tree.add node, route
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
# Kemal::StaticFileHandler is used to serve static files(.js/.css/.png e.g).
|
||||
# This handler is on by default and you can disable it like.
|
||||
#
|
||||
# serve_static false
|
||||
#
|
||||
class Kemal::StaticFileHandler < HTTP::StaticFileHandler
|
||||
def call(context)
|
||||
return call_next(context) if context.request.path.not_nil! == "/"
|
||||
super
|
||||
module Kemal
|
||||
# Kemal::StaticFileHandler is used to serve static files(.js/.css/.png e.g).
|
||||
# This handler is on by default and you can disable it like.
|
||||
#
|
||||
# serve_static false
|
||||
#
|
||||
class StaticFileHandler < HTTP::StaticFileHandler
|
||||
def call(context)
|
||||
return call_next(context) if context.request.path.not_nil! == "/"
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
# Kemal::WebSocketHandler is used for building a WebSocket route.
|
||||
# For each WebSocket route a new handler is created and registered to global handlers.
|
||||
class Kemal::WebSocketHandler < HTTP::WebSocketHandler
|
||||
def initialize(@path : String, &@proc : HTTP::WebSocket, HTTP::Server::Context -> Void)
|
||||
Kemal.config.add_ws_handler self
|
||||
end
|
||||
module Kemal
|
||||
# Kemal::WebSocketHandler is used for building a WebSocket route.
|
||||
# For each WebSocket route a new handler is created and registered to global handlers.
|
||||
class WebSocketHandler < HTTP::WebSocketHandler
|
||||
def initialize(@path : String, &@proc : HTTP::WebSocket, HTTP::Server::Context -> Void)
|
||||
Kemal.config.add_ws_handler self
|
||||
end
|
||||
|
||||
def call(context)
|
||||
return call_next(context) unless context.request.path.not_nil! == @path
|
||||
super
|
||||
def call(context)
|
||||
return call_next(context) unless context.request.path.not_nil! == @path
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue