github.com/resonatecoop/user-api@v1.0.0-13.0.20220915120639-05dc9c04014a/gateway/gateway.go (about)

     1  package gateway
     2  
     3  import (
     4  	"context"
     5  	"crypto/tls"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"mime"
     9  	"net/http"
    10  	"os"
    11  	"strings"
    12  
    13  	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
    14  	"github.com/rakyll/statik/fs"
    15  	"google.golang.org/grpc"
    16  	"google.golang.org/grpc/credentials"
    17  	"google.golang.org/grpc/grpclog"
    18  
    19  	"github.com/resonatecoop/user-api/insecure"
    20  	pbUser "github.com/resonatecoop/user-api/proto/user"
    21  
    22  	// Static files
    23  	_ "github.com/resonatecoop/user-api/statik"
    24  )
    25  
    26  // getOpenAPIHandler serves an OpenAPI UI.
    27  // Adapted from https://github.com/philips/grpc-gateway-example/blob/a269bcb5931ca92be0ceae6130ac27ae89582ecc/cmd/serve.go#L63
    28  func getOpenAPIHandler() http.Handler {
    29  	mime.AddExtensionType(".svg", "image/svg+xml")
    30  
    31  	statikFS, err := fs.New()
    32  	if err != nil {
    33  		// Panic since this is a permanent error.
    34  		panic("creating OpenAPI filesystem: " + err.Error())
    35  	}
    36  
    37  	return http.FileServer(statikFS)
    38  }
    39  
    40  // Run runs the gRPC-Gateway, dialling the provided address.
    41  func Run(dialAddr string) error {
    42  	// Adds gRPC internal logs. This is quite verbose, so adjust as desired!
    43  	log := grpclog.NewLoggerV2(os.Stdout, ioutil.Discard, ioutil.Discard)
    44  	grpclog.SetLoggerV2(log)
    45  
    46  	// Create a client connection to the gRPC Server we just started.
    47  	// This is where the gRPC-Gateway proxies the requests.
    48  	conn, err := grpc.DialContext(
    49  		context.Background(),
    50  		dialAddr,
    51  		grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(insecure.CertPool, "")),
    52  		grpc.WithBlock(),
    53  	)
    54  	if err != nil {
    55  		return fmt.Errorf("failed to dial server: %w", err)
    56  	}
    57  
    58  	gwmux := runtime.NewServeMux()
    59  	err = pbUser.RegisterResonateUserHandler(context.Background(), gwmux, conn)
    60  
    61  	if err != nil {
    62  		return fmt.Errorf("failed to register gateway: %w", err)
    63  	}
    64  
    65  	oa := getOpenAPIHandler()
    66  
    67  	port := os.Getenv("PORT")
    68  	if port == "" {
    69  		port = "11000"
    70  	}
    71  	gatewayAddr := "0.0.0.0:" + port
    72  	gwServer := &http.Server{
    73  		Addr: gatewayAddr,
    74  		Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    75  			if strings.HasPrefix(r.URL.Path, "/api") {
    76  				gwmux.ServeHTTP(w, r)
    77  				return
    78  			}
    79  			oa.ServeHTTP(w, r)
    80  		}),
    81  	}
    82  	// Empty parameters mean use the TLS Config specified with the server.
    83  	if strings.ToLower(os.Getenv("SERVE_HTTP")) == "true" {
    84  		log.Info("Serving gRPC-Gateway and OpenAPI Documentation on http://", gatewayAddr)
    85  		return fmt.Errorf("serving gRPC-Gateway server: %w", gwServer.ListenAndServe())
    86  	}
    87  
    88  	gwServer.TLSConfig = &tls.Config{
    89  		Certificates: []tls.Certificate{insecure.Cert},
    90  	}
    91  	log.Info("Serving gRPC-Gateway and OpenAPI Documentation on https://", gatewayAddr)
    92  	return fmt.Errorf("serving gRPC-Gateway server: %w", gwServer.ListenAndServeTLS("", ""))
    93  }