148 lines
3.7 KiB
Go
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
|