2023-05-28 00:54:04 +00:00
|
|
|
package beacon
|
|
|
|
|
|
|
|
import (
|
2023-12-16 18:12:40 +00:00
|
|
|
"context"
|
2023-06-08 07:43:27 +00:00
|
|
|
"net"
|
2023-05-28 00:54:04 +00:00
|
|
|
"net/http"
|
2023-12-04 23:13:52 +00:00
|
|
|
"strings"
|
2023-05-28 00:54:04 +00:00
|
|
|
|
2023-12-04 23:13:52 +00:00
|
|
|
"github.com/go-chi/chi/v5"
|
2024-01-02 22:29:00 +00:00
|
|
|
"github.com/go-chi/cors"
|
2023-11-15 14:07:16 +00:00
|
|
|
"github.com/ledgerwatch/erigon/cl/beacon/beacon_router_configuration"
|
2023-06-08 07:43:27 +00:00
|
|
|
"github.com/ledgerwatch/erigon/cl/beacon/handler"
|
2023-12-04 23:13:52 +00:00
|
|
|
"github.com/ledgerwatch/erigon/cl/beacon/validatorapi"
|
2023-06-08 07:43:27 +00:00
|
|
|
"github.com/ledgerwatch/log/v3"
|
2023-05-28 00:54:04 +00:00
|
|
|
)
|
|
|
|
|
2023-12-04 23:13:52 +00:00
|
|
|
type LayeredBeaconHandler struct {
|
|
|
|
ValidatorApi *validatorapi.ValidatorApiHandler
|
|
|
|
ArchiveApi *handler.ApiHandler
|
|
|
|
}
|
|
|
|
|
|
|
|
func ListenAndServe(beaconHandler *LayeredBeaconHandler, routerCfg beacon_router_configuration.RouterConfiguration) error {
|
2023-06-08 07:43:27 +00:00
|
|
|
listener, err := net.Listen(routerCfg.Protocol, routerCfg.Address)
|
2023-12-04 23:13:52 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer listener.Close()
|
|
|
|
mux := chi.NewRouter()
|
2024-01-02 22:29:00 +00:00
|
|
|
|
|
|
|
mux.Use(cors.Handler(
|
|
|
|
cors.Options{
|
|
|
|
AllowedOrigins: routerCfg.AllowedOrigins,
|
|
|
|
AllowedMethods: routerCfg.AllowedMethods,
|
|
|
|
AllowCredentials: routerCfg.AllowCredentials,
|
|
|
|
MaxAge: 4,
|
|
|
|
}))
|
2023-12-04 23:13:52 +00:00
|
|
|
// enforce json content type
|
|
|
|
mux.Use(func(h http.Handler) http.Handler {
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
contentType := r.Header.Get("Content-Type")
|
|
|
|
if len(contentType) > 0 && !strings.EqualFold(contentType, "application/json") {
|
|
|
|
http.Error(w, "Content-Type header must be application/json", http.StatusUnsupportedMediaType)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
h.ServeHTTP(w, r)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
// layered handling - 404 on first handler falls back to the second
|
|
|
|
mux.HandleFunc("/eth/*", func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
nfw := ¬FoundNoWriter{rw: w}
|
|
|
|
beaconHandler.ValidatorApi.ServeHTTP(nfw, r)
|
2023-12-16 18:12:40 +00:00
|
|
|
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, chi.NewRouteContext()))
|
|
|
|
if isNotFound(nfw.code) || nfw.code == 0 {
|
2023-12-04 23:13:52 +00:00
|
|
|
beaconHandler.ArchiveApi.ServeHTTP(w, r)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
mux.HandleFunc("/validator/*", func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
http.StripPrefix("/validator", beaconHandler.ValidatorApi).ServeHTTP(w, r)
|
|
|
|
})
|
|
|
|
mux.HandleFunc("/archive/*", func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
http.StripPrefix("/archive", beaconHandler.ArchiveApi).ServeHTTP(w, r)
|
|
|
|
})
|
2023-06-08 07:43:27 +00:00
|
|
|
server := &http.Server{
|
2023-12-04 23:13:52 +00:00
|
|
|
Handler: mux,
|
2023-06-08 07:43:27 +00:00
|
|
|
ReadTimeout: routerCfg.ReadTimeTimeout,
|
|
|
|
IdleTimeout: routerCfg.IdleTimeout,
|
|
|
|
WriteTimeout: routerCfg.IdleTimeout,
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
log.Warn("[Beacon API] Failed to start listening", "addr", routerCfg.Address, "err", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := server.Serve(listener); err != nil {
|
|
|
|
log.Warn("[Beacon API] failed to start serving", "addr", routerCfg.Address, "err", err)
|
2023-12-04 23:13:52 +00:00
|
|
|
return err
|
2023-06-08 07:43:27 +00:00
|
|
|
}
|
2023-12-04 23:13:52 +00:00
|
|
|
return nil
|
|
|
|
}
|