internal/physical/registration.go
raw ยท 1963 bytes
package physical
import (
"sort"
"strings"
"homekey.local/provisioner/drivers/sesame"
)
// Prepare connects unregistered scan results without claiming a lock. Repeated
// scans reuse our live preparations; a device seen on two adapters is dialed once.
// The manager lifetime, rather than the HTTP scan request, owns these links.
func (m *Manager) Prepare(targets []sesame.Target) {
m.enroll.Lock()
defer m.enroll.Unlock()
if m.ctx.Err() != nil {
return
}
m.mu.Lock()
defer m.mu.Unlock()
for _, target := range targets {
if target.Registered {
continue
}
uuid, err := sesame.NormalizeUUID(target.UUID)
if err != nil {
continue
}
target.UUID = uuid
id, err := identity(target)
if err != nil || m.records[id].ID != "" {
continue
}
if old := m.pending[id]; old != nil {
switch old.State().Phase {
case "failed", "disconnected":
old.Close()
default:
continue
}
}
m.pending[id] = sesame.PrepareRegistration(m.ctx, target, m.dial)
}
}
func (m *Manager) RegistrationConnections() []sesame.RegistrationState {
m.mu.RLock()
defer m.mu.RUnlock()
out := []sesame.RegistrationState{}
for _, p := range m.pending {
out = append(out, p.State())
}
sort.Slice(out, func(i, j int) bool {
return out[i].Target.Adapter+out[i].Target.UUID < out[j].Target.Adapter+out[j].Target.UUID
})
return out
}
// DisconnectRegistration releases a preparation owned by us, including a setup
// still in progress. Unknown external links remain the BlueZ route's concern.
func (m *Manager) DisconnectRegistration(adapter, address string) bool {
m.enroll.Lock()
defer m.enroll.Unlock()
m.mu.Lock()
var selected *sesame.RegistrationConnection
for id, p := range m.pending {
t := p.State().Target
if t.Adapter == adapter && strings.EqualFold(t.Address, address) {
selected = p
delete(m.pending, id)
break
}
}
m.mu.Unlock()
if selected == nil {
return false
}
selected.Close()
return true
}