/
server_http.go
135 lines (106 loc) · 2.86 KB
/
server_http.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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package geoipfix
import (
"context"
"fmt"
"net/http"
"strconv"
"time"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"github.com/go-chi/cors"
"github.com/go-chi/render"
"go.uber.org/zap"
)
type handler func(w http.ResponseWriter, r *http.Request) error
// httpServer is an HTTP server.
type httpServer struct {
srv http.Server
cfg serverHTTPConfig
mux *chi.Mux
opt options
recover *recoverMiddleware
}
// newHTTPServer retrieves a new HTTPServer instance.
func newHTTPServer(cfg serverHTTPConfig, opts ...option) *httpServer {
opt := newOptions(opts...)
srv := &httpServer{
cfg: cfg,
}
opt.Logger = opt.Logger.With(zap.String("server", srv.Name()))
srv.opt = opt
return srv
}
func (h *httpServer) Name() string {
return "http"
}
// handle handles an handler and captures error.
func (h *httpServer) handle(f handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
err := f(w, r)
if err != nil {
h.recover.Handle(err)
}
}
}
// Init initializes http server instance.
func (h *httpServer) Init() error {
r := chi.NewRouter()
h.recover = newRecoverMiddleware(h.opt.Debug, h.opt.Logger)
cors := cors.New(cors.Options{
AllowedOrigins: h.cfg.Cors.AllowedOrigins,
AllowedMethods: h.cfg.Cors.AllowedMethods,
AllowedHeaders: h.cfg.Cors.AllowedHeaders,
ExposedHeaders: h.cfg.Cors.ExposedHeaders,
AllowCredentials: h.cfg.Cors.AllowCredentials,
MaxAge: h.cfg.Cors.MaxAge,
})
r.Use(h.recover.Handler)
r.Use(middleware.RealIP)
r.Use(cors.Handler)
r.Use(middleware.RequestID)
r.Use(newLoggerMiddleware(h.opt.Logger))
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
render.Status(r, http.StatusOK)
})
r.Get("/sys/health", func(w http.ResponseWriter, r *http.Request) {
headers := map[string]string{}
for k, v := range r.Header {
if k == "Cookie" {
continue
}
headers[k] = v[0]
}
render.DefaultResponder(w, r, render.M{
"remote_addr": r.RemoteAddr,
"headers": headers,
"status": "OK",
"version": Version,
"revision": Revision,
"build_time": BuildTime,
"compiler": Compiler,
})
})
handler := httpHandler{h.opt}
r.Get("/json/{ipAddress}", h.handle(handler.GetLocation))
r.Get("/json/", h.handle(handler.GetLocation))
h.mux = r
return nil
}
// Serve serves http requests.
func (h *httpServer) Serve(ctx context.Context) error {
addr := fmt.Sprintf(":%s", strconv.Itoa(h.cfg.Port))
h.srv = http.Server{
Addr: addr,
Handler: chi.ServerBaseContext(ctx, h.mux),
}
h.opt.Logger.Info("Launch server", zap.String("addr", addr))
return h.srv.ListenAndServe()
}
// Shutdown stops the http server.
func (h *httpServer) Shutdown() error {
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
err := h.srv.Shutdown(ctx)
h.opt.Logger.Info("Server shutdown")
return err
}