package connectserver import ( "errors" "fmt" "net/http" "sync/atomic" "connectrpc.com/connect" "github.com/XingfenD/yoresee_doc/internal/repository" "github.com/redis/go-redis/v9" pb "github.com/XingfenD/yoresee_doc/pkg/gen/yoresee_doc/v1" "github.com/sirupsen/logrus" "golang.org/x/net/http2" "golang.org/x/net/http2/h2c" "gorm.io/gorm" ) var ( draining atomic.Bool readyDB *gorm.DB readyKVS *redis.Client ) func SetDraining(v bool) { draining.Store(v) } func Start(grpcPort, grpcWebPort int, db *gorm.DB, kvs *redis.Client, repos *repository.Repositories) (*http.Server, *http.Server, error) { readyDB = db readyKVS = kvs allowUnauth := map[string]struct{}{ pb.AuthService_Login_FullMethodName: {}, pb.AuthService_Register_FullMethodName: {}, pb.SystemService_Health_FullMethodName: {}, pb.SystemService_SystemInfo_FullMethodName: {}, } interceptor := UnaryAuthInterceptor(allowUnauth) opts := []connect.HandlerOption{ connect.WithInterceptors(interceptor), } mux := http.NewServeMux() registerHandlers(mux, opts, repos) registerProbeRoutes(mux) handler := withCORS(mux) h2cHandler := h2c.NewHandler(handler, &http2.Server{}) grpcAddr := fmt.Sprintf(":%d", grpcPort) grpcServer := &http.Server{Addr: grpcAddr, Handler: h2cHandler} go func() { if err := grpcServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { logrus.Errorf("grpc server exited unexpectedly: %v", err) } }() grpcWebAddr := fmt.Sprintf(":%d", grpcWebPort) grpcWebServer := &http.Server{Addr: grpcWebAddr, Handler: h2cHandler} go func() { if err := grpcWebServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { logrus.Errorf("grpc-web server exited unexpectedly: %v", err) } }() return grpcServer, grpcWebServer, nil } func withCORS(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { setConnectCorsHeaders(w, r) if r.Method == http.MethodOptions { w.WriteHeader(http.StatusOK) return } next.ServeHTTP(w, r) }) } func setConnectCorsHeaders(w http.ResponseWriter, r *http.Request) { origin := r.Header.Get("Origin") if origin == "" { origin = "*" } w.Header().Set("Access-Control-Allow-Origin", origin) w.Header().Set("Access-Control-Allow-Credentials", "true") w.Header().Set("Access-Control-Allow-Headers", "Accept,Accept-Language,Content-Type,Content-Length,X-Grpc-Web,X-User-Agent,Grpc-Timeout,Authorization,Connect-Protocol-Version") w.Header().Set("Access-Control-Allow-Methods", "POST,GET,OPTIONS") w.Header().Set("Access-Control-Expose-Headers", "Grpc-Status,Grpc-Message,Grpc-Status-Details-Bin,Connect-Protocol-Version") }