lightningtipbot/internal/telegram/bot.go
calle 0631fd53eb
WIP: Satdress (#331)
* satdress rebase

* check config

* satdress rebase

* check config

* check for invoices

* return error

* Update inline photo v5 (#332)

* update url

* round logo

* resize

Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com>

* new logo (#333)

Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com>

* help (#334)

Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com>

* add file (#335)

Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com>

* markdown (#336)

Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com>

* satdress rebase

* check config

* satdress rebase

* check for invoices

* return error

* satdress works

* add lnbits

* timeout

* error checking

* small lnd

* errors

* button fix

Co-authored-by: LightningTipBot <88730856+LightningTipBot@users.noreply.github.com>
2022-04-29 14:28:12 +02:00

144 lines
3.8 KiB
Go

package telegram
import (
"fmt"
"os"
"os/signal"
"sync"
"syscall"
"time"
"github.com/LightningTipBot/LightningTipBot/internal/runtime/mutex"
limiter "github.com/LightningTipBot/LightningTipBot/internal/rate"
"github.com/eko/gocache/store"
"github.com/LightningTipBot/LightningTipBot/internal"
"github.com/LightningTipBot/LightningTipBot/internal/lnbits"
"github.com/LightningTipBot/LightningTipBot/internal/storage"
gocache "github.com/patrickmn/go-cache"
log "github.com/sirupsen/logrus"
tb "gopkg.in/lightningtipbot/telebot.v3"
)
type TipBot struct {
DB *Databases
Bunt *storage.DB
ShopBunt *storage.DB
Telegram *tb.Bot
Client *lnbits.Client
limiter map[string]limiter.Limiter
Cache
}
type Cache struct {
*store.GoCacheStore
}
var (
botWalletInitialisation = sync.Once{}
telegramHandlerRegistration = sync.Once{}
)
// NewBot migrates data and creates a new bot
func NewBot() TipBot {
gocacheClient := gocache.New(5*time.Minute, 10*time.Minute)
gocacheStore := store.NewGoCache(gocacheClient, nil)
// create sqlite databases
dbs := AutoMigration()
limiter.Start()
return TipBot{
DB: dbs,
Client: lnbits.NewClient(internal.Configuration.Lnbits.AdminKey, internal.Configuration.Lnbits.Url),
Bunt: createBunt(internal.Configuration.Database.BuntDbPath),
ShopBunt: createBunt(internal.Configuration.Database.ShopBuntDbPath),
Telegram: newTelegramBot(),
Cache: Cache{GoCacheStore: gocacheStore},
}
}
// newTelegramBot will create a new Telegram bot.
func newTelegramBot() *tb.Bot {
tgb, err := tb.NewBot(tb.Settings{
Token: internal.Configuration.Telegram.ApiKey,
Poller: &tb.LongPoller{Timeout: 60 * time.Second},
ParseMode: tb.ModeMarkdown,
})
if err != nil {
panic(err)
}
return tgb
}
// initBotWallet will create / initialize the bot wallet
// todo -- may want to derive user wallets from this specific bot wallet (master wallet), since lnbits usermanager extension is able to do that.
func (bot TipBot) initBotWallet() error {
botWalletInitialisation.Do(func() {
_, err := bot.initWallet(bot.Telegram.Me)
if err != nil {
log.Errorln(fmt.Sprintf("[initBotWallet] Could not initialize bot wallet: %s", err.Error()))
return
}
})
return nil
}
// GracefulShutdown will gracefully shutdown the bot
// It will wait for all mutex locks to unlock before shutdown.
func (bot *TipBot) GracefulShutdown() {
t := time.NewTicker(time.Second * 10)
log.Infof("[shutdown] Graceful shutdown (timeout=10s).")
for {
select {
case <-t.C:
// timer expired
log.Infof("[shutdown] Graceful shutdown timeout reached. Forcing shutdown.")
return
default:
// check if all mutex locks are unlocked
if mutex.IsEmpty() {
log.Infof("[shutdown] Graceful shutdown successful.")
return
}
}
time.Sleep(time.Second)
log.Tracef("[shutdown] Trying graceful shutdown...")
}
}
// Start will initialize the Telegram bot and lnbits.
func (bot *TipBot) Start() {
log.Infof("[Telegram] Authorized on account @%s", bot.Telegram.Me.Username)
// initialize the bot wallet
err := bot.initBotWallet()
if err != nil {
log.Errorf("Could not initialize bot wallet: %s", err.Error())
}
// register telegram handlers
bot.registerTelegramHandlers()
// download bot avatar once
bot.downloadMyProfilePicture()
// edit worker collects messages to edit and
// periodically edits them
bot.startEditWorker()
// register callbacks for invoices
initInvoiceEventCallbacks(bot)
// register callbacks for user state changes
initializeStateCallbackMessage(bot)
// start the telegram bot
go bot.Telegram.Start()
// gracefully shutdown
exit := make(chan os.Signal, 1) // we need to reserve to buffer size 1, so the notifier are not blocked
// we need to catch SIGTERM and SIGSTOP
signal.Notify(exit, os.Interrupt, syscall.SIGTERM, syscall.SIGSTOP)
<-exit
// gracefully shutdown
bot.GracefulShutdown()
}