From 296af1bdcda681286796ca955d476d59668bfef2 Mon Sep 17 00:00:00 2001 From: Gabe Cook Date: Mon, 14 Aug 2023 23:23:04 -0500 Subject: [PATCH] feat: Add initial connection retry on fail --- cmd/cmd.go | 17 +--------- internal/config/config.go | 1 + internal/config/network.go | 7 ++-- internal/device/dns.go | 66 ++++++++++++++++++++++++++++++++++++++ internal/device/watch.go | 18 +++++++++-- 5 files changed, 88 insertions(+), 21 deletions(-) create mode 100644 internal/device/dns.go diff --git a/cmd/cmd.go b/cmd/cmd.go index 5cd7ddf..aaa99fd 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -3,7 +3,6 @@ package cmd import ( "context" "log/slog" - "net" "os" "os/signal" "sync" @@ -12,8 +11,6 @@ import ( "github.com/gabe565/sponsorblockcast/internal/config" "github.com/gabe565/sponsorblockcast/internal/device" "github.com/spf13/cobra" - "github.com/spf13/viper" - castdns "github.com/vishen/go-chromecast/dns" ) func NewCommand() *cobra.Command { @@ -38,19 +35,7 @@ func run(cmd *cobra.Command, args []string) (err error) { ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT) defer cancel() - var iface *net.Interface - interfaceName := viper.GetString(config.InterfaceKey) - if interfaceName != "" { - iface, err = net.InterfaceByName(interfaceName) - if err != nil { - return err - } - slog.Info("Searching for devices...", "interface", interfaceName) - } else { - slog.Info("Searching for devices...") - } - - entries, err := castdns.DiscoverCastDNSEntries(ctx, iface) + entries, err := device.DiscoverCastDNSEntries(ctx) if err != nil { return err } diff --git a/internal/config/config.go b/internal/config/config.go index bf41575..2f7e03f 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -5,5 +5,6 @@ import "github.com/spf13/viper" func Load() { PausedIntervalValue = viper.GetDuration(PausedIntervalKey) PlayingIntervalValue = viper.GetDuration(PlayingIntervalKey) + InterfaceValue = viper.GetString(InterfaceKey) CategoriesValue = viper.GetStringSlice(CategoriesKey) } diff --git a/internal/config/network.go b/internal/config/network.go index d28d1d8..518d3cc 100644 --- a/internal/config/network.go +++ b/internal/config/network.go @@ -5,10 +5,13 @@ import ( "github.com/spf13/viper" ) -var InterfaceKey = "interface" +var ( + InterfaceKey = "interface" + InterfaceValue string +) func Interface(cmd *cobra.Command) { - cmd.PersistentFlags().StringP(InterfaceKey, "i", "", "Network interface to use for multicast dns discovery") + cmd.PersistentFlags().StringP(InterfaceKey, "i", InterfaceValue, "Network interface to use for multicast dns discovery") if err := viper.BindPFlag(InterfaceKey, cmd.PersistentFlags().Lookup(InterfaceKey)); err != nil { panic(err) } diff --git a/internal/device/dns.go b/internal/device/dns.go new file mode 100644 index 0000000..f6c993f --- /dev/null +++ b/internal/device/dns.go @@ -0,0 +1,66 @@ +package device + +import ( + "context" + "errors" + "fmt" + "log/slog" + "net" + "time" + + "github.com/gabe565/sponsorblockcast/internal/config" + castdns "github.com/vishen/go-chromecast/dns" +) + +var ErrDeviceNotFound = errors.New("device not found") + +func DiscoverCastDNSEntryByUuid(ctx context.Context, uuid string) (castdns.CastEntry, error) { + var iface *net.Interface + if config.InterfaceValue != "" { + var err error + iface, err = net.InterfaceByName(config.InterfaceValue) + if err != nil { + return castdns.CastEntry{}, err + } + } + + ctx, cancel := context.WithTimeout(ctx, 5*time.Second) + defer cancel() + + entries, err := castdns.DiscoverCastDNSEntries(ctx, iface) + if err != nil { + return castdns.CastEntry{}, err + } + + for { + select { + case <-ctx.Done(): + return castdns.CastEntry{}, fmt.Errorf("%w: %s", ErrDeviceNotFound, uuid) + case entry := <-entries: + if entry.UUID == uuid { + return entry, nil + } + } + } +} + +func DiscoverCastDNSEntries(ctx context.Context) (<-chan castdns.CastEntry, error) { + var iface *net.Interface + if config.InterfaceValue != "" { + var err error + iface, err = net.InterfaceByName(config.InterfaceValue) + if err != nil { + return nil, err + } + slog.Info("Searching for devices...", "interface", config.InterfaceValue) + } else { + slog.Info("Searching for devices...") + } + + entries, err := castdns.DiscoverCastDNSEntries(ctx, iface) + if err != nil { + return nil, err + } + + return entries, nil +} diff --git a/internal/device/watch.go b/internal/device/watch.go index c148a87..c396ec5 100644 --- a/internal/device/watch.go +++ b/internal/device/watch.go @@ -28,9 +28,21 @@ func Watch(ctx context.Context, entry castdns.CastEntry) { app := application.NewApplication() - if err := app.Start(entry.GetAddr(), entry.GetPort()); err != nil { - logger.Warn("Failed to start application", "error", err.Error()) - return + tries := 0 + for { + if err := app.Start(entry.GetAddr(), entry.GetPort()); err == nil { + break + } else { + if tries == 0 { + logger.Warn("Failed to connect to device. Retrying") + } + tries += 1 + entry, err = DiscoverCastDNSEntryByUuid(ctx, entry.UUID) + if err != nil && tries >= 10 { + logger.Warn("Failed to start application", "error", err.Error()) + return + } + } } defer func() { _ = app.Close(false)