package chromecast import ( "context" "forge.cadoles.com/arcad/edge/pkg/module/cast" gcast "github.com/barnybug/go-cast" "github.com/pkg/errors" "gitlab.com/wpetit/goweb/logger" ) func init() { cast.Register(DeviceTypeChromecast, &Service{}) } type Service struct { } // Find implements cast.Service. func (s *Service) Find(ctx context.Context, deviceID string) (cast.Device, error) { ctx, cancel := context.WithCancel(ctx) defer cancel() results, err := s.scan(ctx) if err != nil { return nil, errors.WithStack(err) } for dev := range results { if dev.DeviceID() != deviceID { continue } return dev, nil } return nil, errors.WithStack(cast.ErrDeviceNotFound) } // NewClient implements cast.Service. func (*Service) NewClient(ctx context.Context, device cast.Device) (cast.Client, error) { client := gcast.NewClient(device.DeviceHost(), device.DevicePort()) if err := client.Connect(ctx); err != nil { return nil, errors.WithStack(err) } return &Client{client}, nil } // Scan implements cast.Service. func (s *Service) Scan(ctx context.Context) ([]cast.Device, error) { results, err := s.scan(ctx) if err != nil { return nil, errors.WithStack(err) } devices := make([]cast.Device, 0) for dev := range results { devices = append(devices, dev) } return devices, nil } func (*Service) scan(ctx context.Context) (chan cast.Device, error) { discovery := NewDiscovery(ctx) defer discovery.Stop() go func() { if err := discovery.Run(ctx, serviceDiscoveryPollingInterval); err != nil && !errors.Is(err, context.DeadlineExceeded) { logger.Error(ctx, "could not run chromecast discovery", logger.CapturedE(errors.WithStack(err))) } }() results := make(chan cast.Device) go func() { defer close(results) found := make(map[string]struct{}) LOOP: for { select { case c := <-discovery.Found(): dev := &Device{ Host: c.IP().To4(), Port: c.Port(), Name: c.Name(), UUID: c.Uuid(), } if _, exists := found[dev.UUID]; !exists { results <- dev found[dev.UUID] = struct{}{} } case <-ctx.Done(): break LOOP } } }() return results, nil } var _ cast.Service = &Service{}