Telegram bot
This commit is contained in:
parent
8ea2ad9d0d
commit
61e487f10d
|
@ -0,0 +1,24 @@
|
|||
package bot
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.s8k.top/SeraphJACK/beanbot/config"
|
||||
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||
)
|
||||
|
||||
func authorized(ctx *messageHandleContext, user *tgbotapi.User) bool {
|
||||
for _, v := range config.Cfg.AuthorizedUserIDs {
|
||||
if v == user.ID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
msg := tgbotapi.NewMessage(ctx.chat.ID,
|
||||
fmt.Sprintf("User with ID `%d` is not authorized to access this bot.", user.ID))
|
||||
msg.ParseMode = tgbotapi.ModeMarkdown
|
||||
|
||||
go ctx.bot.Send(msg)
|
||||
|
||||
return false
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
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
|
||||
}
|
||||
|
||||
// Polling message updates
|
||||
go func() {
|
||||
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.CallbackQuery != nil {
|
||||
go handleCallback(update.CallbackQuery)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Watch for transactions that need to be committed
|
||||
go func() {
|
||||
for {
|
||||
commitAll()
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
txn, err := syntax.Parse(strings.Split(msg.Text, ""), &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
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
txnMsg, err := ctx.bot.Send(msgCfg)
|
||||
if err != nil {
|
||||
log.Printf("Failed to send txn confirmation message: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
txnID := uuid.New().String()
|
||||
cbMsg, err := ctx.bot.Send(tgbotapi.NewCallback(txnID, "Cancel"))
|
||||
if err != nil {
|
||||
log.Printf("Failed to send cancel callback message: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
aboutToCommit(txnID, &transaction{
|
||||
txn: txn,
|
||||
txmMsg: txnMsg,
|
||||
callbackMsg: cbMsg,
|
||||
commitTime: time.Now().Add(10 * time.Second),
|
||||
})
|
||||
}
|
||||
|
||||
func handleCallback(query *tgbotapi.CallbackQuery) {
|
||||
cancel(query.ID)
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package bot
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.s8k.top/SeraphJACK/beanbot/repo"
|
||||
"git.s8k.top/SeraphJACK/beanbot/syntax"
|
||||
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||
)
|
||||
|
||||
type transaction struct {
|
||||
ctx *messageHandleContext
|
||||
txn *syntax.Transaction
|
||||
txmMsg tgbotapi.Message
|
||||
callbackMsg tgbotapi.Message
|
||||
commitTime time.Time
|
||||
}
|
||||
|
||||
var lock sync.Mutex
|
||||
var aboutToCommitTxn map[string]*transaction
|
||||
|
||||
func aboutToCommit(id string, txn *transaction) {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
aboutToCommitTxn[id] = txn
|
||||
}
|
||||
|
||||
func cancel(id string) {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
if _, ok := aboutToCommitTxn[id]; ok {
|
||||
delete(aboutToCommitTxn, id)
|
||||
}
|
||||
}
|
||||
|
||||
func commitAll() {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
for k, v := range aboutToCommitTxn {
|
||||
// txn not due to commit, skip
|
||||
if time.Now().Before(v.commitTime) {
|
||||
continue
|
||||
}
|
||||
|
||||
err := repo.CommitTransaction(v.txn)
|
||||
if err != nil {
|
||||
go v.ctx.bot.Send(tgbotapi.NewMessage(v.ctx.chat.ID, fmt.Sprintf("Failed to commit txn: %v", err)))
|
||||
}
|
||||
|
||||
delete(aboutToCommitTxn, k)
|
||||
|
||||
if err == nil {
|
||||
// delete transaction message
|
||||
go v.ctx.bot.Send(tgbotapi.NewDeleteMessage(v.ctx.chat.ID, v.ctx.msg.MessageID))
|
||||
}
|
||||
// delete transaction confirmation message
|
||||
go v.ctx.bot.Send(tgbotapi.NewDeleteMessage(v.ctx.chat.ID, v.txmMsg.MessageID))
|
||||
// delete transaction cancel callback message
|
||||
go v.ctx.bot.Send(tgbotapi.NewDeleteMessage(v.ctx.chat.ID, v.callbackMsg.MessageID))
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import (
|
|||
"log"
|
||||
"os"
|
||||
|
||||
"git.s8k.top/SeraphJACK/beanbot/bot"
|
||||
"git.s8k.top/SeraphJACK/beanbot/config"
|
||||
"git.s8k.top/SeraphJACK/beanbot/repo"
|
||||
"github.com/spf13/pflag"
|
||||
|
@ -32,4 +33,9 @@ func main() {
|
|||
log.Fatalf("Failed to init beancount repository: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := bot.Start(); err != nil {
|
||||
log.Fatalf("Failed to start telegram bot: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ import (
|
|||
)
|
||||
|
||||
type Config struct {
|
||||
BotToken string `yaml:"botToken"`
|
||||
AuthorizedUserIDs []int64 `yaml:"authorizedUserIDs"`
|
||||
Repo string `yaml:"repo"`
|
||||
Username string `yaml:"username"`
|
||||
Password string `yaml:"password"`
|
||||
|
@ -19,6 +21,8 @@ type Config struct {
|
|||
}
|
||||
|
||||
var Cfg = Config{
|
||||
BotToken: "xxx",
|
||||
AuthorizedUserIDs: []int64{},
|
||||
Repo: "https://git.xxx.com/xxx/xxx.git",
|
||||
Username: "someone",
|
||||
Password: "password",
|
||||
|
|
2
go.mod
2
go.mod
|
@ -4,6 +4,8 @@ go 1.21.1
|
|||
|
||||
require (
|
||||
github.com/go-git/go-git/v5 v5.9.0
|
||||
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1
|
||||
github.com/google/uuid v1.3.1
|
||||
github.com/spf13/pflag v1.0.5
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
|
4
go.sum
4
go.sum
|
@ -33,10 +33,14 @@ github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0
|
|||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo=
|
||||
github.com/go-git/go-git/v5 v5.9.0 h1:cD9SFA7sHVRdJ7AYck1ZaAa/yeuBvGPxwXDL8cxrObY=
|
||||
github.com/go-git/go-git/v5 v5.9.0/go.mod h1:RKIqga24sWdMGZF+1Ekv9kylsDz6LzdTSI2s/OsZWE0=
|
||||
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 h1:wG8n/XJQ07TmjbITcGiUaOtXxdrINDz1b0J1w0SzqDc=
|
||||
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1/go.mod h1:A2S0CWkNylc2phvKXWBBdD3K0iGnDBGbzRpISP2zBl8=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
|
||||
|
|
Loading…
Reference in New Issue