2023-06-05 13:41:48 +00:00
|
|
|
package bot
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"git.dev.m-and-m.ovh/mderasse/tesla/alert"
|
|
|
|
"git.dev.m-and-m.ovh/mderasse/tesla/api"
|
|
|
|
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
tele "gopkg.in/telebot.v3"
|
|
|
|
)
|
|
|
|
|
|
|
|
var apiClient *api.Client
|
|
|
|
|
|
|
|
// Init will initialize telegram bot.
|
|
|
|
func Init(alertChan chan api.Availability) {
|
|
|
|
log.Info("Starting bot initialization")
|
|
|
|
|
|
|
|
log.Debug("Loading bot configuration")
|
|
|
|
config, err := initBotConfig()
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("Fail to initialize bot configuration. Error: %s", err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
apiClient, err = api.NewClient()
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("Fail to instantiate the HTTP Client. Error: %s", err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
pref := tele.Settings{
|
|
|
|
Token: config.Token,
|
|
|
|
Poller: &tele.LongPoller{Timeout: 10 * time.Second},
|
|
|
|
ParseMode: tele.ModeMarkdownV2,
|
|
|
|
}
|
|
|
|
|
|
|
|
bot, err := tele.NewBot(pref)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Debug("Initializing bot middlewares")
|
|
|
|
initMiddlewares(bot, config)
|
|
|
|
|
|
|
|
log.Debug("Initializing bot commands")
|
|
|
|
initCommands(bot, config)
|
|
|
|
|
|
|
|
log.Debug("Launching alert handler")
|
|
|
|
go handleAlert(bot, config, alertChan)
|
|
|
|
|
|
|
|
bot.Start()
|
|
|
|
}
|
|
|
|
|
|
|
|
func handleAlert(bot *tele.Bot, config *botConfig, alertChan chan api.Availability) {
|
|
|
|
for availability := range alertChan {
|
|
|
|
log.Warn("ALLERLRTEFDF")
|
|
|
|
for _, chatId := range config.AlertChatIds {
|
|
|
|
log.Infof("Sending alert to chat %d", chatId)
|
|
|
|
|
|
|
|
_, err := bot.Send(
|
|
|
|
tele.ChatID(chatId),
|
|
|
|
fmt.Sprintf(
|
|
|
|
"ALERT\\!\\! Found a Tesla Long Range in *%s* color is: *%d* €",
|
|
|
|
strings.Join(availability.Paint, " and "),
|
|
|
|
availability.Price,
|
|
|
|
),
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
log.Warnf("Fail to send alert message. Error: %s", err.Error())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func initMiddlewares(bot *tele.Bot, config *botConfig) {
|
|
|
|
log.Infof("Trusting the following chats: %v", config.WhiteListChatIds)
|
|
|
|
bot.Use(
|
2023-06-05 19:01:52 +00:00
|
|
|
middlewareAllowChat(config.WhiteListChatIds...),
|
2023-06-05 13:41:48 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2023-06-05 19:01:52 +00:00
|
|
|
func middlewareAllowChat(chatIds ...int64) tele.MiddlewareFunc {
|
|
|
|
return func(next tele.HandlerFunc) tele.HandlerFunc {
|
|
|
|
return func(c tele.Context) error {
|
|
|
|
for _, chat := range chatIds {
|
|
|
|
if chat == c.Chat().ID {
|
|
|
|
return next(c)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-05 13:41:48 +00:00
|
|
|
func initCommands(bot *tele.Bot, config *botConfig) {
|
|
|
|
|
|
|
|
bot.Handle(tele.OnText, func(c tele.Context) error {
|
|
|
|
|
|
|
|
msg := c.Text()
|
|
|
|
if c.Chat().ID < 0 {
|
|
|
|
if !strings.HasPrefix(msg, fmt.Sprintf("@%s", config.BotName)) {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
msg = strings.TrimPrefix(msg, fmt.Sprintf("@%s ", config.BotName))
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Debugf("receive telegram message: %s", msg)
|
|
|
|
|
|
|
|
switch strings.ToLower(msg) {
|
|
|
|
case "help":
|
|
|
|
return help(c)
|
|
|
|
case "price":
|
|
|
|
return price(c)
|
|
|
|
case "list":
|
|
|
|
return list(c)
|
|
|
|
default:
|
|
|
|
return home(c)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
bot.Handle(&tele.Btn{Unique: "list"}, list)
|
|
|
|
bot.Handle(&tele.Btn{Unique: "price"}, price)
|
|
|
|
bot.Handle(&tele.Btn{Unique: "help"}, help)
|
|
|
|
bot.Handle(&tele.Btn{Unique: "home"}, home)
|
|
|
|
}
|
|
|
|
|
|
|
|
func home(c tele.Context) error {
|
|
|
|
return c.EditOrReply(
|
|
|
|
"Welcome to Tesla Alerter\\. What can i do for you ?",
|
|
|
|
&homeMenu,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func help(c tele.Context) error {
|
|
|
|
return c.EditOrReply(
|
|
|
|
fmt.Sprintf(`I'm a bot that have for main objective to inform you about tesla price\.
|
|
|
|
I will also send you alert when tesla car are at a price under %d€`, alert.PriceAlert),
|
|
|
|
&helpMenu,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func price(c tele.Context) error {
|
|
|
|
availabilities, err := apiClient.GetAvailabilities(context.Background(), &api.AvailabilityParams{
|
|
|
|
Query: carFilter,
|
|
|
|
Count: 1,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
log.Warnf("Fail to retrieve availability from tesla website. Error: %s", err.Error())
|
|
|
|
return c.Send("Fail to retrieve availability from tesla website :(")
|
|
|
|
}
|
|
|
|
|
|
|
|
return c.Reply(
|
|
|
|
fmt.Sprintf("The lowest price currently found for a *Tesla Long Range* in *%s* color is: *%d* €",
|
|
|
|
strings.Join(availabilities.Results[0].Paint, " and "),
|
|
|
|
availabilities.Results[0].Price,
|
|
|
|
),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func list(c tele.Context) error {
|
|
|
|
availabilities, err := apiClient.GetAvailabilities(context.Background(), &api.AvailabilityParams{
|
|
|
|
Query: carFilter,
|
|
|
|
Count: 30,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
log.Warnf("Fail to retrieve availability from tesla website. Error: %s", err.Error())
|
|
|
|
return c.Send("Fail to retrieve availability from tesla website :(")
|
|
|
|
}
|
|
|
|
|
|
|
|
availabilitiesStr := fmt.Sprintf("Found *%s* cars\n", availabilities.TotalMatchesFound)
|
|
|
|
for _, availability := range availabilities.Results {
|
|
|
|
availabilitiesStr = fmt.Sprintf(
|
|
|
|
"%sTesla Long Range, color *%s* available in *%s* for *%d*€\n",
|
|
|
|
availabilitiesStr,
|
|
|
|
strings.Join(availability.Paint, " and "),
|
|
|
|
strings.ReplaceAll(availability.City, "-", "\\-"),
|
|
|
|
availability.Price,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
return c.Reply(availabilitiesStr)
|
|
|
|
}
|