-
Notifications
You must be signed in to change notification settings - Fork 5
/
http.cr
117 lines (101 loc) · 3.66 KB
/
http.cr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
require "onyx-http"
require "../onyx"
module Onyx
{% for method in Onyx::HTTP::Middleware::Router::HTTP_METHODS %}
# Define a {{method.upcase.id}} route with block for the top-level `.router`.
# See `HTTP::Router#{{method.id}}`.
def self.{{method.id}}(*args, **nargs, &block : ::HTTP::Server::Context -> Nil)
Onyx::HTTP::Singleton.instance.router.{{method.id}}(*args, **nargs, &block)
end
# Define a {{method.upcase.id}} route for the top-level `.router`.
# See `HTTP::Router#{{method.id}}`.
def self.{{method.id}}(*args, **nargs)
Onyx::HTTP::Singleton.instance.router.{{method.id}}(*args, **nargs)
end
{% end %}
# Define a "ws://" route with block for the top-level `.router`.
# See `HTTP::Router#ws`.
def self.ws(*args, **nargs, &block : ::HTTP::WebSocket, ::HTTP::Server::Context -> Nil)
Onyx::HTTP::Singleton.instance.router.ws(*args, **nargs, &block)
end
# ditto
def self.ws(*args, **nargs)
Onyx::HTTP::Singleton.instance.router.ws(*args, **nargs)
end
# Draw routes for the top-level `.router`.
# See `HTTP::Router#draw`.
def self.draw(&block)
with Onyx::HTTP::Singleton.instance.router yield
end
# The top-level `HTTP::Router` instance.
def self.router
Onyx::HTTP::Singleton.instance.router
end
# Render a template at *path* into *io* with [Kilt](https://github.com/jeromegn/kilt).
#
# ```
# Onyx.render(env.response, "./hello.html.ecr")
# # Expands to
# Kilt.embed("./hello.html.ecr", env.response)
# ```
macro render(io, path)
Kilt.embed({{path}}, {{io}})
end
def self.renderer=(value)
HTTP::Singleton.instance.renderer = value
end
def self.renderer
HTTP::Singleton.instance.renderer
end
# Instantiate an `Onyx::HTTP::Server`, bind it to the *host* and *port* and start listening.
# Routes for it are defined with top-level `Onyx.get` methods and its siblings.
#
# You can insert your custom code into the `&block`.
# At this point, `handlers` variable will be available.
macro listen(host = "127.0.0.1", port = 5000, reuse_port = false, **handler_options, &block)
handlers = Onyx::HTTP::Singleton.instance.handlers({{handler_options.double_splat}})
{{yield.id}}
server = Onyx::HTTP::Server.new(handlers, logger: Onyx.logger)
server.bind_tcp({{host}}, {{port}}, reuse_port: {{reuse_port}})
server.listen
end
module HTTP
# The singleton instance of an Onyx HTTP server wrapper.
# It is **not** initialized unless called.
class Singleton
# The singleton instance.
def self.instance
@@instance ||= new
end
@router = Middleware::Router.new
# The singleton `HTTP::Router` instance.
property router
@renderer : ::HTTP::Handler = Middleware::Renderer.new(
verbose: ENV["CRYSTAL_ENV"]? != "production"
)
# The singleton renderer instance.
property renderer
# The default set of handlers. See its source code to find out which handlers in particular.
# You can in theory modify these handlers in the `Onyx.listen` block.
def handlers(cors = nil)
[
Middleware::ResponseTime.new,
Middleware::RequestID.new,
Middleware::Logger.new(
Onyx.logger,
query: ENV["CRYSTAL_ENV"]? != "production"
),
cors ? Middleware::CORS.new(**cors) : Middleware::CORS.new,
Middleware::Rescuer::Standard(Exception).new(
renderer,
Onyx.logger,
verbose: true, # Always be verbose with unhandled exceptions
),
Middleware::Rescuer::Error.new(renderer),
router,
renderer,
].compact!
end
end
end
end