package main import ( "context" "database/sql" "encoding/json" "errors" "fmt" "github.com/disgoorg/disgo" "github.com/disgoorg/disgo/discord" "github.com/disgoorg/disgo/rest" "github.com/disgoorg/disgo/webhook" "github.com/disgoorg/snowflake/v2" "grow.rievo.dev/discordBots" "grow.rievo.dev/discordBots/cmd/domaincheckbot/config" "grow.rievo.dev/discordBots/cmd/domaincheckbot/dns" "grow.rievo.dev/discordBots/pkg/db" "log/slog" "os" "os/signal" "reflect" "syscall" "time" _ "modernc.org/sqlite" ) var ( webhookID = snowflake.GetEnv("webhook_id") webhookToken = os.Getenv("webhook_token") ) var logger = slog.New(slog.NewJSONHandler(os.Stdout, nil)) // TODO: clear db from domains removed from json var release string func main() { logger.Info("starting domainCheck...", slog.String("disgo version", disgo.Version)) client := webhook.New(webhookID, webhookToken) defer client.Close(context.TODO()) ctx := context.Background() con, err := sql.Open("sqlite", "file:db/domain.db?cache=shared") if err != nil { logger.Error("error opening db", slog.Any("error", err)) panic(err) } defer con.Close() // create tables if _, err := con.ExecContext(ctx, discordBots.Schema); err != nil { logger.Error("error creating db schema", slog.Any("error", err)) panic(err) } query := db.New(con) ticker := time.NewTicker(1 * time.Minute) quit := make(chan struct{}) go func() { for { select { case <-ticker.C: for _, d := range config.Domains { go checkDomain(0, d, query, client) } case <-quit: ticker.Stop() return } } }() logger.Info("domaincheckbot is now running. Press CTRL-C to exit.", slog.String("version", release)) s := make(chan os.Signal, 1) signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) <-s } func checkDomain(counter int, d string, query *db.Queries, client webhook.Client) { domain := dns.CheckDomain(d) retrievedDomainJson, dbErr := query.GetItem(context.TODO(), d) retrievedDomain := dns.Domain{} if err := json.Unmarshal(retrievedDomainJson.Data, &retrievedDomain); !errors.Is(dbErr, sql.ErrNoRows) && err != nil { logger.Error("failed unmarshalling deal", slog.Any("error", err)) } if reflect.DeepEqual(domain, retrievedDomain) { logger.Debug("domain did not change", slog.String("domain", d)) return } logger.Info("domain changed changed", slog.String("domain", d)) counter += 1 if counter >= 2 { go sendWebhook(client, domain, retrievedDomain) domainJson, _ := json.Marshal(domain) err := query.CreateItem(context.TODO(), db.CreateItemParams{ ID: domain.Name, Data: domainJson, }) if err != nil { logger.Error("failed saving domain", slog.Any("error", err)) } return } time.Sleep(1 * time.Minute) checkDomain(counter, d, query, client) } func sendWebhook(client webhook.Client, domain dns.Domain, oldDomain dns.Domain) { var status string status = fmt.Sprintf("```md\n# %v", domain.Name) status = fmt.Sprintf("%v\n - %v", status, oldDomain.NS) status = fmt.Sprintf("%v\n + %v", status, domain.NS) status = fmt.Sprintf("%v```\n", status) if _, err := client.CreateMessage(discord.NewWebhookMessageCreateBuilder(). SetContent(status).Build(), rest.WithDelay(2*time.Second), ); err != nil { logger.Error("sending message failed", slog.Any("error", err)) } }