mirror of
https://github.com/aljazceru/ark.git
synced 2025-12-18 12:44:19 +01:00
Add grpc-gateway and /healthz endpoint (#133)
* Add grpc-gateway and /healthz endpoint * Add nolint * nosec
This commit is contained in:
committed by
GitHub
parent
f135869928
commit
f9e7621165
@@ -32,13 +32,8 @@ func (c Config) address() string {
|
|||||||
return fmt.Sprintf(":%d", c.Port)
|
return fmt.Sprintf(":%d", c.Port)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Config) listener() net.Listener {
|
func (c Config) gatewayAddress() string {
|
||||||
lis, _ := net.Listen("tcp", c.address())
|
return fmt.Sprintf("localhost:%d", c.Port)
|
||||||
|
|
||||||
if c.insecure() {
|
|
||||||
return lis
|
|
||||||
}
|
|
||||||
return tls.NewListener(lis, c.tlsConfig())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Config) tlsConfig() *tls.Config {
|
func (c Config) tlsConfig() *tls.Config {
|
||||||
|
|||||||
29
server/internal/interface/grpc/handlers/healthservice.go
Normal file
29
server/internal/interface/grpc/handlers/healthservice.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
grpchealth "google.golang.org/grpc/health/grpc_health_v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type healthHandler struct{}
|
||||||
|
|
||||||
|
func NewHealthHandler() grpchealth.HealthServer {
|
||||||
|
return &healthHandler{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *healthHandler) Check(
|
||||||
|
_ context.Context,
|
||||||
|
_ *grpchealth.HealthCheckRequest,
|
||||||
|
) (*grpchealth.HealthCheckResponse, error) {
|
||||||
|
return &grpchealth.HealthCheckResponse{
|
||||||
|
Status: grpchealth.HealthCheckResponse_SERVING,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *healthHandler) Watch(
|
||||||
|
_ *grpchealth.HealthCheckRequest,
|
||||||
|
_ grpchealth.Health_WatchServer,
|
||||||
|
) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -1,22 +1,32 @@
|
|||||||
package grpcservice
|
package grpcservice
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1"
|
arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1"
|
||||||
appconfig "github.com/ark-network/ark/internal/app-config"
|
appconfig "github.com/ark-network/ark/internal/app-config"
|
||||||
interfaces "github.com/ark-network/ark/internal/interface"
|
interfaces "github.com/ark-network/ark/internal/interface"
|
||||||
"github.com/ark-network/ark/internal/interface/grpc/handlers"
|
"github.com/ark-network/ark/internal/interface/grpc/handlers"
|
||||||
"github.com/ark-network/ark/internal/interface/grpc/interceptors"
|
"github.com/ark-network/ark/internal/interface/grpc/interceptors"
|
||||||
|
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
"golang.org/x/net/http2"
|
||||||
|
"golang.org/x/net/http2/h2c"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/credentials"
|
||||||
"google.golang.org/grpc/credentials/insecure"
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
|
grpchealth "google.golang.org/grpc/health/grpc_health_v1"
|
||||||
|
"google.golang.org/protobuf/encoding/protojson"
|
||||||
)
|
)
|
||||||
|
|
||||||
type service struct {
|
type service struct {
|
||||||
config Config
|
config Config
|
||||||
appConfig *appconfig.Config
|
appConfig *appconfig.Config
|
||||||
server *grpc.Server
|
server *http.Server
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(
|
func NewService(
|
||||||
@@ -36,16 +46,79 @@ func NewService(
|
|||||||
return nil, fmt.Errorf("tls termination not supported yet")
|
return nil, fmt.Errorf("tls termination not supported yet")
|
||||||
}
|
}
|
||||||
creds := insecure.NewCredentials()
|
creds := insecure.NewCredentials()
|
||||||
|
if !svcConfig.insecure() {
|
||||||
|
creds = credentials.NewTLS(svcConfig.tlsConfig())
|
||||||
|
}
|
||||||
grpcConfig = append(grpcConfig, grpc.Creds(creds))
|
grpcConfig = append(grpcConfig, grpc.Creds(creds))
|
||||||
server := grpc.NewServer(grpcConfig...)
|
|
||||||
handler := handlers.NewHandler(appConfig.AppService())
|
// Server grpc.
|
||||||
arkv1.RegisterArkServiceServer(server, handler)
|
grpcServer := grpc.NewServer(grpcConfig...)
|
||||||
|
appHandler := handlers.NewHandler(appConfig.AppService())
|
||||||
|
arkv1.RegisterArkServiceServer(grpcServer, appHandler)
|
||||||
|
healthHandler := handlers.NewHealthHandler()
|
||||||
|
grpchealth.RegisterHealthServer(grpcServer, healthHandler)
|
||||||
|
|
||||||
|
// Creds for grpc gateway reverse proxy.
|
||||||
|
gatewayCreds := insecure.NewCredentials()
|
||||||
|
if !svcConfig.insecure() {
|
||||||
|
gatewayCreds = credentials.NewTLS(&tls.Config{
|
||||||
|
InsecureSkipVerify: true, // #nosec
|
||||||
|
})
|
||||||
|
}
|
||||||
|
gatewayOpts := grpc.WithTransportCredentials(gatewayCreds)
|
||||||
|
ctx := context.Background()
|
||||||
|
conn, err := grpc.DialContext(
|
||||||
|
ctx, svcConfig.gatewayAddress(), gatewayOpts,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Reverse proxy grpc-gateway.
|
||||||
|
gwmux := runtime.NewServeMux(
|
||||||
|
runtime.WithHealthzEndpoint(grpchealth.NewHealthClient(conn)),
|
||||||
|
runtime.WithMarshalerOption("application/json+pretty", &runtime.JSONPb{
|
||||||
|
MarshalOptions: protojson.MarshalOptions{
|
||||||
|
Indent: " ",
|
||||||
|
Multiline: true,
|
||||||
|
},
|
||||||
|
UnmarshalOptions: protojson.UnmarshalOptions{
|
||||||
|
DiscardUnknown: true,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
if err := arkv1.RegisterArkServiceHandler(
|
||||||
|
ctx, gwmux, conn,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
grpcGateway := http.Handler(gwmux)
|
||||||
|
|
||||||
|
handler := router(grpcServer, grpcGateway)
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.Handle("/", handler)
|
||||||
|
|
||||||
|
httpServerHandler := http.Handler(mux)
|
||||||
|
if svcConfig.insecure() {
|
||||||
|
httpServerHandler = h2c.NewHandler(httpServerHandler, &http2.Server{})
|
||||||
|
}
|
||||||
|
|
||||||
|
server := &http.Server{
|
||||||
|
Addr: svcConfig.address(),
|
||||||
|
Handler: httpServerHandler,
|
||||||
|
TLSConfig: svcConfig.tlsConfig(),
|
||||||
|
}
|
||||||
|
|
||||||
return &service{svcConfig, appConfig, server}, nil
|
return &service{svcConfig, appConfig, server}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) Start() error {
|
func (s *service) Start() error {
|
||||||
// nolint:all
|
if s.config.insecure() {
|
||||||
go s.server.Serve(s.config.listener())
|
// nolint:all
|
||||||
|
go s.server.ListenAndServe()
|
||||||
|
} else {
|
||||||
|
// nolint:all
|
||||||
|
go s.server.ListenAndServeTLS("", "")
|
||||||
|
}
|
||||||
log.Infof("started listening at %s", s.config.address())
|
log.Infof("started listening at %s", s.config.address())
|
||||||
|
|
||||||
if err := s.appConfig.AppService().Start(); err != nil {
|
if err := s.appConfig.AppService().Start(); err != nil {
|
||||||
@@ -57,8 +130,41 @@ func (s *service) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) Stop() {
|
func (s *service) Stop() {
|
||||||
s.server.Stop()
|
// nolint:all
|
||||||
|
s.server.Shutdown(context.Background())
|
||||||
log.Info("stopped grpc server")
|
log.Info("stopped grpc server")
|
||||||
s.appConfig.AppService().Stop()
|
s.appConfig.AppService().Stop()
|
||||||
log.Info("stopped app service")
|
log.Info("stopped app service")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func router(
|
||||||
|
grpcServer *grpc.Server, grpcGateway http.Handler,
|
||||||
|
) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if isOptionRequest(r) {
|
||||||
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
|
w.Header().Set("Access-Control-Allow-Headers", "*")
|
||||||
|
w.Header().Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if isHttpRequest(r) {
|
||||||
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
|
w.Header().Set("Access-Control-Allow-Headers", "*")
|
||||||
|
w.Header().Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
|
||||||
|
|
||||||
|
grpcGateway.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
grpcServer.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func isOptionRequest(req *http.Request) bool {
|
||||||
|
return req.Method == http.MethodOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
func isHttpRequest(req *http.Request) bool {
|
||||||
|
return req.Method == http.MethodGet ||
|
||||||
|
strings.Contains(req.Header.Get("Content-Type"), "application/json")
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user