public-ip-tracker/tracker/bot/bot.go
Melora Hugues 3a1bb20a1f
All checks were successful
continuous-integration/drone/push Build is passing
Add monitoring of the current public IP
Ref #4

This commit adds an active monitoring of the current public IP. If a
change is detected, then a message is sent to the given Telegram
channel. Add a few tests for the main monitoring logic.
2023-01-28 14:29:39 +01:00

97 lines
2.3 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"
"github.com/ahugues/go-telegram-api/bot"
)
type Notifier struct {
ctx context.Context
cancel context.CancelFunc
tgBot bot.Bot
tgChatID int64
ipGetter ip.IPGetter
timeGetter func() time.Time
currentIP net.IP
frequency time.Duration
errChan chan error
changesChan chan net.IP
exitChan chan struct{}
}
func (n *Notifier) SendInitMessage() error {
publicIP, err := n.ipGetter.GetCurrentPublicIP(n.ctx)
if err != nil {
return fmt.Errorf("failed to get current public IP: %w", err)
}
n.currentIP = publicIP
currentTime := n.timeGetter()
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)
}
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) Run() {
for {
select {
case <-time.After(n.frequency):
newIP, err := n.ipGetter.GetCurrentPublicIP(n.ctx)
if err != nil {
n.errChan <- fmt.Errorf("failed to update public IP: %w", err)
continue
}
if !newIP.Equal(n.currentIP) {
n.currentIP = newIP
if err := n.sendUpdatedIPMsg(); err != nil {
n.errChan <- err
}
}
case <-n.ctx.Done():
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,
}
}