Melora Hugues
51bc7cb3a0
All checks were successful
continuous-integration/drone/push Build is passing
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.
146 lines
4 KiB
Go
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,
|
|
}
|
|
}
|