Skip to content

Commit

Permalink
refactor(linux,dbusx): ♻️ better error handling of session bus path r…
Browse files Browse the repository at this point in the history
…etrieval
  • Loading branch information
joshuar committed Jun 13, 2024
1 parent aaf039d commit aae9e81
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 35 deletions.
11 changes: 9 additions & 2 deletions internal/linux/power/idle.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ func newIdleSensor(ctx context.Context) (*idleSensor, error) {
}

//nolint:cyclop,exhaustruct
//revive:disable:function-length
func IdleUpdater(ctx context.Context) chan sensor.Details {
sensorCh := make(chan sensor.Details)

Expand All @@ -100,13 +101,19 @@ func IdleUpdater(ctx context.Context) chan sensor.Details {
return sensorCh
}

sessionPath := dbusx.GetSessionPath(ctx)
sessionPath, err := dbusx.GetSessionPath(ctx)
if err != nil {
log.Debug().Err(err).Msg("Cannot create idle sensor.")
close(sensorCh)

return sensorCh
}

events, err := dbusx.WatchBus(ctx, &dbusx.Watch{
Bus: dbusx.SystemBus,
Names: []string{sessionIdleProp, sessionIdleTimeProp},
Interface: sessionInterface,
Path: string(sessionPath),
Path: sessionPath,
})
if err != nil {
log.Debug().Err(err).
Expand Down
23 changes: 16 additions & 7 deletions internal/linux/power/laptop.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package power

import (
"context"
"fmt"
"path/filepath"
"slices"

Expand Down Expand Up @@ -85,17 +86,17 @@ func newLaptopEvent(prop string, state bool) *laptopSensor {
return sensorEvent
}

type laptopWorker struct{}
type laptopWorker struct {
sessionPath string
}

//nolint:exhaustruct
func (w *laptopWorker) Setup(ctx context.Context) *dbusx.Watch {
sessionPath := dbusx.GetSessionPath(ctx)

func (w *laptopWorker) Setup(_ context.Context) *dbusx.Watch {
return &dbusx.Watch{
Bus: dbusx.SystemBus,
Names: []string{dbusx.PropChangedSignal},
Interface: managerInterface,
Path: string(sessionPath),
Path: w.sessionPath,
}
}

Expand Down Expand Up @@ -160,16 +161,24 @@ func (w *laptopWorker) Sensors(ctx context.Context) ([]sensor.Details, error) {
return sensors, nil
}

func NewLaptopWorker(_ context.Context) (*linux.SensorWorker, error) {
func NewLaptopWorker(ctx context.Context) (*linux.SensorWorker, error) {
// Don't run this worker if we are not running on a laptop.
if linux.Chassis() != "laptop" {
return nil, linux.ErrUnsupportedHardware
}

// If we can't get a session path, we can't run.
sessionPath, err := dbusx.GetSessionPath(ctx)
if err != nil {
return nil, fmt.Errorf("could not create laptop worker: %w", err)
}

return &linux.SensorWorker{
WorkerName: "Laptop State Sensors",
WorkerDesc: "Sensors for laptop lid, dock and external power states.",
Value: &laptopWorker{},
Value: &laptopWorker{
sessionPath: sessionPath,
},
},
nil
}
10 changes: 8 additions & 2 deletions internal/linux/power/powerControl.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,19 @@ var commands = map[string]commandConfig{
func NewPowerControl(ctx context.Context) []*mqtthass.ButtonEntity {
entities := make([]*mqtthass.ButtonEntity, 0, len(commands))
device := linux.MQTTDevice()
sessionPath := dbusx.GetSessionPath(ctx)

sessionPath, err := dbusx.GetSessionPath(ctx)
if err != nil {
log.Warn().Err(err).Msg("Cannot create entity.")

return nil
}

for cmdName, cmdInfo := range commands {
var callback func(p *paho.Publish)
if cmdInfo.path == "" {
callback = func(_ *paho.Publish) {
err := dbusx.Call(ctx, dbusx.SystemBus, string(sessionPath), loginBaseInterface, cmdInfo.method)
err := dbusx.Call(ctx, dbusx.SystemBus, sessionPath, loginBaseInterface, cmdInfo.method)
if err != nil {
log.Warn().Err(err).Msgf("Could not %s session.", cmdInfo.name)
}
Expand Down
22 changes: 15 additions & 7 deletions internal/linux/power/screenLock.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package power

import (
"context"
"fmt"

"github.com/rs/zerolog/log"

Expand Down Expand Up @@ -45,17 +46,17 @@ func newScreenlockEvent(value bool) *screenlockSensor {
}
}

type screenLockWorker struct{}
type screenLockWorker struct {
sessionPath string
}

//nolint:exhaustruct
func (w *screenLockWorker) Setup(ctx context.Context) *dbusx.Watch {
sessionPath := dbusx.GetSessionPath(ctx)

func (w *screenLockWorker) Setup(_ context.Context) *dbusx.Watch {
return &dbusx.Watch{
Bus: dbusx.SystemBus,
Names: []string{sessionLockSignal, sessionUnlockSignal, sessionLockedProp},
Interface: sessionInterface,
Path: string(sessionPath),
Path: w.sessionPath,
}
}

Expand Down Expand Up @@ -100,11 +101,18 @@ func (w *screenLockWorker) Sensors(_ context.Context) ([]sensor.Details, error)
return nil, linux.ErrUnimplemented
}

func NewScreenLockWorker(_ context.Context) (*linux.SensorWorker, error) {
func NewScreenLockWorker(ctx context.Context) (*linux.SensorWorker, error) {
sessionPath, err := dbusx.GetSessionPath(ctx)
if err != nil {
return nil, fmt.Errorf("could not create screen lock worker: %w", err)
}

return &linux.SensorWorker{
WorkerName: "Screen Lock Sensor",
WorkerDesc: "Sensor to track whether the screen is currently locked.",
Value: &screenLockWorker{},
Value: &screenLockWorker{
sessionPath: sessionPath,
},
},
nil
}
30 changes: 18 additions & 12 deletions internal/linux/system/dbusCommand.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"encoding/json"

"github.com/eclipse/paho.golang/paho"
"github.com/godbus/dbus/v5"
mqttapi "github.com/joshuar/go-hass-anything/v9/pkg/mqtt"
"github.com/rs/zerolog/log"

Expand All @@ -22,12 +21,12 @@ const (
)

type dbusCommandMsg struct {
Bus string `json:"bus"`
Destination string `json:"destination"`
Path dbus.ObjectPath `json:"path"`
Method string `json:"method"`
Args []any `json:"args"`
UseSessionPath bool `json:"use_session_path"`
Bus string `json:"bus"`
Destination string `json:"destination"`
Path string `json:"path"`
Method string `json:"method"`
Args []any `json:"args"`
UseSessionPath bool `json:"use_session_path"`
}

func NewDBusCommandSubscription(ctx context.Context) *mqttapi.Subscription {
Expand All @@ -36,13 +35,20 @@ func NewDBusCommandSubscription(ctx context.Context) *mqttapi.Subscription {
var dbusMsg dbusCommandMsg

if err := json.Unmarshal(p.Payload, &dbusMsg); err != nil {
log.Warn().Err(err).Msg("could not unmarshal dbus MQTT message")
log.Warn().Err(err).Msg("Could not unmarshal dbus MQTT message")

return
}

if dbusMsg.UseSessionPath {
dbusMsg.Path = dbusx.GetSessionPath(ctx)
var err error

dbusMsg.Path, err = dbusx.GetSessionPath(ctx)
if err != nil {
log.Warn().Err(err).Msg("Could not determine session path.")

return
}
}

dbusType, ok := dbusx.DbusTypeMap[dbusMsg.Bus]
Expand All @@ -55,16 +61,16 @@ func NewDBusCommandSubscription(ctx context.Context) *mqttapi.Subscription {
log.Info().
Str("bus", dbusMsg.Bus).
Str("destination", dbusMsg.Destination).
Str("path", string(dbusMsg.Path)).
Str("path", dbusMsg.Path).
Str("method", dbusMsg.Method).
Msg("Dispatching D-Bus command to MQTT.")

err := dbusx.Call(ctx, dbusType, string(dbusMsg.Path), dbusMsg.Destination, dbusMsg.Method, dbusMsg.Args...)
err := dbusx.Call(ctx, dbusType, dbusMsg.Path, dbusMsg.Destination, dbusMsg.Method, dbusMsg.Args...)
if err != nil {
log.Warn().Err(err).
Str("bus", dbusMsg.Bus).
Str("destination", dbusMsg.Destination).
Str("path", string(dbusMsg.Path)).
Str("path", dbusMsg.Path).
Str("method", dbusMsg.Method).
Msg("Error dispatching D-Bus command.")
}
Expand Down
11 changes: 6 additions & 5 deletions pkg/linux/dbusx/dbus.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ var (
ErrNotValChanged = errors.New("signal contents do not appear to represent a value change")
ErrParseNewVal = errors.New("could not parse new value")
ErrParseOldVal = errors.New("could not parse old value")
ErrNoSessionPath = errors.New("could not determine session path")
)

var DbusTypeMap = map[string]dbusType{
Expand Down Expand Up @@ -317,26 +318,26 @@ func WatchBus(ctx context.Context, conditions *Watch) (chan Trigger, error) {
return outCh, nil
}

func GetSessionPath(ctx context.Context) dbus.ObjectPath {
func GetSessionPath(ctx context.Context) (string, error) {
usr, err := user.Current()
if err != nil {
return ""
return "", fmt.Errorf("unable to determine user: %w", err)
}

sessions, err := GetData[[][]any](ctx, SystemBus, loginBasePath, loginBaseInterface, listSessionsMethod)
if err != nil {
return ""
return "", fmt.Errorf("unable to retrieve session path: %w", err)
}

for _, s := range sessions {
if thisUser, ok := s[2].(string); ok && thisUser == usr.Username {
if p, ok := s[4].(dbus.ObjectPath); ok {
return p
return string(p), nil
}
}
}

return ""
return "", ErrNoSessionPath
}

// ParsePropertiesChanged treats the given signal body as matching the canonical
Expand Down

0 comments on commit aae9e81

Please sign in to comment.