feat(init): Start a bot for tesla
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
174
bot/bot.go
Normal file
174
bot/bot.go
Normal file
@ -0,0 +1,174 @@
|
||||
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"
|
||||
"gopkg.in/telebot.v3/middleware"
|
||||
|
||||
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(
|
||||
middleware.Whitelist(config.WhiteListChatIds...),
|
||||
)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
16
bot/botMenu.go
Normal file
16
bot/botMenu.go
Normal file
@ -0,0 +1,16 @@
|
||||
package bot
|
||||
|
||||
import tele "gopkg.in/telebot.v3"
|
||||
|
||||
var homeMenu tele.ReplyMarkup = tele.ReplyMarkup{
|
||||
InlineKeyboard: [][]tele.InlineButton{
|
||||
{tele.InlineButton{Text: "Lowest Price", Unique: "price"}, tele.InlineButton{Text: "List", Unique: "list"}},
|
||||
{tele.InlineButton{Text: "Help", Unique: "help"}},
|
||||
},
|
||||
}
|
||||
|
||||
var helpMenu tele.ReplyMarkup = tele.ReplyMarkup{
|
||||
InlineKeyboard: [][]tele.InlineButton{
|
||||
{tele.InlineButton{Text: "Back", Unique: "home"}},
|
||||
},
|
||||
}
|
92
bot/config.go
Normal file
92
bot/config.go
Normal file
@ -0,0 +1,92 @@
|
||||
package bot
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"git.dev.m-and-m.ovh/mderasse/tesla/api"
|
||||
)
|
||||
|
||||
var carFilter api.AvailabilityQueryParams = api.AvailabilityQueryParams{
|
||||
Model: "my",
|
||||
Condition: "new",
|
||||
Options: api.OptionsParams{
|
||||
Trim: []string{"LRAWD"},
|
||||
},
|
||||
Arrangeby: "Price",
|
||||
Order: "asc",
|
||||
Market: "FR",
|
||||
Language: "fr",
|
||||
SuperRegion: "north america",
|
||||
Lng: 3.0511,
|
||||
Lat: 50.624,
|
||||
Zip: "59100",
|
||||
Range: 0,
|
||||
Region: "FR",
|
||||
}
|
||||
|
||||
// botConfig contain configuration for the telegram bot.
|
||||
type botConfig struct {
|
||||
AlertChatIds []int64
|
||||
BotName string
|
||||
WhiteListChatIds []int64
|
||||
Token string
|
||||
}
|
||||
|
||||
func initBotConfig() (*botConfig, error) {
|
||||
alertChatIdsArrStr := strings.Split(os.Getenv("TELEGRAM_ALERT_CHAT_IDS"), ",")
|
||||
whitelistChatIdsArrStr := strings.Split(os.Getenv("TELEGRAM_WHITELIST_CHAT_IDS"), ",")
|
||||
botName := os.Getenv("TELEGRAM_BOT_NAME")
|
||||
token := os.Getenv("TELEGRAM_TOKEN")
|
||||
|
||||
// FOR DEV
|
||||
// botName = "M_AND_M_Test_bot"
|
||||
// token = "6273217607:AAGvMIU6bpc7xFWKDhd4llPH6f9zhgUzirs"
|
||||
// alertChatIdsArrStr = []string{"648385994", "-894368809", "-893895409"}
|
||||
// whitelistChatIdsArrStr = []string{"648385994", "-894368809", "-893895409"}
|
||||
|
||||
if len(alertChatIdsArrStr) == 0 {
|
||||
return nil, fmt.Errorf("missing TELEGRAM_ALERT_CHAT_IDS environment variable")
|
||||
}
|
||||
|
||||
if len(whitelistChatIdsArrStr) == 0 {
|
||||
return nil, fmt.Errorf("missing TELEGRAM_WHITELIST_CHAT_IDS environment variable")
|
||||
}
|
||||
|
||||
if botName == "" {
|
||||
return nil, fmt.Errorf("missing TELEGRAM_BOT_NAME environment variable")
|
||||
}
|
||||
|
||||
if token == "" {
|
||||
return nil, fmt.Errorf("missing TELEGRAM_TOKEN environment variable")
|
||||
}
|
||||
|
||||
config := botConfig{
|
||||
AlertChatIds: []int64{},
|
||||
BotName: botName,
|
||||
Token: token,
|
||||
WhiteListChatIds: []int64{},
|
||||
}
|
||||
|
||||
for _, chatIdStr := range alertChatIdsArrStr {
|
||||
chatId, err := strconv.ParseInt(chatIdStr, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("impossible to use TELEGRAM_ALERT_CHAT_IDS. format expected: int64,int64")
|
||||
}
|
||||
|
||||
config.AlertChatIds = append(config.AlertChatIds, chatId)
|
||||
}
|
||||
|
||||
for _, chatIdStr := range whitelistChatIdsArrStr {
|
||||
chatId, err := strconv.ParseInt(chatIdStr, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("impossible to use TELEGRAM_WHITELIST_CHAT_IDS. format expected: int64,int64")
|
||||
}
|
||||
|
||||
config.WhiteListChatIds = append(config.AlertChatIds, chatId)
|
||||
}
|
||||
|
||||
return &config, nil
|
||||
}
|
Reference in New Issue
Block a user