diff --git a/cmd/bot/main.go b/cmd/bot/main.go new file mode 100644 index 0000000..a87af86 --- /dev/null +++ b/cmd/bot/main.go @@ -0,0 +1,149 @@ +package main + +import ( + "context" + "database/sql" + "errors" + "fmt" + "log/slog" + "os" + "os/signal" + "strings" + "syscall" + "time" + + tb "github.com/go-telegram-bot-api/telegram-bot-api/v5" + "github.com/maximotejeda/us_dop_bot/broadcast" + commands "github.com/maximotejeda/us_dop_bot/command" + "github.com/maximotejeda/us_dop_bot/db" + edb "github.com/maximotejeda/us_dop_bot/edb" + "github.com/maximotejeda/us_dop_bot/query" + "github.com/nats-io/nats.go" +) + +func main() { + dbUserUri := os.Getenv("DBURIUSER") + + dbInstUri := os.Getenv("DBURINST") + token := os.Getenv("TOKEN") + natsURI := os.Getenv("NATSURI") + log := slog.New(slog.NewJSONHandler(os.Stderr, nil)) + nc, _ := nats.Connect(natsURI) + ctx := context.Background() + userDB := db.Dial(ctx, db.DEFAULT_DRIVER, dbUserUri) + instDB := edb.Dial(dbInstUri, log) + + bot, err := tb.NewBotAPI(token) + if err != nil { + panic(err) + } + bot.Debug = false + log.Info("Bot Authorized", "username", bot.Self.UserName) + u := tb.NewUpdate(0) + u.Timeout = 60 + + // bot user update channel + updtChan := bot.GetUpdatesChan(u) + // subs chann + ch := make(chan *nats.Msg, 64) + defer close(ch) + sub, err := nc.ChanSubscribe("dolar-crawler", ch) + if err != nil { + log.Error("subscribing", "error", err.Error()) + } + defer sub.Drain() + defer nc.Close() + // exit channel + sign := make(chan os.Signal, 1) + signal.Notify(sign, syscall.SIGINT, syscall.SIGTERM) + defer close(sign) + for { + select { + case update := <-updtChan: + usr := db.NewUser(userDB, log) + _, err := usr.Get(update.SentFrom().ID) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + usr.Add(update.SentFrom().ID) + } + + } + + if update.Message != nil { + msg := tb.NewMessage(update.Message.Chat.ID, "") + if update.Message.Text != "" && !update.Message.IsCommand() { + log.Info("update", "username", update.Message.From.UserName, "message", update.Message.Text) + msg.Text = update.Message.Text + msg.ReplyToMessageID = update.Message.MessageID + bot.Send(msg) + } else if update.Message.IsCommand() { + go func(update tb.Update) { + msg = commands.CommandHandler(ctx, userDB, instDB, log, update) + + if resp, err := bot.Request(tb.NewDeleteMessage(update.Message.From.ID, update.Message.MessageID)); err != nil || !resp.Ok { + log.Error(err.Error()) + } + + bot.Send(msg) + }(update) + } + } else if update.CallbackQuery != nil { + ctx, cancel := context.WithTimeout(ctx, 3*time.Second) + go func(update tb.Update) { + msg := query.QueryHandler(ctx, userDB, instDB, log, update.CallbackQuery) + + //del := tb.NewDeleteMessage(update.CallbackQuery.From.ID, update.CallbackQuery.Message.MessageID) + if resp, err := bot.Request(tb.NewDeleteMessage(update.CallbackQuery.From.ID, update.CallbackQuery.Message.MessageID)); err != nil || !resp.Ok { + log.Error(err.Error()) + } + if msg != nil { + if _, err := bot.Send(msg); err != nil { + log.Error(err.Error()) + } + } else { + data := update.CallbackQuery.Data + + dataList := strings.Split(data, "&") + + dataMap := map[string]string{} + for _, val := range dataList { + subData := strings.Split(val, "=") + dataMap[subData[0]] = subData[1] + } + queryinf := tb.CallbackConfig{} + name := dataMap["name"] + if _, ok := dataMap["subs"]; ok { + queryinf.Text = fmt.Sprintf("Te haz suscrito a %s:\nRecibiras un mensaje cuando cambie el precio del dolar.", name) + } else if _, ok := dataMap["unsubs"]; ok { + queryinf.Text = fmt.Sprintf("Haz eliminado a %s de tus suscripciones\nNo recibiras notificaciones de %s", name, name) + } else if _, ok := dataMap["reset"]; ok { + queryinf.Text = "Haz eliminado todas tus suscripciones" + } + if queryinf.Text != "" { + queryinf.ShowAlert = true + queryinf.CallbackQueryID = update.CallbackQuery.ID + if resp, err := bot.Request(queryinf); err != nil || !resp.Ok { + log.Error(err.Error()) + } + } + } + cancel() + }(update) + + } + case message := <-ch: + // we are outside update so we will be querying db to + // get users interested in specific updates ex bpd, brd, apa + // userID inst=> comma separated string + msgList := broadcast.SendList(ctx, userDB, log, message.Data) + //log.Info(string(message.Data)) + for _, msg := range msgList { + go bot.Send(msg) + } + + case <-sign: + log.Error("killing app due to syscall ") + os.Exit(1) + } + } +}