package main import ( "context" "fmt" "log" "os" "os/signal" "syscall" "ticket-pimp/bot/handler" discordbot "ticket-pimp/discord-bot" "ticket-pimp/internal/domain" "ticket-pimp/internal/services" db "ticket-pimp/internal/storage/db/tickets" "github.com/jackc/pgx/v5" "github.com/joho/godotenv" "github.com/mr-linch/go-tg" "github.com/mr-linch/go-tg/tgb" ) func main() { log.Print("started") config := env("develop.env") run(config) } func run(conf domain.Config) { ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill, syscall.SIGTERM) defer cancel() conn, err := pgx.Connect( ctx, fmt.Sprintf( "postgresql://%s:%s@%s:%s/%s", conf.DB.User, conf.DB.Pass, conf.DB.Host, conf.DB.Port, conf.DB.Name, )) if err != nil { log.Fatalf("DB connection failed: %v", err) } defer conn.Close(ctx) opts := TelegramOptions{ ticketsRepo: db.New(conn), gitService: services.NewGit(conf.Git), cloudService: services.NewCloud(conf.Cloud), coda: services.NewCodaClient(conf.Coda), appConfig: &conf, } go func() { if err := runDiscrodBot(conf); err != nil { log.Fatalf("discord bot cannot be runned: %v", err) } }() if err := runTgBot(ctx, opts); err != nil { log.Fatalf("telegram bot cannot be runned: %v", err) defer os.Exit(1) } } // env // env function reads provided file and setup envirmental variables; func env(envFilePath string) domain.Config { err := godotenv.Load(envFilePath) if err != nil { log.Fatal("Error while loading env file") } return domain.Config{ Git: domain.GitConfig{ BaseUrl: os.Getenv("GIT_BASE_URL"), Token: os.Getenv("GIT_TOKEN"), User: os.Getenv("GIT_USER"), }, Cloud: domain.CloudConfig{ BaseUrl: os.Getenv("CLOUD_BASE_URL"), User: os.Getenv("CLOUD_USER"), Pass: os.Getenv("CLOUD_PASS"), RootDir: os.Getenv("ROOTDIR"), }, Coda: domain.CodaConfig{ Farm: os.Getenv("CODA_TOKEN1"), Develop: os.Getenv("CODA_TOKEN2"), }, DB: domain.DBConfig{ Host: os.Getenv("DB_HOST"), Port: os.Getenv("DB_PORT"), Name: os.Getenv("DB_NAME"), User: os.Getenv("DB_USER"), Pass: os.Getenv("DB_PASS"), SslMode: os.Getenv("SSLMODE"), }, Telegram: domain.TelegramConfig{ Token: os.Getenv("TG_API"), }, Discord: domain.DiscordConfig{ Token: os.Getenv("DISCORD_TOKEN"), }, } } func runDiscrodBot(conf domain.Config) error { token := conf.Discord.Token dbot, err := discordbot.NewDiscordBot(token) if err != nil { return err } createRepoHandler := discordbot.CreateRepoHandler(3) dbot.Session.AddHandler(createRepoHandler.Handler) if err := dbot.Session.Open(); err != nil { return fmt.Errorf("cannot open the session: %v", err) } log.Println("Adding commands...") cmd, err := dbot.Session.ApplicationCommandCreate(dbot.Session.State.User.ID, "", &createRepoHandler.Command) if err != nil { log.Panicf("Cannot create '%v' command: %v", createRepoHandler.Command.Name, err) } defer dbot.Session.Close() stop := make(chan os.Signal, 1) signal.Notify(stop, os.Interrupt) <-stop log.Println("Graceful shutdown") log.Println("Removing commands...") err = dbot.Session.ApplicationCommandDelete(dbot.Session.State.User.ID, "", cmd.ID) if err != nil { log.Panicf("Cannot delete '%v' command: %v", cmd.Name, err) } return nil } type TelegramOptions struct { ticketsRepo *db.Queries gitService *services.Git cloudService *services.Cloud coda *services.Coda appConfig *domain.Config } // runTgBot ... // ..function creates new Telegram BOT instance // ..throw env variables through bot's handlers // ..setup tg bot router; // and finally returns tgb.Poller func runTgBot(ctx context.Context, opts TelegramOptions) error { log.Print("Start telegram bot init..") client := tg.New(opts.appConfig.Telegram.Token) h := handler.NewHandler( opts.gitService, opts.cloudService, opts.coda, opts.ticketsRepo, ) router := tgb.NewRouter(). Message(h.Init, tgb.Command("init")). Message(h.PingHandler, tgb.Command("ping")). Message(h.DevelopmentTaskHandler, tgb.TextHasPrefix("/new")). Message(h.NewRepoHandler, tgb.TextHasPrefix("/repo")). Message(h.NewFolderHandler, tgb.TextHasPrefix("/folder")). Message(h.FarmTaskHandler, tgb.TextHasPrefix("/task")) return tgb.NewPoller( router, client, ).Run(ctx) }