Improve bot messages
All checks were successful
continuous-integration/drone/push Build is passing

Ref #13

This commit uses markdown formatting to improve the messages sent to
the Telegram bot.
This commit is contained in:
Melora Hugues 2023-02-04 19:07:04 +01:00
parent 51bc7cb3a0
commit d9c57f7441
6 changed files with 54 additions and 15 deletions

View file

@ -4,6 +4,7 @@ import (
"context"
"fmt"
"net"
"strings"
"time"
"git.faercol.me/faercol/public-ip-tracker/tracker/config"
@ -15,6 +16,20 @@ import (
"github.com/sirupsen/logrus"
)
func formatInitMsg(currentTime time.Time, publicIP net.IP, hostname string) string {
formattedHostname := fmt.Sprintf("`%s`", hostname)
formattedIP := strings.ReplaceAll(publicIP.String(), ".", "\\.")
return fmt.Sprintf(`\[Host %s\] %s
Public IP tracker initialized\. Current IP is %s`, formattedHostname, currentTime.Format(time.RFC1123), formattedIP)
}
func formatUpdate(currentTime time.Time, publicIP net.IP, hostname string) string {
formattedHostname := fmt.Sprintf("`%s`", hostname)
formattedIP := strings.ReplaceAll(publicIP.String(), ".", "\\.")
return fmt.Sprintf(`\[Host %s\] %s
Public IP has changed, new IP is %s`, formattedHostname, currentTime.Format(time.RFC1123), formattedIP)
}
type Notifier struct {
ctx context.Context
cancel context.CancelFunc
@ -29,6 +44,7 @@ type Notifier struct {
changesChan chan net.IP
exitChan chan struct{}
logger logrus.Logger
hostname string
}
func (n *Notifier) SendInitMessage() error {
@ -43,8 +59,7 @@ func (n *Notifier) SendInitMessage() error {
currentTime := n.timeGetter()
n.logger.Debug("Sending init message to Telegram")
initMsg := fmt.Sprintf("Public IP tracker initialized at %v, public IP is %s", currentTime, publicIP)
if err := n.tgBot.SendMessage(n.ctx, n.tgChatID, initMsg); err != nil {
if err := n.tgBot.SendMessage(n.ctx, n.tgChatID, formatInitMsg(currentTime, publicIP, n.hostname), structs.FormattingMarkdownV2); err != nil {
return fmt.Errorf("failed to send initialization message: %w", err)
}
n.logger.Debug("Message sent")
@ -52,8 +67,7 @@ func (n *Notifier) SendInitMessage() error {
}
func (n *Notifier) sendUpdatedIPMsg() error {
updateMsg := fmt.Sprintf("Public IP has been changed, is now %s", n.currentIP)
if err := n.tgBot.SendMessage(n.ctx, n.tgChatID, updateMsg); err != nil {
if err := n.tgBot.SendMessage(n.ctx, n.tgChatID, formatUpdate(n.timeGetter(), n.currentIP, n.hostname), structs.FormattingMarkdownV2); err != nil {
return fmt.Errorf("failed to send update message: %w", err)
}
return nil
@ -61,7 +75,7 @@ func (n *Notifier) sendUpdatedIPMsg() error {
func (n *Notifier) sendCurrentIP() error {
statusMsg := fmt.Sprintf("Current public IP is %s", n.currentIP)
if err := n.tgBot.SendMessage(n.ctx, n.tgChatID, statusMsg); err != nil {
if err := n.tgBot.SendMessage(n.ctx, n.tgChatID, statusMsg, structs.FormattingMarkdownV2); err != nil {
return fmt.Errorf("failed to send message: %w", err)
}
return nil
@ -142,5 +156,6 @@ func New(ctx context.Context, config *config.Config) *Notifier {
frequency: config.PollingFrequency,
tgWatcher: notifier.New(config.Telegram.Token),
logger: logger.L,
hostname: config.Hostname,
}
}

View file

@ -17,7 +17,7 @@ const expectedChatID = 42
// Need to mock the telegram bot, because no mock is provided by my own lib, what a shame.
type mockTGBot struct {
SendMessageProp error
SendMessageFunc func(context.Context, int64, string) error
SendMessageFunc func(context.Context, int64, string, structs.FormattingOption) error
}
// Do nothing here, it's not used by this bot
@ -25,11 +25,11 @@ func (mb *mockTGBot) GetMe(ctx context.Context) (structs.User, error) {
return structs.User{}, nil
}
func (mb *mockTGBot) SendMessage(ctx context.Context, chatID int64, content string) error {
func (mb *mockTGBot) SendMessage(ctx context.Context, chatID int64, content string, option structs.FormattingOption) error {
if mb.SendMessageFunc == nil {
return mb.SendMessageProp
}
return mb.SendMessageFunc(ctx, chatID, content)
return mb.SendMessageFunc(ctx, chatID, content, option)
}
// Need to mock the notifier here too, but will do later on, I need to improve my lib in the future
@ -49,12 +49,17 @@ func TestInit(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
called := false
expectedMsg := "\\[Host `test`\\] Sat, 28 Jan 2023 14:17:12 UTC\nPublic IP tracker initialized\\. Current IP is 198\\.51\\.100\\.42"
tgBot := mockTGBot{
SendMessageFunc: func(ctx context.Context, chatID int64, content string) error {
SendMessageFunc: func(ctx context.Context, chatID int64, content string, option structs.FormattingOption) error {
if option != structs.FormattingMarkdownV2 {
t.Errorf("Unexpected formatting option %v", option)
}
if chatID != expectedChatID {
t.Errorf("Unexpected chatID %d", chatID)
}
if content != "Public IP tracker initialized at 2023-01-28 14:17:12 +0000 UTC, public IP is 198.51.100.42" {
if content != expectedMsg {
t.Errorf("Unexpected message %s", content)
}
called = true
@ -75,6 +80,7 @@ func TestInit(t *testing.T) {
ipGetter: &ipGetter,
frequency: 1 * time.Minute,
tgWatcher: &mockTGNotifier{},
hostname: "test",
}
if err := bot.SendInitMessage(); err != nil {
@ -91,12 +97,17 @@ func TestUpdateIP(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
called := false
expectedMsg := "\\[Host `test`\\] Sat, 28 Jan 2023 14:17:12 UTC\nPublic IP has changed, new IP is 198\\.51\\.100\\.42"
tgBot := mockTGBot{
SendMessageFunc: func(ctx context.Context, chatID int64, content string) error {
SendMessageFunc: func(ctx context.Context, chatID int64, content string, option structs.FormattingOption) error {
if option != structs.FormattingMarkdownV2 {
t.Errorf("Unexpected formatting option %v", option)
}
if chatID != expectedChatID {
t.Errorf("Unexpected chatID %d", chatID)
}
if content != "Public IP has been changed, is now 198.51.100.42" {
if content != expectedMsg {
t.Errorf("Unexpected message %s", content)
}
called = true
@ -120,6 +131,7 @@ func TestUpdateIP(t *testing.T) {
ipGetter: &ipGetter,
tgWatcher: &mockTGNotifier{},
frequency: 500 * time.Millisecond,
hostname: "test",
}
go bot.Run()

View file

@ -25,12 +25,14 @@ type jsonLogConfig struct {
type Config struct {
Telegram *TelegramConfig
PollingFrequency time.Duration
Hostname string
Log *LogConfig
}
type jsonConfig struct {
Telegram *TelegramConfig `json:"telegram"`
PollingFrequency int64 `json:"polling_frequency"`
Hostname string `json:"hostname"`
Log *jsonLogConfig `json:"log"`
}
@ -55,6 +57,7 @@ func New(filepath string) (*Config, error) {
return &Config{
Telegram: jsonConf.Telegram,
PollingFrequency: time.Duration(jsonConf.PollingFrequency) * time.Second,
Hostname: jsonConf.Hostname,
Log: &LogConfig{
Level: parseLevel(jsonConf.Log.Level),
},

View file

@ -3,7 +3,7 @@ module git.faercol.me/faercol/public-ip-tracker/tracker
go 1.16
require (
github.com/ahugues/go-telegram-api v0.1.0
github.com/ahugues/go-telegram-api v0.2.0
github.com/google/uuid v1.3.0
github.com/sirupsen/logrus v1.9.0
)

View file

@ -1,5 +1,5 @@
github.com/ahugues/go-telegram-api v0.1.0 h1:CGJG0WR282O0hAO9JH2RutPj+Vn+Q+zbjdSHjuvN5yY=
github.com/ahugues/go-telegram-api v0.1.0/go.mod h1:8I/JWxd9GYM7dHOgGmkRI3Ei1u+nGvzeR2knIMmFw7E=
github.com/ahugues/go-telegram-api v0.2.0 h1:wAY4qr0T0I2mgW1HxAZFdzhOdXuZ5WE4e8GNR4t7Yrs=
github.com/ahugues/go-telegram-api v0.2.0/go.mod h1:8I/JWxd9GYM7dHOgGmkRI3Ei1u+nGvzeR2knIMmFw7E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=

View file

@ -38,6 +38,15 @@ func main() {
logger.Init(conf.Log.Level)
logger.L.Infof("Intialized logger with level %v", conf.Log.Level)
if conf.Hostname == "" {
logger.L.Warn("Unspecified hostname, trying to get current hostname, this might not be reliable")
conf.Hostname, err = os.Hostname()
if err != nil {
logger.L.Errorf("Failed to get hostname, using a default value: %s", err.Error())
conf.Hostname = "default"
}
}
logger.L.Debug("Initializing notification bot")
notifBot := bot.New(mainCtx, conf)