prysm-pulse/beacon-chain/server/main.go
Radosław Kapka ff99a2ed40
Run text/event-stream values returned from grpc-gateway through API Middleware (#9080)
* register events handler in v1

* begin `status.Error` messages with uppercase

* something works

* handle errors

* topic comments

* handle the rest of event types

* gzl

* make code more testable + test

* better error handling

* tests

* gzl

* fix deps

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
2021-06-24 16:18:28 +00:00

137 lines
4.3 KiB
Go

// Package main allows for creation of an HTTP-JSON to gRPC
// gateway as a binary go process.
package main
import (
"context"
"flag"
"fmt"
"net/http"
"strings"
gwruntime "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
joonix "github.com/joonix/log"
"github.com/prysmaticlabs/prysm/beacon-chain/rpc/apimiddleware"
pbrpc "github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1"
ethpbv1 "github.com/prysmaticlabs/prysm/proto/eth/v1"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/shared/gateway"
_ "github.com/prysmaticlabs/prysm/shared/maxprocs"
"github.com/sirupsen/logrus"
"google.golang.org/protobuf/encoding/protojson"
)
var (
beaconRPC = flag.String("beacon-rpc", "localhost:4000", "Beacon chain gRPC endpoint")
port = flag.Int("port", 8000, "Port to serve on")
apiMiddlewarePort = flag.Int("port", 8001, "Port to serve API middleware on")
host = flag.String("host", "127.0.0.1", "Host to serve on")
debug = flag.Bool("debug", false, "Enable debug logging")
allowedOrigins = flag.String("corsdomain", "localhost:4242", "A comma separated list of CORS domains to allow")
enableDebugRPCEndpoints = flag.Bool("enable-debug-rpc-endpoints", false, "Enable debug rpc endpoints such as /eth/v1alpha1/beacon/state")
grpcMaxMsgSize = flag.Int("grpc-max-msg-size", 1<<22, "Integer to define max recieve message call size")
)
func init() {
logrus.SetFormatter(joonix.NewFormatter())
}
func main() {
flag.Parse()
if *debug {
log.SetLevel(logrus.DebugLevel)
}
v1Alpha1Registrations := []gateway.PbHandlerRegistration{
ethpb.RegisterNodeHandler,
ethpb.RegisterBeaconChainHandler,
ethpb.RegisterBeaconNodeValidatorHandler,
pbrpc.RegisterHealthHandler,
}
v1Registrations := []gateway.PbHandlerRegistration{
ethpbv1.RegisterBeaconNodeHandler,
ethpbv1.RegisterBeaconChainHandler,
ethpbv1.RegisterBeaconValidatorHandler,
ethpbv1.RegisterEventsHandler,
}
if *enableDebugRPCEndpoints {
v1Alpha1Registrations = append(v1Alpha1Registrations, pbrpc.RegisterDebugHandler)
v1Registrations = append(v1Registrations, ethpbv1.RegisterBeaconDebugHandler)
}
v1Alpha1Mux := gwruntime.NewServeMux(
gwruntime.WithMarshalerOption(gwruntime.MIMEWildcard, &gwruntime.HTTPBodyMarshaler{
Marshaler: &gwruntime.JSONPb{
MarshalOptions: protojson.MarshalOptions{
EmitUnpopulated: true,
},
UnmarshalOptions: protojson.UnmarshalOptions{
DiscardUnknown: true,
},
},
}),
gwruntime.WithMarshalerOption(
"text/event-stream", &gwruntime.EventSourceJSONPb{},
),
)
v1Mux := gwruntime.NewServeMux(
gwruntime.WithMarshalerOption(gwruntime.MIMEWildcard, &gwruntime.HTTPBodyMarshaler{
Marshaler: &gwruntime.JSONPb{
MarshalOptions: protojson.MarshalOptions{
UseProtoNames: true,
EmitUnpopulated: true,
},
UnmarshalOptions: protojson.UnmarshalOptions{
DiscardUnknown: true,
},
},
}),
)
muxHandler := func(h http.Handler, w http.ResponseWriter, req *http.Request) {
h.ServeHTTP(w, req)
}
v1Alpha1PbHandler := gateway.PbMux{
Registrations: v1Alpha1Registrations,
Patterns: []string{"/eth/v1alpha1/"},
Mux: v1Alpha1Mux,
}
v1PbHandler := gateway.PbMux{
Registrations: v1Registrations,
Patterns: []string{"/eth/v1/"},
Mux: v1Mux,
}
gw := gateway.New(
context.Background(),
[]gateway.PbMux{v1Alpha1PbHandler, v1PbHandler},
muxHandler,
*beaconRPC,
fmt.Sprintf("%s:%d", *host, *port),
).WithAllowedOrigins(strings.Split(*allowedOrigins, ",")).
WithMaxCallRecvMsgSize(uint64(*grpcMaxMsgSize)).
WithApiMiddleware(fmt.Sprintf("%s:%d", *host, *apiMiddlewarePort), &apimiddleware.BeaconEndpointFactory{})
mux := http.NewServeMux()
mux.HandleFunc("/swagger/", gateway.SwaggerServer())
mux.HandleFunc("/healthz", healthzServer(gw))
gw = gw.WithMux(mux)
gw.Start()
select {}
}
// healthzServer returns a simple health handler which returns ok.
func healthzServer(gw *gateway.Gateway) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
if err := gw.Status(); err != nil {
http.Error(w, err.Error(), http.StatusBadGateway)
return
}
if _, err := fmt.Fprintln(w, "ok"); err != nil {
log.WithError(err).Error("failed to respond to healthz")
}
}
}