package api import ( _ "FamilyHub/src/api/docs" "FamilyHub/src/api/routers" "FamilyHub/src/api/services" "FamilyHub/src/config" "FamilyHub/src/database" "FamilyHub/src/integrations/ocr" "FamilyHub/src/integrations/receiptProvider" "FamilyHub/src/repositories" "context" "log" "net/http" "net/http/httptest" "os" "strings" "github.com/gin-gonic/gin" swaggerFiles "github.com/swaggo/files" ginSwagger "github.com/swaggo/gin-swagger" ) type Server struct { httpServer *http.Server ocr ocr.OCR } func NewServer(cfg config.Config) *Server { dbManager := &database.Database{ ConnectionString: cfg.DBConnectionString, MigrationsPath: "file://migrations", } dbConn, err := dbManager.Connect() if err != nil { log.Fatal(err) } if err := dbManager.RunMigrations(dbConn); err != nil { log.Fatal(err) } if !cfg.DebugMode { gin.SetMode(gin.ReleaseMode) } router := gin.New() router.Use(gin.Logger()) //router.Use(requestLoggingMiddleware()) router.Use(gin.RecoveryWithWriter(os.Stderr)) if cfg.OpenAPIEnabled { openAPIEndpoint := cfg.OpenAPIEndpoint if openAPIEndpoint == "" { openAPIEndpoint = "/openapi" } swaggerHandler := ginSwagger.WrapHandler(swaggerFiles.Handler) serveSwaggerIndex := func(c *gin.Context) { recorder := httptest.NewRecorder() proxyCtx, _ := gin.CreateTestContext(recorder) proxyCtx.Request = c.Request.Clone(c.Request.Context()) proxyCtx.Request.URL.Path = openAPIEndpoint + "/index.html" proxyCtx.Request.RequestURI = openAPIEndpoint + "/index.html" swaggerHandler(proxyCtx) for key, values := range recorder.Header() { for _, value := range values { c.Writer.Header().Add(key, value) } } body := strings.Replace( recorder.Body.String(), "", "", 1, ) c.Status(recorder.Code) _, _ = c.Writer.WriteString(body) } router.GET(openAPIEndpoint, serveSwaggerIndex) router.GET(openAPIEndpoint+"/*any", func(c *gin.Context) { if c.Param("any") == "/" { serveSwaggerIndex(c) return } swaggerHandler(c) }) } apiV1 := router.Group("/api/v1") transactionRepo := repositories.NewTransactionsSQLRepository(dbConn) activityRepo := repositories.NewActivitySQLRepository(dbConn) ocrSvc, err := ocr.NewGoogleOCR(context.Background()) if err != nil { log.Fatal(err) } receiptRepo := repositories.NewReceiptsSQLRepository(dbConn) receiptProvider_ := receiptProvider.NewReceiptProvider() receiptService := services.NewReceiptService(receiptProvider_, receiptRepo, transactionRepo) transactionService := services.NewTransactionService(transactionRepo, activityRepo) transactionCreationService := services.NewTransactionCreationService(transactionService, receiptService, ocrSvc) transactionRouter := routers.NewTransactionsRouter(transactionService, transactionCreationService) transactionRouter.RegisterRoutes(apiV1) activityService := services.NewActivityService(activityRepo) activityRouter := routers.NewActivitiesRouter(activityService) activityRouter.RegisterRoutes(apiV1) usersRepo := repositories.NewUsersSQLRepository(dbConn) usersService := services.NewUserService(usersRepo) usersRouter := routers.NewUsersRouter(usersService) usersRouter.RegisterRoutes(apiV1) familyRepo := repositories.NewFamilySQLRepository(dbConn) familyService := services.NewFamilyService(familyRepo) familyRouter := routers.NewFamiliesRouter(familyService) familyRouter.RegisterRoutes(apiV1) otpRepo := repositories.NewOTPSQLRepository(dbConn) authService := services.NewAuthService(usersRepo, otpRepo) authRouter := routers.NewAuthRouter(authService) authRouter.RegisterRouter(apiV1) // подключаем статику Vue — должно быть последним registerStaticFiles(router, "src/api/dist") return &Server{ httpServer: &http.Server{ Addr: cfg.APIHost + ":" + cfg.APIPort, Handler: router, }, ocr: ocrSvc, } } func (s *Server) Start() error { return s.httpServer.ListenAndServe() } func (s *Server) Shutdown(ctx context.Context) error { if s.ocr != nil { _ = s.ocr.Close() } return s.httpServer.Shutdown(ctx) }