Improve bot messages #31
6 changed files with 54 additions and 15 deletions
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.faercol.me/faercol/public-ip-tracker/tracker/config"
|
"git.faercol.me/faercol/public-ip-tracker/tracker/config"
|
||||||
|
@ -15,6 +16,20 @@ import (
|
||||||
"github.com/sirupsen/logrus"
|
"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 {
|
type Notifier struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
|
@ -29,6 +44,7 @@ type Notifier struct {
|
||||||
changesChan chan net.IP
|
changesChan chan net.IP
|
||||||
exitChan chan struct{}
|
exitChan chan struct{}
|
||||||
logger logrus.Logger
|
logger logrus.Logger
|
||||||
|
hostname string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Notifier) SendInitMessage() error {
|
func (n *Notifier) SendInitMessage() error {
|
||||||
|
@ -43,8 +59,7 @@ func (n *Notifier) SendInitMessage() error {
|
||||||
currentTime := n.timeGetter()
|
currentTime := n.timeGetter()
|
||||||
|
|
||||||
n.logger.Debug("Sending init message to Telegram")
|
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, formatInitMsg(currentTime, publicIP, n.hostname), structs.FormattingMarkdownV2); err != nil {
|
||||||
if err := n.tgBot.SendMessage(n.ctx, n.tgChatID, initMsg); err != nil {
|
|
||||||
return fmt.Errorf("failed to send initialization message: %w", err)
|
return fmt.Errorf("failed to send initialization message: %w", err)
|
||||||
}
|
}
|
||||||
n.logger.Debug("Message sent")
|
n.logger.Debug("Message sent")
|
||||||
|
@ -52,8 +67,7 @@ func (n *Notifier) SendInitMessage() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Notifier) sendUpdatedIPMsg() 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, formatUpdate(n.timeGetter(), n.currentIP, n.hostname), structs.FormattingMarkdownV2); err != nil {
|
||||||
if err := n.tgBot.SendMessage(n.ctx, n.tgChatID, updateMsg); err != nil {
|
|
||||||
return fmt.Errorf("failed to send update message: %w", err)
|
return fmt.Errorf("failed to send update message: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -61,7 +75,7 @@ func (n *Notifier) sendUpdatedIPMsg() error {
|
||||||
|
|
||||||
func (n *Notifier) sendCurrentIP() error {
|
func (n *Notifier) sendCurrentIP() error {
|
||||||
statusMsg := fmt.Sprintf("Current public IP is %s", n.currentIP)
|
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 fmt.Errorf("failed to send message: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -142,5 +156,6 @@ func New(ctx context.Context, config *config.Config) *Notifier {
|
||||||
frequency: config.PollingFrequency,
|
frequency: config.PollingFrequency,
|
||||||
tgWatcher: notifier.New(config.Telegram.Token),
|
tgWatcher: notifier.New(config.Telegram.Token),
|
||||||
logger: logger.L,
|
logger: logger.L,
|
||||||
|
hostname: config.Hostname,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
// Need to mock the telegram bot, because no mock is provided by my own lib, what a shame.
|
||||||
type mockTGBot struct {
|
type mockTGBot struct {
|
||||||
SendMessageProp error
|
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
|
// 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
|
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 {
|
if mb.SendMessageFunc == nil {
|
||||||
return mb.SendMessageProp
|
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
|
// 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())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
called := false
|
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{
|
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 {
|
if chatID != expectedChatID {
|
||||||
t.Errorf("Unexpected chatID %d", chatID)
|
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)
|
t.Errorf("Unexpected message %s", content)
|
||||||
}
|
}
|
||||||
called = true
|
called = true
|
||||||
|
@ -75,6 +80,7 @@ func TestInit(t *testing.T) {
|
||||||
ipGetter: &ipGetter,
|
ipGetter: &ipGetter,
|
||||||
frequency: 1 * time.Minute,
|
frequency: 1 * time.Minute,
|
||||||
tgWatcher: &mockTGNotifier{},
|
tgWatcher: &mockTGNotifier{},
|
||||||
|
hostname: "test",
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := bot.SendInitMessage(); err != nil {
|
if err := bot.SendInitMessage(); err != nil {
|
||||||
|
@ -91,12 +97,17 @@ func TestUpdateIP(t *testing.T) {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
called := false
|
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{
|
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 {
|
if chatID != expectedChatID {
|
||||||
t.Errorf("Unexpected chatID %d", chatID)
|
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)
|
t.Errorf("Unexpected message %s", content)
|
||||||
}
|
}
|
||||||
called = true
|
called = true
|
||||||
|
@ -120,6 +131,7 @@ func TestUpdateIP(t *testing.T) {
|
||||||
ipGetter: &ipGetter,
|
ipGetter: &ipGetter,
|
||||||
tgWatcher: &mockTGNotifier{},
|
tgWatcher: &mockTGNotifier{},
|
||||||
frequency: 500 * time.Millisecond,
|
frequency: 500 * time.Millisecond,
|
||||||
|
hostname: "test",
|
||||||
}
|
}
|
||||||
|
|
||||||
go bot.Run()
|
go bot.Run()
|
||||||
|
|
|
@ -25,12 +25,14 @@ type jsonLogConfig struct {
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Telegram *TelegramConfig
|
Telegram *TelegramConfig
|
||||||
PollingFrequency time.Duration
|
PollingFrequency time.Duration
|
||||||
|
Hostname string
|
||||||
Log *LogConfig
|
Log *LogConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
type jsonConfig struct {
|
type jsonConfig struct {
|
||||||
Telegram *TelegramConfig `json:"telegram"`
|
Telegram *TelegramConfig `json:"telegram"`
|
||||||
PollingFrequency int64 `json:"polling_frequency"`
|
PollingFrequency int64 `json:"polling_frequency"`
|
||||||
|
Hostname string `json:"hostname"`
|
||||||
Log *jsonLogConfig `json:"log"`
|
Log *jsonLogConfig `json:"log"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,6 +57,7 @@ func New(filepath string) (*Config, error) {
|
||||||
return &Config{
|
return &Config{
|
||||||
Telegram: jsonConf.Telegram,
|
Telegram: jsonConf.Telegram,
|
||||||
PollingFrequency: time.Duration(jsonConf.PollingFrequency) * time.Second,
|
PollingFrequency: time.Duration(jsonConf.PollingFrequency) * time.Second,
|
||||||
|
Hostname: jsonConf.Hostname,
|
||||||
Log: &LogConfig{
|
Log: &LogConfig{
|
||||||
Level: parseLevel(jsonConf.Log.Level),
|
Level: parseLevel(jsonConf.Log.Level),
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,7 +3,7 @@ module git.faercol.me/faercol/public-ip-tracker/tracker
|
||||||
go 1.16
|
go 1.16
|
||||||
|
|
||||||
require (
|
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/google/uuid v1.3.0
|
||||||
github.com/sirupsen/logrus v1.9.0
|
github.com/sirupsen/logrus v1.9.0
|
||||||
)
|
)
|
||||||
|
|
|
@ -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.2.0 h1:wAY4qr0T0I2mgW1HxAZFdzhOdXuZ5WE4e8GNR4t7Yrs=
|
||||||
github.com/ahugues/go-telegram-api v0.1.0/go.mod h1:8I/JWxd9GYM7dHOgGmkRI3Ei1u+nGvzeR2knIMmFw7E=
|
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.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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
|
|
@ -38,6 +38,15 @@ func main() {
|
||||||
logger.Init(conf.Log.Level)
|
logger.Init(conf.Log.Level)
|
||||||
logger.L.Infof("Intialized logger with level %v", 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")
|
logger.L.Debug("Initializing notification bot")
|
||||||
notifBot := bot.New(mainCtx, conf)
|
notifBot := bot.New(mainCtx, conf)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue