beanbot/bot/bot.go

134 lines
2.9 KiB
Go

package bot
import (
"fmt"
"log"
"strings"
"time"
"git.s8k.top/SeraphJACK/beanbot/config"
"git.s8k.top/SeraphJACK/beanbot/syntax"
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
"github.com/google/uuid"
)
type messageHandleContext struct {
bot *tgbotapi.BotAPI
chat *tgbotapi.Chat
msg *tgbotapi.Message
}
func Start() error {
bot, err := tgbotapi.NewBotAPI(config.Cfg.BotToken)
if err != nil {
return err
}
// Watch for transactions that need to be committed
go func() {
for {
commitAll()
time.Sleep(time.Second)
}
}()
// Polling message updates
id := 0
for {
id++
u := tgbotapi.NewUpdate(id)
u.Timeout = 60
updates := bot.GetUpdatesChan(u)
for update := range updates {
if update.Message != nil {
ctx := &messageHandleContext{bot: bot, chat: update.Message.Chat, msg: update.Message}
go handleMessage(ctx)
}
if update.EditedMessage != nil {
ctx := &messageHandleContext{bot: bot, chat: update.EditedMessage.Chat, msg: update.EditedMessage}
go handleMessage(ctx)
}
if update.CallbackQuery != nil {
handleCallbackQuery(update.CallbackQuery)
}
}
}
}
func handleMessage(ctx *messageHandleContext) {
msg := ctx.msg
// We only process private messages
if msg.Chat.Type != "private" {
return
}
// User is not authorized, break
if !authorized(ctx, msg.From) {
return
}
if msg.Command() == "recent" {
updateRecentKeyboard(ctx)
return
}
raw := msg.Text
txn, err := syntax.Parse(strings.Split(raw, " "), &config.Cfg.Syntax)
if err != nil {
msg := tgbotapi.NewMessage(ctx.chat.ID, "Failed to parse txn syntax: "+err.Error())
go ctx.bot.Send(msg)
return
}
txnID := uuid.New().String()
msgCfg := tgbotapi.NewMessage(ctx.chat.ID,
fmt.Sprintf("The following transaction is about to be committed:```\n%s\n```",
txn.ToBeanLanguageSyntax()),
)
msgCfg.ParseMode = tgbotapi.ModeMarkdown
msgCfg.ReplyMarkup = tgbotapi.NewInlineKeyboardMarkup([]tgbotapi.InlineKeyboardButton{
tgbotapi.NewInlineKeyboardButtonData("Cancel", txnID),
})
confirmMsg, err := ctx.bot.Send(msgCfg)
if err != nil {
log.Printf("Failed to send txn confirmation message: %v", err)
return
}
aboutToCommit(txnID, &transaction{
ctx: ctx,
raw: raw,
txn: txn,
confirmMsg: confirmMsg,
commitTime: time.Now().Add(10 * time.Second),
})
}
func handleCallbackQuery(query *tgbotapi.CallbackQuery) {
cancel(query.Data)
}
func updateRecentKeyboard(ctx *messageHandleContext) {
var btns [][]tgbotapi.KeyboardButton
for _, v := range recentCmds {
btns = append(btns, tgbotapi.NewKeyboardButtonRow(
tgbotapi.NewKeyboardButton(v.command),
))
}
msg := tgbotapi.NewMessage(ctx.chat.ID, "Recent Commands")
if len(btns) > 0 {
markup := tgbotapi.NewReplyKeyboard(btns...)
markup.OneTimeKeyboard = true
msg.ReplyMarkup = markup
}
_, err := ctx.bot.Send(msg)
if err != nil {
log.Printf("Failed to send recent menu: %v", err)
}
return
}