package main import ( "context" "fmt" "gitea.pena/PenaSide/common/encrypt" "gitea.pena/PenaSide/common/mongo" "gitea.pena/PenaSide/common/validate" "gitea.pena/PenaSide/customer/internal/models" "github.com/gofiber/fiber/v2" "github.com/twmb/franz-go/pkg/kgo" "log" "os" "strconv" "strings" "time" ) func main() { config, err := loadConfig() if err != nil { log.Fatalf("error loading config: %v", err) } err = validateNotEmpty(config) if err != nil { log.Fatalf("error validating config: %v", err) } urls := []string{ config.AuthMicroserviceURL, config.HubadminMicroserviceURL, config.CurrencyMicroserviceURL, config.DiscountMicroserviceGRPC, config.CodewordMicroserviceGRPC, config.PaymentMicroserviceGRPC, config.VerificationMicroservice, config.TemplategenMicroserviceURL, config.TrashLogHost, config.AdminURL, config.ExternalCfg.MailClientCfg.ApiURL, } if err = validateURLs(urls); err != nil { log.Fatalf("error validating urls: %v", err) } // todo validate jwt if err = validateKafka(config.KafkaBrokers, config.KafkaTopicTariff); err != nil { log.Fatalf("error validating kafka: %v", err) } if err = validateMail(config.ExternalCfg.MailClientCfg); err != nil { log.Fatalf("error validating smtp: %v", err) } if err = validate.ValidateEncryptKeys(&config.ExternalCfg.EncryptCommon); err != nil { log.Fatalf("error validating encrypted: %v", err) } if err = validateTG(config.NotificationBotToken, config.NotificationRsPayChannel, config.NotificationChannel); err != nil { log.Fatalf("error validating tg enviroments: %v", err) } if err = validate.ValidateMongo(config.ExternalCfg.Database); err != nil { log.Fatalf("error validating mongodb: %v", err) } } // 38 fields func loadConfig() (*models.Config, error) { config := models.Config{ ExternalCfg: models.ExternalCfg{ JwtCfg: models.JWTConfiguration{ PublicKey: os.Getenv("JWT_PUBLIC_KEY"), Audience: os.Getenv("JWT_AUDIENCE"), Issuer: os.Getenv("JWT_ISSUER"), }, Database: mongo.Configuration{ URL: os.Getenv("MONGO_URL"), DatabaseName: os.Getenv("MONGO_DB_NAME"), }, MailClientCfg: models.MailClientCfg{ ApiURL: os.Getenv("API_URL"), Sender: os.Getenv("MAIL_SENDER"), ApiKey: os.Getenv("MAIL_API_KEY"), MailAddress: os.Getenv("MAIL_ADDRESS"), }, EncryptCommon: encrypt.Encrypt{ PrivKey: os.Getenv("ENCRYPT_PRIVATE_KEY"), PubKey: os.Getenv("ENCRYPT_PUBLIC_KEY"), }, }, ClientHttpURL: os.Getenv("CLIENT_HTTP_URL"), AdminHttpURL: os.Getenv("ADMIN_HTTP_URL"), GrpcURL: os.Getenv("GRPC_URL"), GrpcDomain: os.Getenv("GRPC_DOMAIN"), KafkaBrokers: strings.Split(os.Getenv("KAFKA_BROKERS"), ","), KafkaTopicTariff: os.Getenv("KAFKA_TOPIC_TARIFF"), AuthMicroserviceURL: os.Getenv("AUTH_MICROSERVICE_URL"), HubadminMicroserviceURL: os.Getenv("HUBADMIN_MICROSERVICE_URL"), CurrencyMicroserviceURL: os.Getenv("CURRENCY_MICROSERVICE_URL"), DiscountMicroserviceGRPC: os.Getenv("DISCOUNT_MICROSERVICE_GRPC_URL"), PaymentMicroserviceGRPC: os.Getenv("PAYMENT_MICROSERVICE_GRPC_URL"), VerificationMicroservice: os.Getenv("VERIFICATION_MICROSERVICE_URL"), TemplategenMicroserviceURL: os.Getenv("TEMPLATEGEN_MICROSERVICE_URL"), CodewordMicroserviceGRPC: os.Getenv("CODEWORD_MICROSERVICE_GRPC_URL"), TrashLogHost: os.Getenv("TRASH_LOG_HOST"), NotificationBotToken: os.Getenv("TELEGRAM_TOKEN"), NotificationRsPayChannel: envToInt64(os.Getenv("TELEGRAM_RS_PAY_CHANNEL_ID")), NotificationChannel: envToInt64(os.Getenv("TELEGRAM_NOTIFICATION_CHANNEL_ID")), AdminURL: os.Getenv("ADMIN_FRONT_URL"), } return &config, nil } func envToInt64(str string) int64 { n, err := strconv.ParseInt(str, 10, 64) if err != nil { panic(err) } return n } func validateURLs(urls []string) error { for index, u := range urls { if u == "" { return fmt.Errorf("empty url, index: %d", index) } // todo check the liveness of these URLs, many services do not support } return nil } func validateKafka(brokers []string, topic string) error { if len(brokers) == 0 { return fmt.Errorf("kafka brokers is empty") } if topic == "" { return fmt.Errorf("kafka topic is empty") } for _, addr := range brokers { if addr == "" { return fmt.Errorf("empty kafka broker") } } ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() kafkaTariffClient, err := kgo.NewClient( kgo.SeedBrokers(brokers...), kgo.ConsumeResetOffset(kgo.NewOffset().AtStart()), kgo.DefaultProduceTopic(topic), kgo.ConsumeTopics(topic), ) if err != nil { return err } defer kafkaTariffClient.Close() err = kafkaTariffClient.Ping(ctx) if err != nil { return err } return nil } func validateMail(cfg models.MailClientCfg) error { if cfg.MailAddress == "" { return fmt.Errorf("mail address is empty") } if cfg.ApiURL == "" { return fmt.Errorf("mail api url is empty") } if cfg.ApiKey == "" { return fmt.Errorf("mail api key is empty") } if cfg.Sender == "" { return fmt.Errorf("mail sender is empty") } client := fiber.AcquireClient() req := client.Get("https://api.smtp.bz/v1/user") req.Set("Authorization", cfg.ApiKey) code, _, _ := req.Bytes() if code != fiber.StatusOK { return fmt.Errorf("invalid smtp code, no auth: %d", code) } return nil } func validateNotEmpty(config *models.Config) error { if config.ExternalCfg.EncryptCommon.PrivKey == "" { return fmt.Errorf("invalid private encrypt key") } if config.ExternalCfg.EncryptCommon.PubKey == "" { return fmt.Errorf("invalid publice encrypt key") } return nil } func validateTG(notificationBotToken string, notificationRsPayChannel int64, notificationChannel int64) error { err := validate.ValidateTgToken(notificationBotToken) if err != nil { return err } if notificationChannel == 0 { return fmt.Errorf("notificationChannel is not set") } if notificationRsPayChannel == 0 { return fmt.Errorf("notificationRsPayChannel is not set") } return nil }