package main import ( "flag" "fmt" "log" "net" "os" "os/signal" "syscall" "github.com/cloudprint/cloudprint-backend/config" "github.com/cloudprint/cloudprint-backend/internal/grpc" "github.com/cloudprint/cloudprint-backend/internal/grpc/interceptor" "github.com/cloudprint/cloudprint-backend/internal/grpc/service" "github.com/cloudprint/cloudprint-backend/internal/model" "github.com/cloudprint/cloudprint-backend/internal/repository" "github.com/cloudprint/cloudprint-backend/internal/service" "github.com/cloudprint/cloudprint-backend/pkg/jwt" "github.com/cloudprint/cloudprint-backend/pkg/pay" "github.com/cloudprint/cloudprint-backend/pkg/upload" pb "github.com/cloudprint/cloudprint-backend/proto/generated" "go.uber.org/zap" "google.golang.org/grpc" "gorm.io/driver/mysql" "gorm.io/gorm" "gorm.io/gorm/logger" ) func main() { configPath := flag.String("config", "config.yaml", "path to config file") flag.Parse() // Load configuration cfg, err := config.LoadConfig(*configPath) if err != nil { log.Fatalf("Failed to load config: %v", err) } // Initialize logger zapLogger, _ := zap.NewProduction() defer zapLogger.Sync() // Initialize database db, err := initDB(cfg) if err != nil { log.Fatalf("Failed to initialize database: %v", err) } // Auto migrate if err := db.AutoMigrate( &model.User{}, &model.Admin{}, &model.Printer{}, &model.Order{}, &model.OrderItem{}, &model.File{}, &model.LibraryCategory{}, &model.LibraryFile{}, &model.PrintJob{}, &model.PriceList{}, &model.Payment{}, ); err != nil { log.Fatalf("Failed to migrate database: %v", err) } // Initialize repositories userRepo := repository.NewUserRepository(db) adminRepo := repository.NewAdminRepository(db) fileRepo := repository.NewFileRepository(db) orderRepo := repository.NewOrderRepository(db) orderItemRepo := repository.NewOrderItemRepository(db) printerRepo := repository.NewPrinterRepository(db) printJobRepo := repository.NewPrintJobRepository(db) libraryRepo := repository.NewLibraryRepository(db) priceRepo := repository.NewPriceRepository(db) paymentRepo := repository.NewPaymentRepository(db) // Initialize JWT manager jwtManager := jwt.NewJWTManager( cfg.JWT.Secret, cfg.JWT.AccessTokenTTL, cfg.JWT.RefreshTokenTTL, ) // Initialize file uploader fileUploader := upload.NewFileUploader( cfg.Upload.Path, cfg.Upload.ChunkPath, cfg.Upload.MaxSize, ) // Initialize WeChat pay weChatPay := pay.NewWeChatPay(&cfg.WeChat) // Initialize services authService := service.NewAuthService(userRepo, adminRepo, jwtManager, nil, &cfg.WeChat) fileService := service.NewFileService(fileRepo, fileUploader, cfg.Upload.Path) orderService := service.NewOrderService(orderRepo, orderItemRepo, fileRepo, priceRepo, userRepo, printerRepo, printJobRepo) printService := service.NewPrintService(printerRepo, printJobRepo, orderRepo) // Initialize gRPC server grpcServer := grpc.NewServer( grpc.UnaryInterceptor(interceptor.NewAuthInterceptor(jwtManager).UnaryServerInterceptor()), ) // Register gRPC services pb.RegisterAuthServiceServer(grpcServer, service.NewAuthServiceServer(authService)) pb.RegisterFileServiceServer(grpcServer, service.NewFileServiceServer(fileService)) pb.RegisterOrderServiceServer(grpcServer, service.NewOrderServiceServer(orderService)) pb.RegisterPrintServiceServer(grpcServer, service.NewPrintServiceServer(printService)) pb.RegisterLibraryServiceServer(grpcServer, service.NewLibraryServiceServer(libraryRepo, fileRepo)) pb.RegisterPriceServiceServer(grpcServer, service.NewPriceServiceServer(priceRepo)) pb.RegisterPayServiceServer(grpcServer, service.NewPayServiceServer(orderService, paymentRepo, weChatPay, userRepo)) pb.RegisterAdminServiceServer(grpcServer, service.NewAdminServiceServer(authService, orderRepo, printerRepo)) // Start server addr := fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port) lis, err := net.Listen("tcp", addr) if err != nil { log.Fatalf("Failed to listen: %v", err) } // Graceful shutdown sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) go func() { <-sigCh grpcServer.GracefulStop() }() zapLogger.Info("Starting gRPC server", zap.String("address", addr)) if err := grpcServer.Serve(lis); err != nil { log.Fatalf("Failed to serve: %v", err) } } func initDB(cfg *config.Config) (*gorm.DB, error) { gormLogger := logger.New( log.New(os.Stdout, "\r\n", log.LstdFlags), logger.Config{ LogLevel: logger.Info, }, ) db, err := gorm.Open(mysql.Open(cfg.Database.DSN()), &gorm.Config{ Logger: gormLogger, }) if err != nil { return nil, err } sqlDB, err := db.DB() if err != nil { return nil, err } sqlDB.SetMaxOpenConns(cfg.Database.MaxOpenConns) sqlDB.SetMaxIdleConns(cfg.Database.MaxIdleConns) return db, nil }