dn42grcd/server.go
2020-10-10 18:51:45 +01:00

148 lines
3.7 KiB
Go

//////////////////////////////////////////////////////////////////////////
// API to serve the internal data structures
//////////////////////////////////////////////////////////////////////////
package main
//////////////////////////////////////////////////////////////////////////
import (
"context"
"github.com/gorilla/mux"
log "github.com/sirupsen/logrus"
"net/http"
"os"
"time"
)
//////////////////////////////////////////////////////////////////////////
type APIServer struct {
data *DataStruct
server *http.Server
router *mux.Router
}
//////////////////////////////////////////////////////////////////////////
// http request logger
func requestLogger(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.WithFields(log.Fields{
"method": r.Method,
"URL": r.URL.String(),
"Remote": r.RemoteAddr,
}).Debug("HTTP Request")
next.ServeHTTP(w, r)
})
}
//////////////////////////////////////////////////////////////////////////
// start the API servers
func StartAPIServer(bindAddress string, data *DataStruct,
staticRoot string) *APIServer {
api := &APIServer{
data: data,
router: mux.NewRouter(),
}
// initialise http server
api.server = &http.Server{
Addr: bindAddress,
WriteTimeout: time.Second * 15,
ReadTimeout: time.Second * 15,
IdleTimeout: time.Second * 60,
Handler: api.router,
}
// add the api
api.router.Use(requestLogger)
s := api.router.Methods("GET").PathPrefix("/api").Subrouter()
s.HandleFunc("/flaps", api.handleFlaps)
s.HandleFunc("/roa", api.handleROA)
api.installStaticRoutes(staticRoot)
// run the server in a non-blocking goroutine
log.WithFields(log.Fields{
"BindAddress": bindAddress,
}).Info("Starting server")
go func() {
if err := api.server.ListenAndServe(); err != nil {
log.WithFields(log.Fields{
"error": err,
"BindAddress": bindAddress,
}).Fatal("Unable to start server")
}
}()
return api
}
//////////////////////////////////////////////////////////////////////////
// shutdown the API Server
func (api *APIServer) Shutdown(ctx context.Context) {
api.server.Shutdown(ctx)
}
//////////////////////////////////////////////////////////////////////////
// handler funcs
func (api *APIServer) handleFlaps(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Write(api.data.snapshot.route.ToJSON())
}
func (api *APIServer) handleROA(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Write(api.data.snapshot.roa.ToJSON())
}
//////////////////////////////////////////////////////////////////////////
// static route handler
func (api *APIServer) installStaticRoutes(staticPath string) {
// an empty path disables static route serving
if staticPath == "" {
log.Info("Disabling static route serving")
return
}
// validate that the staticPath exists
stat, err := os.Stat(staticPath)
if err != nil {
log.WithFields(log.Fields{
"error": err,
"path": staticPath,
}).Fatal("Unable to find static page directory")
}
// and it is a directory
if !stat.IsDir() {
log.WithFields(log.Fields{
"error": err,
"path": staticPath,
}).Fatal("Static path is not a directory")
}
// install a file server for the static route
api.router.PathPrefix("/").Handler(http.StripPrefix("/",
http.FileServer(http.Dir(staticPath)))).Methods("GET")
log.WithFields(log.Fields{
"path": staticPath,
}).Info("Static route installed")
}
//////////////////////////////////////////////////////////////////////////
// end of file