Compare commits

..

No commits in common. "main" and "13-improve-messages" have entirely different histories.

9 changed files with 28 additions and 212 deletions

2
.gitignore vendored
View file

@ -16,7 +16,7 @@
*.out
# build directory
**/build
tracker/build
# Dependency directories (remove the comment below to include it)
# vendor/

View file

@ -10,7 +10,7 @@ FROM --platform=$TARGETPLATFORM alpine:latest
WORKDIR /root
COPY --from=builder go/src/git.faercol.me/public-ip-tracker/build/tracker ./
VOLUME [ "/config", "/output" ]
VOLUME [ "/config" ]
ENTRYPOINT [ "./tracker" ]
CMD [ "-config", "/config/config.json" ]

View file

@ -44,9 +44,6 @@ For now, the program is configured through a JSON configuration file. Here is a
"polling_frequency": 5,
"log": {
"level": "info"
},
"export": {
"mode": "native
}
}
```

View file

@ -1,17 +0,0 @@
services:
telegram_exporter:
container_name: telegram_exporter
image: git.faercol.me/notification/telegram-notifier:latest
environment:
- SOCK_PATH=/input/telegram.sock
volumes:
- './build/config/exporter:/config'
- './build/run:/input'
ip_tracker:
container_name: ip_tracker
image: git.faercol.me/faercol/public-ip-tracker:latest
# Volumes store your data between container upgrades
volumes:
- './build/config/tracker:/config'
- './build/run:/output'

View file

@ -10,8 +10,6 @@ import (
"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"
"git.faercol.me/faercol/public-ip-tracker/tracker/messager"
"git.faercol.me/faercol/public-ip-tracker/tracker/unixsender"
"github.com/ahugues/go-telegram-api/bot"
"github.com/ahugues/go-telegram-api/notifier"
"github.com/ahugues/go-telegram-api/structs"
@ -43,22 +41,10 @@ type Notifier struct {
currentIP net.IP
frequency time.Duration
errChan chan error
changesChan chan net.IP
exitChan chan struct{}
logger logrus.Logger
hostname string
sendMode config.ExportMode
sender messager.Sender
}
func (n *Notifier) sendMessage(msg string) error {
switch n.sendMode {
case config.ExportNative:
return n.tgBot.SendMessage(n.ctx, n.tgChatID, msg, structs.FormattingMarkdownV2)
case config.ExportUnix:
return n.sender.SendMessage(msg)
default:
return fmt.Errorf("invalid sending mode %v", n.sendMode)
}
}
func (n *Notifier) SendInitMessage() error {
@ -73,8 +59,7 @@ func (n *Notifier) SendInitMessage() error {
currentTime := n.timeGetter()
n.logger.Debug("Sending init message to Telegram")
initMsg := formatInitMsg(currentTime, publicIP, n.hostname)
if err := n.sendMessage(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")
@ -82,8 +67,7 @@ func (n *Notifier) SendInitMessage() error {
}
func (n *Notifier) sendUpdatedIPMsg() error {
updateMsg := formatUpdate(n.timeGetter(), n.currentIP, n.hostname)
if err := n.sendMessage(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
@ -91,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.sendMessage(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
@ -156,26 +140,10 @@ func (n *Notifier) Exit() <-chan struct{} {
return n.exitChan
}
func buildSender(ctx context.Context, conf *config.Config) (messager.Sender, error) {
switch conf.Export.Mode {
case config.ExportUnix:
logger.L.Infof("Building notifier in Unix mode")
return unixsender.New(ctx, conf)
default:
return nil, nil
}
}
func New(ctx context.Context, config *config.Config) (*Notifier, error) {
func New(ctx context.Context, config *config.Config) *Notifier {
subCtx, cancel := context.WithCancel(ctx)
tgBot := bot.New(config.Telegram.Token)
sender, err := buildSender(subCtx, config)
if err != nil {
cancel()
return nil, fmt.Errorf("failed to build message sender: %w", err)
}
return &Notifier{
ctx: subCtx,
cancel: cancel,
@ -189,7 +157,5 @@ func New(ctx context.Context, config *config.Config) (*Notifier, error) {
tgWatcher: notifier.New(config.Telegram.Token),
logger: logger.L,
hostname: config.Hostname,
sendMode: config.Export.Mode,
sender: sender,
}, nil
}
}

View file

@ -9,24 +9,6 @@ import (
"github.com/sirupsen/logrus"
)
type ExportMode int64
const (
ExportNative = iota
ExportUnix
)
func exportModeFromStr(val string) ExportMode {
switch val {
case "native":
return ExportNative
case "unix":
return ExportUnix
default:
return ExportNative
}
}
type TelegramConfig struct {
ChannelID int64 `json:"channel_id"`
Token string `json:"token"`
@ -40,30 +22,18 @@ type jsonLogConfig struct {
Level string `json:"level"`
}
type ExportConfig struct {
Mode ExportMode
UnixSock string
}
type jsonExportConfig struct {
Mode string `json:"mode"`
UnixSock string `json:"sock_path"`
}
type Config struct {
Telegram *TelegramConfig
PollingFrequency time.Duration
Hostname string
Log LogConfig
Export ExportConfig
Log *LogConfig
}
type jsonConfig struct {
Telegram *TelegramConfig `json:"telegram"`
PollingFrequency int64 `json:"polling_frequency"`
Hostname string `json:"hostname"`
Log jsonLogConfig `json:"log"`
Export jsonExportConfig `json:"export"`
Log *jsonLogConfig `json:"log"`
}
func parseLevel(lvlStr string) logrus.Level {
@ -84,17 +54,12 @@ func New(filepath string) (*Config, error) {
if err := json.Unmarshal(content, &jsonConf); err != nil {
return nil, fmt.Errorf("failed to parse config file: %w", err)
}
return &Config{
Telegram: jsonConf.Telegram,
PollingFrequency: time.Duration(jsonConf.PollingFrequency) * time.Second,
Hostname: jsonConf.Hostname,
Log: LogConfig{
Log: &LogConfig{
Level: parseLevel(jsonConf.Log.Level),
},
Export: ExportConfig{
UnixSock: jsonConf.Export.UnixSock,
Mode: exportModeFromStr(jsonConf.Export.Mode),
},
}, nil
}

View file

@ -48,10 +48,7 @@ func main() {
}
logger.L.Debug("Initializing notification bot")
notifBot, err := bot.New(mainCtx, conf)
if err != nil {
logger.L.Fatalf("Failed to create notification bot: %s", err.Error())
}
notifBot := bot.New(mainCtx, conf)
logger.L.Debug("Sending initialization message to Telegram")
if err := notifBot.SendInitMessage(); err != nil {

View file

@ -1,26 +0,0 @@
package messager
import (
"fmt"
"net"
"strings"
"time"
)
type Sender interface {
SendMessage(message string) error
}
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)
}

View file

@ -1,66 +0,0 @@
package unixsender
import (
"bytes"
"context"
"fmt"
"net"
"net/http"
"git.faercol.me/faercol/public-ip-tracker/tracker/config"
"git.faercol.me/faercol/public-ip-tracker/tracker/logger"
"github.com/sirupsen/logrus"
)
const method = http.MethodPost
const baseURL = "http://unix/"
type UnixSender struct {
logger *logrus.Logger
ctx context.Context
cancel context.CancelFunc
httpClt *http.Client
}
func (s *UnixSender) SendMessage(message string) error {
s.logger.Debug("Sending message to unix sock")
body := bytes.NewBufferString(message)
req, err := http.NewRequestWithContext(s.ctx, method, baseURL, body)
if err != nil {
return fmt.Errorf("failed to prepare request: %w", err)
}
resp, err := s.httpClt.Do(req)
if err != nil {
return fmt.Errorf("failed to run query: %w", err)
}
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("invalid returncode %d", resp.StatusCode)
}
return nil
}
func New(ctx context.Context, config *config.Config) (*UnixSender, error) {
subCtx, cancel := context.WithCancel(ctx)
logger.L.Infof("Creating Unix exporter to sock %q", config.Export.UnixSock)
httpClt := http.Client{
Transport: &http.Transport{
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
dialer := net.Dialer{}
return dialer.DialContext(ctx, "unix", config.Export.UnixSock)
},
},
}
return &UnixSender{
ctx: subCtx,
cancel: cancel,
httpClt: &httpClt,
logger: &logger.L,
}, nil
}