public-ip-tracker/tracker/bot/bot.go
Melora Hugues 51bc7cb3a0
All checks were successful
continuous-integration/drone/push Build is passing
Use logrus to handle logs
This commit adds the logrus module, and improves logs handling for the
entire program. Error logs are better displayed, and the log level can
be set from the configuration file.
2023-02-04 18:15:22 +01:00

146 lines
4 KiB
Go

package bot
import (
"context"
"fmt"
"net"
"time"
"git.faercol.me/faercol/public-ip-tracker/tracker/config"
"git.faercol.me/faercol/public-ip-tracker/tracker/ip"
"git.faercol.me/faercol/public-ip-tracker/tracker/logger"
"github.com/ahugues/go-telegram-api/bot"
"github.com/ahugues/go-telegram-api/notifier"
"github.com/ahugues/go-telegram-api/structs"
"github.com/sirupsen/logrus"
)
type Notifier struct {
ctx context.Context
cancel context.CancelFunc
tgBot bot.Bot
tgChatID int64
tgWatcher notifier.EventNotifier
ipGetter ip.IPGetter
timeGetter func() time.Time
currentIP net.IP
frequency time.Duration
errChan chan error
changesChan chan net.IP
exitChan chan struct{}
logger logrus.Logger
}
func (n *Notifier) SendInitMessage() error {
n.logger.Debug("Getting current public IP")
publicIP, err := n.ipGetter.GetCurrentPublicIP(n.ctx)
if err != nil {
return fmt.Errorf("failed to get current public IP: %w", err)
}
n.logger.Debugf("Current public IP is %s", publicIP.String())
n.currentIP = publicIP
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 {
return fmt.Errorf("failed to send initialization message: %w", err)
}
n.logger.Debug("Message sent")
return nil
}
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 {
return fmt.Errorf("failed to send update message: %w", err)
}
return nil
}
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 {
return fmt.Errorf("failed to send message: %w", err)
}
return nil
}
func (n *Notifier) watchTG() {
n.logger.Debug("Subscribing to messages notificator")
id, updateChan := n.tgWatcher.Subscribe([]structs.UpdateType{structs.UpdateMessage})
go n.tgWatcher.Run(n.ctx)
for {
select {
case update := <-updateChan:
if update.Message.Text == "/getIP" {
if err := n.sendCurrentIP(); err != nil {
n.errChan <- fmt.Errorf("failed to reply current public IP: %w", err)
}
}
case <-n.ctx.Done():
n.tgWatcher.Unsubscribe(id)
return
}
}
}
func (n *Notifier) Run() {
go n.watchTG()
n.logger.Infof("Start watching for public IP changes, polling frequency is %v", n.frequency)
for {
select {
case <-time.After(n.frequency):
n.logger.Debug("Checking if current IP has changed")
newIP, err := n.ipGetter.GetCurrentPublicIP(n.ctx)
if err != nil {
n.errChan <- fmt.Errorf("failed to update public IP: %w", err)
continue
}
n.logger.Debugf("Got new public IP %s", newIP.String())
if !newIP.Equal(n.currentIP) {
n.logger.Debug("New public IP is different from previous IP")
n.logger.Warnf("Public IP has changed from %s to %s", n.currentIP.String(), newIP.String())
n.currentIP = newIP
if err := n.sendUpdatedIPMsg(); err != nil {
n.errChan <- err
}
} else {
n.logger.Debug("Public IP has not changed")
}
case <-n.ctx.Done():
n.logger.Info("Stopping notification daemon")
n.exitChan <- struct{}{}
return
}
}
}
func (n *Notifier) ErrChan() <-chan error {
return n.errChan
}
func (n *Notifier) Exit() <-chan struct{} {
return n.exitChan
}
func New(ctx context.Context, config *config.Config) *Notifier {
subCtx, cancel := context.WithCancel(ctx)
tgBot := bot.New(config.Telegram.Token)
return &Notifier{
ctx: subCtx,
cancel: cancel,
tgBot: tgBot,
tgChatID: config.Telegram.ChannelID,
timeGetter: time.Now,
ipGetter: ip.New(),
errChan: make(chan error, 10),
exitChan: make(chan struct{}, 1),
frequency: config.PollingFrequency,
tgWatcher: notifier.New(config.Telegram.Token),
logger: logger.L,
}
}