package gateway import ( "context" "crypto/tls" "fmt" "io" "io/fs" "mime" "net/http" "os" "strings" "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "github.com/osguydch/ccosproc/insecure" "github.com/osguydch/ccosproc/middleware" usersv1 "github.com/osguydch/ccosproc/proto/device/v3" "github.com/osguydch/ccosproc/third_party" "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/grpclog" ) // getOpenAPIHandler serves an OpenAPI UI. // Adapted from https://github.com/philips/grpc-gateway-example/blob/a269bcb5931ca92be0ceae6130ac27ae89582ecc/cmd/serve.go#L63 func getOpenAPIHandler() http.Handler { mime.AddExtensionType(".svg", "image/svg+xml") // Use subdirectory in embedded files subFS, err := fs.Sub(third_party.OpenAPI, "OpenAPI") if err != nil { panic("couldn't create sub filesystem: " + err.Error()) } return http.FileServer(http.FS(subFS)) } // Run runs the gRPC-Gateway, dialling the provided address. func Run(dialAddr string, httpPort string, supprtSSL string) error { // Adds gRPC internal logs. This is quite verbose, so adjust as desired! log := grpclog.NewLoggerV2(os.Stdout, io.Discard, io.Discard) grpclog.SetLoggerV2(log) // Create a client connection to the gRPC Server we just started. // This is where the gRPC-Gateway proxies the requests. conn, err := grpc.DialContext( context.Background(), dialAddr, grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(insecure.CertPool, "")), //grpc.WithInsecure(), grpc.WithBlock(), ) if err != nil { return fmt.Errorf("failed to dial server: %w", err) } gwmux := runtime.NewServeMux() err = usersv1.RegisterDeviceHandler(context.Background(), gwmux, conn) if err != nil { return fmt.Errorf("failed to register gateway: %w", err) } // 预先创建CORS包装的handlers,避免每次请求重复创建 apiHandler := middleware.Cors(gwmux) moduleHandler := middleware.Cors(http.StripPrefix("/module/", http.FileServer(http.Dir("./DriverDefine")))) dataHandler := middleware.Cors(http.StripPrefix("/Data/", http.FileServer(http.Dir("./RawData")))) openAPIHandler := getOpenAPIHandler() gatewayAddr := "0.0.0.0:" + httpPort gwServer := &http.Server{ Addr: gatewayAddr, Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if strings.HasPrefix(r.URL.Path, "/api") { log.Info("Serving device apis", r.URL.Path) apiHandler.ServeHTTP(w, r) return } if strings.HasPrefix(r.URL.Path, "/module") { log.Info("Serving module definition", r.URL.Path) moduleHandler.ServeHTTP(w, r) return } if strings.HasPrefix(r.URL.Path, "/Data") { log.Info("Serving data file", r.URL.Path) dataHandler.ServeHTTP(w, r) return } openAPIHandler.ServeHTTP(w, r) }), } if supprtSSL != "ON" { log.Info("Serving gRPC-Gateway and OpenAPI Documentation on http://", gatewayAddr) return fmt.Errorf("serving gRPC-Gateway server: %w", gwServer.ListenAndServe()) } gwServer.TLSConfig = &tls.Config{ Certificates: []tls.Certificate{insecure.Cert}, } log.Info("Serving gRPC-Gateway and OpenAPI Documentation on https://", gatewayAddr) return fmt.Errorf("serving gRPC-Gateway server: %w", gwServer.ListenAndServeTLS("", "")) }