diff --git a/cmd/gluetun/main.go b/cmd/gluetun/main.go index d5dfb5cd..39bcf938 100644 --- a/cmd/gluetun/main.go +++ b/cmd/gluetun/main.go @@ -208,6 +208,7 @@ func _main(background context.Context, args []string) int { restartOpenvpn := make(chan struct{}) restartUnbound := make(chan struct{}) + restartPublicIP := make(chan struct{}) openvpnDone := make(chan struct{}) unboundDone := make(chan struct{}) serverDone := make(chan struct{}) @@ -220,6 +221,9 @@ func _main(background context.Context, args []string) int { // wait for restartUnbound go unboundLooper.Run(ctx, restartUnbound, unboundDone) + publicIPLooper := publicip.NewLooper(client, logger, fileManager, allSettings.System.IPStatusFilepath, uid, gid) + go publicIPLooper.Run(ctx, restartPublicIP) + go func() { first := true var restartTickerContext context.Context @@ -237,7 +241,7 @@ func _main(background context.Context, args []string) int { restartTickerCancel() restartTickerContext, restartTickerCancel = context.WithCancel(ctx) go unboundLooper.RunRestartTicker(restartTickerContext, restartUnbound) - onConnected(allSettings, logger, fileManager, routingConf, defaultInterface, providerConf) + onConnected(allSettings, logger, routingConf, defaultInterface, providerConf, restartPublicIP) } } }() @@ -355,10 +359,10 @@ func trimEventualProgramPrefix(s string) string { } func onConnected(allSettings settings.Settings, - logger logging.Logger, fileManager files.FileManager, - routingConf routing.Routing, defaultInterface string, - providerConf provider.Provider, + logger logging.Logger, routingConf routing.Routing, defaultInterface string, + providerConf provider.Provider, restartPublicIP chan<- struct{}, ) { + restartPublicIP <- struct{}{} uid, gid := allSettings.System.UID, allSettings.System.GID if allSettings.OpenVPN.Provider.PortForwarding.Enabled { time.AfterFunc(5*time.Second, func() { @@ -372,22 +376,6 @@ func onConnected(allSettings settings.Settings, } else { logger.Info("Gateway VPN IP address: %s", vpnGatewayIP) } - time.AfterFunc(10*time.Second, func() { // wait for Unbound to start - TODO use signal channel - publicIP, err := publicip.NewIPGetter(network.NewClient(3 * time.Second)).Get() - if err != nil { - logger.Error(err) - } else { - logger.Info("Public IP address is %s", publicIP) - err = fileManager.WriteLinesToFile( - string(allSettings.System.IPStatusFilepath), - []string{publicIP.String()}, - files.Ownership(uid, gid), - files.Permissions(0400)) - if err != nil { - logger.Error(err) - } - } - }) } func setupPortForwarding(logger logging.Logger, providerConf provider.Provider, filepath models.Filepath, uid, gid int) { diff --git a/internal/publicip/loop.go b/internal/publicip/loop.go new file mode 100644 index 00000000..46e76dfc --- /dev/null +++ b/internal/publicip/loop.go @@ -0,0 +1,73 @@ +package publicip + +import ( + "context" + "time" + + "github.com/qdm12/golibs/files" + "github.com/qdm12/golibs/logging" + "github.com/qdm12/golibs/network" + "github.com/qdm12/private-internet-access-docker/internal/models" +) + +type Looper interface { + Run(ctx context.Context, restart <-chan struct{}) +} + +type looper struct { + getter IPGetter + logger logging.Logger + fileManager files.FileManager + ipStatusFilepath models.Filepath + uid int + gid int +} + +func NewLooper(client network.Client, logger logging.Logger, fileManager files.FileManager, + ipStatusFilepath models.Filepath, uid, gid int) Looper { + return &looper{ + getter: NewIPGetter(client), + logger: logger.WithPrefix("ip getter: "), + fileManager: fileManager, + ipStatusFilepath: ipStatusFilepath, + uid: uid, + gid: gid, + } +} + +func (l *looper) logAndWait(err error) { + l.logger.Error(err) + l.logger.Info("retrying in 5 seconds") + time.Sleep(5 * time.Second) +} + +func (l *looper) Run(ctx context.Context, restart <-chan struct{}) { + select { + case <-restart: + case <-ctx.Done(): + return + } + for { + ip, err := l.getter.Get() + if err != nil { + l.logAndWait(err) + continue + } + l.logger.Info("Public IP address is %s", ip) + err = l.fileManager.WriteLinesToFile( + string(l.ipStatusFilepath), + []string{ip.String()}, + files.Ownership(l.uid, l.gid), + files.Permissions(0600)) + if err != nil { + l.logAndWait(err) + continue + } + select { + case <-restart: // triggered restart + case <-ctx.Done(): + l.logger.Warn("context canceled: exiting loop") + return + } + } +}