package sesame import ( "context" "errors" "sort" "strings" "github.com/godbus/dbus/v5" ) // Connection is a BlueZ link, independent of local lock enrollment. type Connection struct { Adapter string `json:"adapter"` Address string `json:"address"` Name string `json:"name"` } func sesameDevice(p map[string]dbus.Variant) bool { if _, ok := advertised(p); ok { return true } uuids, _ := p["UUIDs"].Value().([]string) for _, uuid := range uuids { if strings.EqualFold(uuid, ServiceUUID) { return true } } return false } func connectedSesames(o objects) []Connection { out := []Connection{} for _, ifs := range o { p := ifs["org.bluez.Device1"] connected, _ := p["Connected"].Value().(bool) if !connected || !sesameDevice(p) { continue } adapter, _ := p["Adapter"].Value().(dbus.ObjectPath) parts := strings.Split(string(adapter), "/") out = append(out, Connection{parts[len(parts)-1], value(p, "Address"), value(p, "Alias")}) } sort.Slice(out, func(i, j int) bool { return out[i].Adapter+out[i].Address < out[j].Adapter+out[j].Address }) return out } // Connections reads current controller state without starting discovery. func Connections(ctx context.Context) ([]Connection, error) { c, err := dbus.ConnectSystemBus() if err != nil { return nil, err } defer c.Close() o, err := getObjects(ctx, c) if err != nil { return nil, err } return connectedSesames(o), nil } // Disconnect affects only the explicitly selected Sesame device, never its keys. func Disconnect(ctx context.Context, adapter, address string) error { c, err := dbus.ConnectSystemBus() if err != nil { return err } defer c.Close() o, err := getObjects(ctx, c) if err != nil { return err } for path, ifs := range o { p := ifs["org.bluez.Device1"] a, _ := p["Adapter"].Value().(dbus.ObjectPath) if string(a) != "/org/bluez/"+adapter || !strings.EqualFold(value(p, "Address"), address) || !sesameDevice(p) { continue } connected, _ := p["Connected"].Value().(bool) if !connected { return nil } return c.Object("org.bluez", path).CallWithContext(ctx, "org.bluez.Device1.Disconnect", 0).Err } return errors.New("Sesame device no longer found on this adapter; refresh connections") }