|
|
package lifx
import ( "context" "fmt" "git.aiterp.net/lucifer/new-server/models" "net" "sync" "time" )
type Driver struct { mu sync.Mutex bridges []*Bridge }
func (d *Driver) SearchBridge(ctx context.Context, address string, _ bool) ([]models.Bridge, error) { if address == "" { ifaces, err := net.Interfaces() if err != nil { return nil, err }
bridges := make([]models.Bridge, 0, len(ifaces)) for _, iface := range ifaces { if iface.Name == "lo" { continue }
addrs, err := iface.Addrs() if err != nil || len(addrs) == 0 { continue }
for _, addr := range addrs { bridges = append(bridges, models.Bridge{ ID: -1, Name: fmt.Sprintf("%s (%s)", iface.Name, addr), Driver: models.DTLIFX, Address: addr.String(), }) } }
return bridges, nil }
ctx2, cancel := context.WithCancel(ctx) defer cancel() _, err := createClient(ctx2, address, false) if err != nil { return nil, err }
return []models.Bridge{{ ID: 0, Name: "Your network card", Driver: models.DTLIFX, Address: address, Token: "", }}, nil }
func (d *Driver) SearchDevices(ctx context.Context, bridge models.Bridge, timeout time.Duration) ([]models.Device, error) { b, err := d.ensureBridge(ctx, bridge) if err != nil { return nil, err }
before, err := d.ListDevices(ctx, bridge) if err != nil { return nil, err }
err = b.StartSearch(ctx) if err != nil { return nil, err }
if timeout < time.Second/10 { timeout = time.Second / 10 }
select { case <-ctx.Done(): return nil, ctx.Err() case <-time.After(timeout): }
after, err := d.ListDevices(ctx, bridge) if err != nil { return nil, err }
intersection := make([]models.Device, 0, 4) for _, device := range after { found := false for _, device2 := range before { if device2.InternalID == device.InternalID { found = true break } }
if !found { intersection = append(intersection, device) } }
return intersection, nil }
func (d *Driver) ListDevices(ctx context.Context, bridge models.Bridge) ([]models.Device, error) { b, err := d.ensureBridge(ctx, bridge) if err != nil { return nil, err }
return b.Devices(), nil }
func (d *Driver) Publish(ctx context.Context, bridge models.Bridge, devices []models.Device) error { b, err := d.ensureBridge(ctx, bridge) if err != nil { return err }
b.Publish(devices)
return nil }
func (d *Driver) Run(ctx context.Context, bridge models.Bridge, ch chan<- models.Event) error { b, err := d.ensureBridge(ctx, bridge) if err != nil { return err }
return b.Run(ctx, bridge.Token == "debug") }
func (d *Driver) ensureBridge(ctx context.Context, info models.Bridge) (*Bridge, error) { d.mu.Lock() for _, bridge := range d.bridges { if bridge.ip == info.Address { d.mu.Unlock() return bridge, nil } } d.mu.Unlock()
bridge := &Bridge{ ip: info.Address, externalID: info.ID, }
// Try to create a short-lived client to make sure it works.
ctx2, cancel := context.WithCancel(ctx) defer cancel() _, err := createClient(ctx2, info.Address, info.Token == "debug") if err != nil { return nil, err }
// To avoid a potential duplicate, try looking for it again before inserting
d.mu.Lock() for _, bridge := range d.bridges { if bridge.ip == info.Address { d.mu.Unlock() return bridge, nil } } d.bridges = append(d.bridges, bridge) d.mu.Unlock()
return bridge, nil }
|