-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
server.go
136 lines (115 loc) · 3.39 KB
/
server.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
136
package server
import (
"context"
"net/http"
"time"
"github.com/NYTimes/gziphandler"
"github.com/Pigmice2733/peregrine-backend/internal/config"
ihttp "github.com/Pigmice2733/peregrine-backend/internal/http"
"github.com/Pigmice2733/peregrine-backend/internal/store"
"github.com/Pigmice2733/peregrine-backend/internal/tba"
"github.com/sirupsen/logrus"
)
//go:generate go run ../cmd/pack/pack.go -package server -in openapi.yaml -out openapi.go -name openAPI
var openAPI []byte
// Server is the scouting API server
type Server struct {
config.Server
TBA tba.Service
Store store.Service
Logger *logrus.Logger
eventsLastUpdate *time.Time
start time.Time
}
// Run starts the server, and returns if it runs into an error
func (s *Server) Run(ctx context.Context) error {
router := s.registerRoutes()
var handler http.Handler = router
handler = ihttp.LimitBody(handler)
handler = gziphandler.GzipHandler(handler)
handler = ihttp.Log(handler, s.Logger)
handler = ihttp.Auth(handler, s.Secret)
handler = ihttp.CORS(handler, s.Origin)
s.Logger.Info("fetching seed events")
if err := s.updateEvents(ctx); err != nil {
s.Logger.WithError(err).Error("updating event data on server run")
}
httpServer := &http.Server{
Addr: s.HTTPAddress,
Handler: handler,
ReadTimeout: time.Second * 15,
ReadHeaderTimeout: time.Second * 15,
WriteTimeout: time.Second * 15,
IdleTimeout: time.Second * 30,
MaxHeaderBytes: 4096,
}
defer httpServer.Close()
errs := make(chan error)
s.start = time.Now()
go func() {
s.Logger.WithField("httpAddress", s.HTTPAddress).Info("serving http")
errs <- httpServer.ListenAndServe()
}()
if s.CertFile != "" && s.KeyFile != "" {
httpsServer := &http.Server{
Addr: s.HTTPSAddress,
Handler: handler,
ReadTimeout: time.Second * 15,
ReadHeaderTimeout: time.Second * 15,
WriteTimeout: time.Second * 15,
IdleTimeout: time.Second * 30,
MaxHeaderBytes: 4096,
}
defer httpsServer.Close()
go func() {
s.Logger.WithField("httpsAddress", s.HTTPSAddress).Info("serving https")
errs <- httpsServer.ListenAndServeTLS(s.CertFile, s.KeyFile)
}()
}
select {
case err := <-errs:
return err
case <-ctx.Done():
return nil
}
}
type listen struct {
HTTP string `json:"http,omitempty"`
HTTPS string `json:"https,omitempty"`
}
type services struct {
TBA bool `json:"tba"`
PostgreSQL bool `json:"postgresql"`
}
type status struct {
StartTime int64 `json:"startTime"`
Uptime int64 `json:"uptime"`
Listen listen `json:"listen"`
Services services `json:"services"`
Ok bool `json:"ok"`
}
func (s *Server) openAPIHandler() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/x-yaml")
w.Write(openAPI)
}
}
func (s *Server) healthHandler() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
tbaHealthy := s.TBA.Ping(r.Context()) == nil
pgHealthy := s.Store.Ping(r.Context()) == nil
ihttp.Respond(w, status{
StartTime: s.start.Unix(),
Uptime: int64(time.Since(s.start).Seconds()),
Listen: listen{
HTTP: s.HTTPAddress,
HTTPS: s.HTTPSAddress,
},
Services: services{
TBA: tbaHealthy,
PostgreSQL: pgHealthy,
},
Ok: tbaHealthy && pgHealthy,
}, http.StatusOK)
}
}