-
Notifications
You must be signed in to change notification settings - Fork 0
/
tinyserver.go
102 lines (82 loc) · 2.98 KB
/
tinyserver.go
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
package tinyserver
import (
"log"
"net/http"
)
// Server is a top-level abstraction for the web server
type Server struct {
// Routes stores each route separately
Routes []*Route
// HTTPServer is the primary HTTP server
HTTPServer *http.Server
// Router is the primary request router
Router *http.ServeMux
// Middlewares stores global middlewares
Middlewares []Middleware
}
// NewServer creates a new instance of Server and returns a reference to it
func NewServer() (*Server, error) {
// Create a new instance of the server
server := &Server{}
// Create a new request router
server.Router = http.NewServeMux()
// Add default middlewares
err := server.AddMiddleware(JSONMiddleware) // TODO: Instead of adding default middlewares, expose this with something like a "EnableJSON" function?
// Add default routes
err = server.AddRoute("/", func(w http.ResponseWriter, r *http.Request) {})
// Return the server instance and a potential error
return server, err
}
// AddRoute constructs and stores a new route
func (server *Server) AddRoute(path string, handler func(w http.ResponseWriter, r *http.Request)) error {
//route := &Route{Path: path, Handler: http.HandlerFunc(handler)}
route, err := NewRoute()
if err != nil {
log.Panic(err)
}
route.Path = path
route.Handler = http.HandlerFunc(handler)
server.Routes = append(server.Routes, route)
return nil
}
// AddMiddleware adds one or more global middleware
func (server *Server) AddMiddleware(middlewares ...MiddlewareFunc) error {
for _, middleware := range middlewares {
server.Middlewares = append(server.Middlewares, middleware)
}
return nil
}
// Listen starts the HTTP server on the specified port (synchronous/blocking)
func (server *Server) Listen(port string) error {
server.initialize(port)
// FIXME: ListenAndServe always returns a non-nil error. After Shutdown or Close, the returned error is ErrServerClosed
err := server.HTTPServer.ListenAndServe()
return err
}
// ListenAsync starts the HTTP server on the specified port (asynchronous/non-blocking)
func (server *Server) ListenAsync(port string) {
server.initialize(port)
// FIXME: ListenAndServe always returns a non-nil error. After Shutdown or Close, the returned error is ErrServerClosed
go server.HTTPServer.ListenAndServe()
}
// Close the HTTP server and cleanup after ourselves
func (server *Server) Close() error {
log.Println("Closing server..")
return server.HTTPServer.Close()
}
// Internal server initialization logic
func (server *Server) initialize(port string) {
server.HTTPServer = &http.Server{Addr: ":" + port, Handler: server.Router}
// Setup routes and middlewares
for _, route := range server.Routes {
log.Println("Adding route", route.Path)
// Apply each middleware to this route
handler := route.Handler
for _, middleware := range server.Middlewares {
handler = middleware.Middleware(handler)
}
// Add the route with the final handler
server.Router.Handle(route.Path, handler)
}
log.Println("Server listening on port", port)
}