93 lines
2.8 KiB
Go
93 lines
2.8 KiB
Go
// Command gunk-example-server-gw is a grpc-gateway example implementation for
|
|
// the gunk-example-server.
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
|
codequestpb "github.com/hhhapz/codequest/api/v1"
|
|
"github.com/peterbourgon/ff/v3"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/grpclog"
|
|
"google.golang.org/protobuf/encoding/protojson"
|
|
)
|
|
|
|
func main() {
|
|
fs := flag.NewFlagSet("codequest", flag.ExitOnError)
|
|
|
|
addr := fs.String("l", "0.0.0.0:8080", "listen address")
|
|
endpoint := fs.String("endpoint", "localhost:10000", "grpc endpoint")
|
|
|
|
if err := ff.Parse(fs, os.Args[1:], ff.WithEnvVarPrefix("CQ")); err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
if err := run(context.Background(), *addr, *endpoint); err != nil {
|
|
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
// run creates and runs the gateway instance.
|
|
func run(ctx context.Context, addr, endpoint string) error {
|
|
// build gateway mux
|
|
gw, opts := runtime.NewServeMux(
|
|
runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.JSONPb{
|
|
MarshalOptions: protojson.MarshalOptions{
|
|
EmitUnpopulated: true,
|
|
},
|
|
}),
|
|
), []grpc.DialOption{grpc.WithInsecure()}
|
|
for _, f := range []func(context.Context, *runtime.ServeMux, string, []grpc.DialOption) error{
|
|
codequestpb.RegisterAuthServiceHandlerFromEndpoint,
|
|
codequestpb.RegisterUserServiceHandlerFromEndpoint,
|
|
codequestpb.RegisterQuestServiceHandlerFromEndpoint,
|
|
} {
|
|
if err := f(ctx, gw, endpoint, opts); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
log := grpclog.NewLoggerV2(io.Discard, os.Stderr, os.Stderr)
|
|
grpclog.SetLoggerV2(log)
|
|
log.Info("Serving gateway on http://", addr)
|
|
|
|
server := &http.Server{
|
|
Addr: addr,
|
|
Handler: allowCORS(gw),
|
|
}
|
|
return server.ListenAndServe()
|
|
}
|
|
|
|
// allowCORS allows Cross Origin Resoruce Sharing from any origin.
|
|
// Don't do this without consideration in production systems.
|
|
func allowCORS(h http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if origin := r.Header.Get("Origin"); origin != "" {
|
|
w.Header().Set("Access-Control-Allow-Origin", origin)
|
|
if r.Method == "OPTIONS" && r.Header.Get("Access-Control-Request-Method") != "" {
|
|
preflightHandler(w, r)
|
|
return
|
|
}
|
|
}
|
|
h.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
|
|
// preflightHandler adds the necessary headers in order to serve
|
|
// CORS from any origin using the methods "GET", "HEAD", "POST", "PUT", "DELETE"
|
|
// We insist, don't do this without consideration in production systems.
|
|
func preflightHandler(w http.ResponseWriter, r *http.Request) {
|
|
headers := []string{"Content-Type", "Accept", "Authorization"}
|
|
w.Header().Set("Access-Control-Allow-Headers", strings.Join(headers, ","))
|
|
methods := []string{"GET", "HEAD", "POST", "PUT", "DELETE"}
|
|
w.Header().Set("Access-Control-Allow-Methods", strings.Join(methods, ","))
|
|
}
|