package main import ( "context" "fmt" "net/http" "os" "os/signal" "syscall" "time" "github.com/gorilla/mux" "github.com/twmb/franz-go/pkg/kgo" "go.uber.org/zap" "go.uber.org/zap/zapcore" "penahub.gitlab.yandexcloud.net/backend/templategen/amo" "penahub.gitlab.yandexcloud.net/backend/templategen/broker/tariff" "penahub.gitlab.yandexcloud.net/backend/templategen/dal" "penahub.gitlab.yandexcloud.net/backend/templategen/gdisk" "penahub.gitlab.yandexcloud.net/backend/templategen/handlers" "penahub.gitlab.yandexcloud.net/backend/templategen/middleware" "penahub.gitlab.yandexcloud.net/backend/templategen/privileges" "penahub.gitlab.yandexcloud.net/backend/templategen/tools" "penahub.gitlab.yandexcloud.net/backend/templategen/worker" "penahub.gitlab.yandexcloud.net/backend/templategen/yadisk" ) type Env struct { Domain string `env:"DOMAIN" default:"tempgen.pena.digital"` LogFile string `env:"LOG_FILE" default:"./tmp/logs.log"` MongoURL string `env:"MONGO_URL" default:"mongodb://mongo:30000/?replicaSet=penahub-rs"` DBName string `env:"DB_NAME" default:"templategen"` YaDiskClientID string `env:"YADISK_CLIENT_ID" default:"94482c181e5148c096ae6ad3b2a981ea"` YaDiskClientSecret string `env:"YADISK_CLIENT_SECRET" default:"7dc4f541c3f64f4a9078e59d7494d222"` GDiskCredentials string `env:"GDISK_CREDENTIALS" default:"./static/gdisk-credentials.json"` AmoClientID string `env:"AMO_CLIENT_ID" default:"6c7f3fdb-cce7-4fb0-a8a3-640b695c8d00"` AmoClientSecret string `env:"AMO_CLIENT_SECRET" default:"5oJU1L8pScLKfEasShJ6KuDU32VrIs6BVKQ6BiY4vABIQycUWJziULytiUs5jaZU"` AmoRedirectUrn string `env:"AMO_REDIRECT_URN" default:"/settings/widgets/penagen/"` TokenKey string `env:"TOKEN_KEY" default:"z1eRU{fq*VtfLAszrz"` KafkaTariff string `env:"KAFKA_TARIFF"` KafkaBrokers []string `env:"KAFKA_BROKERS"` KafkaTariffTopic string `env:"KAFKA_TARIFF_TOPIC"` KafkaConsumerGroupID string `env:"KAFKA_CONSUMER_GROUP_ID"` PrivilegesDomain string `env:"PRIVILEGES_DOMAIN"` } func main() { opts := GetOpts() ctx, cancel := context.WithCancel(context.Background()) // Set tools/token tools.SetToken(opts.TokenKey) // Logger cfgLogger := zap.NewDevelopmentConfig() cfgLogger.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder cfgLogger.EncoderConfig.ConsoleSeparator = " " logger, err := cfgLogger.Build() logger.Info("OPTIONS", zap.Any("ENV", opts)) if err != nil { panic(err) } err = privileges.PublishPrivileges(ctx, "https://admin.pena.digital/strator") if err != nil { logger.Error("ErrorPublishPrivileges", zap.Error(err)) } // Start Data Access Layer mongoDal, err := dal.InitMongoDAL(ctx, opts.MongoURL, opts.DBName, logger) defer mongoDal.Disconnect() if err != nil { logger.Error("ErrorConnectToDAL", zap.Error(err)) return } // Yandex Disk yaDisk := yadisk.NewClientApp( opts.YaDiskClientID, opts.YaDiskClientSecret, fmt.Sprintf("https://%v/yadisk", opts.Domain), fmt.Sprintf("https://%v", opts.Domain), ) // Google Drive gDisk, err := gdisk.NewClientApp(opts.GDiskCredentials) if err != nil { logger.Error("ErrorCreateGoogleDriveClientApp", zap.Error(err)) return } // Amo amoApp := amo.NewClientApp( opts.AmoClientID, opts.AmoClientSecret, fmt.Sprintf("https://%v/amo", opts.Domain), ) // Tariff kafkaTariffClient, err := kgo.NewClient( kgo.SeedBrokers(opts.KafkaBrokers...), kgo.ConsumerGroup(opts.KafkaConsumerGroupID), kgo.ConsumeResetOffset(kgo.NewOffset().AtStart()), kgo.DefaultProduceTopic(opts.KafkaTariffTopic), kgo.ConsumeTopics(opts.KafkaTariffTopic), ) if err != nil { logger.Error("ErrorCreateKafkaTariffClient", zap.Error(err)) return } tariffConsumerDeps := tariff.ConsumerDeps{ Logger: logger, Client: kafkaTariffClient, } tariffConsumer := tariff.NewConsumer(tariffConsumerDeps) // Tariff worker tariffWorkerDeps := worker.TariffWorkerDeps{ Logger: logger, Dal: mongoDal, TariffConsumer: tariffConsumer, PrivilegesDomain: opts.PrivilegesDomain, } tariffWorker := worker.NewTariffWorker(tariffWorkerDeps) go tariffWorker.Run(ctx) // Handlers h := handlers.NewHandlers(mongoDal, yaDisk, gDisk, amoApp, logger, &handlers.HandlerVars{ Domain: opts.Domain, AmoRedirectUrn: opts.AmoRedirectUrn, }) r := mux.NewRouter() // Add Assets r.PathPrefix("/tmp/generated/").Handler(http.StripPrefix("/tmp/generated/", http.FileServer(http.Dir("tmp/generated")))) r.PathPrefix("/tmp/downloaded/").Handler(http.StripPrefix("/tmp/downloaded/", http.FileServer(http.Dir("tmp/downloaded")))) r.PathPrefix("/.well-known/pki-validation/").Handler(http.StripPrefix("/.well-known/pki-validation/", http.FileServer(http.Dir(".well-known/pki-validation")))) r.PathPrefix("/.well-known/acme-challenge/").Handler(http.StripPrefix("/.well-known/acme-challenge/", http.FileServer(http.Dir(".well-known/acme-challenge")))) r.PathPrefix("/static/examples/docx/").Handler(http.StripPrefix("/static/examples/docx/", http.FileServer(http.Dir("/static/examples/docx/")))) //# region ====== HANDLERS ====== r.NotFoundHandler = http.HandlerFunc(h.PageNotFound) r.HandleFunc("/amo", h.AmoSaveToken) r.HandleFunc("/amo/state", h.AmoState) r.HandleFunc("/amo/access_rules", h.AmoAccessRules) // Set rules for Amo end-points amoAccess := map[string]string{ "/amo/webhook": "visibility", "/amo/generateDoc": "creation", } r.HandleFunc("/yadisk", h.YaDiskSaveToken) r.HandleFunc("/yadisk/setSettings", h.YaDiskSetSettings) r.HandleFunc("/yadisk/getList", h.YaDiskGetList) r.HandleFunc("/yadisk/resources/get", h.YaDiskGetResources) r.HandleFunc("/yadisk/resources/put", h.YaDiskPutResources) r.HandleFunc("/yadisk/resources/delete", h.YaDiskDeleteResources) r.HandleFunc("/yadisk/resources/upload", h.YaDiskUploadResources) r.HandleFunc("/yadisk/resources/downloadlink", h.YaDiskDownloadLink) r.HandleFunc("/yadisk/resources/download", h.YaDiskDownload) r.HandleFunc("/gdisk/getTemplateDir", h.GDiskGetDirTemplate) // устарело? r.HandleFunc("/gdisk", h.GDiskSaveToken) r.HandleFunc("/gdisk/setSettings", h.GDiskSetSettings) r.HandleFunc("/gdisk/getList", h.GDiskGetList) r.HandleFunc("/gdisk/resources/get", h.GDiskGetResources) r.HandleFunc("/gdisk/resources/put", h.GDiskPutResources) r.HandleFunc("/gdisk/resources/delete", h.GDiskDeleteResources) r.HandleFunc("/gdisk/resources/upload", h.GDiskUploadResources) r.HandleFunc("/penadisk/setSettings", h.PenaDiskSetSettings) r.HandleFunc("/penadisk/resources/get", h.PenaDiskGetResources) r.HandleFunc("/penadisk/resources/put", h.PenaDiskPutResources) r.HandleFunc("/penadisk/resources/delete", h.PenaDiskDeleteResources) r.HandleFunc("/penadisk/resources/upload", h.PenaDiskUploadResources) r.HandleFunc("/penadisk/resources/downloadlink", h.PenaDiskDownloadLink) r.HandleFunc("/template/set", h.TemplateSet) r.HandleFunc("/template/get", h.TemplateGet) r.HandleFunc("/template/getListByUser", h.TemplateGetListByUser) r.HandleFunc("/template/getListByGroup", h.TemplateGetListByGroup) r.HandleFunc("/template/update", h.TemplateUpdate) r.HandleFunc("/template/delete", h.TemplateDelete) r.HandleFunc("/group/create", h.TemplateGroupCreate) r.HandleFunc("/group/getList", h.TemplateGroupGetList) r.HandleFunc("/group/edit", h.TemplateGroupEdit) r.HandleFunc("/group/put", h.TemplateGroupPut) r.HandleFunc("/group/remove", h.TemplateGroupRemove) r.HandleFunc("/group/delete", h.TemplateGroupDelete) r.HandleFunc("/group/{id}", h.TemplateGroupGet) r.HandleFunc("/generator/byAmoLead", h.GeneratorByAmoLead) r.HandleFunc("/generator/byData", h.GeneratorByData) r.HandleFunc("/generator/byTemplate", h.GeneratorByData) r.HandleFunc("/generator/byAmoWebhook", h.GeneratorByAmoWebhook) r.HandleFunc("/generator/byamowebhook", h.GeneratorByAmoWebhook) r.HandleFunc("/history/get", h.GetHistoryByID) r.HandleFunc("/history/getList", h.GetHistoryList) r.HandleFunc("/history/getlist", h.GetHistoryList) //#endregion // Middlewares mw := middleware.InitMiddleware(mongoDal, amoApp, logger, amoAccess) r.Use( mw.MiddlewareHeaders, mw.MiddlewareCors, mw.MiddlewareAmoJwt, mw.MiddlewareJwt, // mw.MiddlewareAmoPlug, mw.Logger, ) r.NotFoundHandler = r.NewRoute().HandlerFunc(h.PageNotFound).GetHandler() srv := http.Server{ Handler: r, ReadHeaderTimeout: time.Second * 3, // TODO: Обсудить со Skeris } go func() { err := srv.ListenAndServe() if err != nil { logger.Error("CanNotServe", zap.Error(err)) return } }() // TLS fullCert := fmt.Sprintf("./static/cert/%v/fullchain.pem", opts.Domain) privCert := fmt.Sprintf("./static/cert/%v/privkey.pem", opts.Domain) go func() { err := srv.ListenAndServeTLS(fullCert, privCert) if err != nil { logger.Error("CanNotServe", zap.Error(err)) return } }() // Graceful Shutdown interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM) killSignal := <-interrupt switch killSignal { case os.Interrupt: logger.Error("AppInterrupted") return case syscall.SIGTERM: logger.Error("AppTerminated") return } defer cancel() } func GetOpts() Env { return getEnv(Env{}) }