joshuar-go-hass-agent/internal/linux/system/dbusCommand.go

96 lines
2.5 KiB
Go

// Copyright (c) 2024 Joshua Rich <joshua.rich@gmail.com>
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
package system
import (
"context"
"encoding/json"
"log/slog"
"github.com/eclipse/paho.golang/paho"
mqtthass "github.com/joshuar/go-hass-anything/v11/pkg/hass"
mqttapi "github.com/joshuar/go-hass-anything/v11/pkg/mqtt"
"github.com/joshuar/go-hass-agent/internal/linux"
"github.com/joshuar/go-hass-agent/internal/logging"
"github.com/joshuar/go-hass-agent/pkg/linux/dbusx"
)
type dbusCommandMsg struct {
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, device *mqtthass.Device) (*mqttapi.Subscription, error) {
logger := logging.FromContext(ctx).With(slog.String("controller", "dbus_command"))
systemBus, ok := linux.CtxGetSystemBus(ctx)
if !ok {
return nil, linux.ErrNoSystemBus
}
sessionBus, ok := linux.CtxGetSessionBus(ctx)
if !ok {
return nil, linux.ErrNoSessionBus
}
busMap := map[string]*dbusx.Bus{"session": sessionBus, "system": systemBus}
return &mqttapi.Subscription{
Callback: func(packet *paho.Publish) {
var (
dbusMsg dbusCommandMsg
err error
)
logger = logger.With(
slog.String("bus", dbusMsg.Bus),
slog.String("destination", dbusMsg.Destination),
slog.String("path", dbusMsg.Path),
slog.String("method", dbusMsg.Method),
)
// Unmarshal the request.
if err = json.Unmarshal(packet.Payload, &dbusMsg); err != nil {
logger.Error("Could not unmarshal D-Bus MQTT message.", slog.Any("error", err))
return
}
// Check which bus type was requested.
bus, ok := busMap[dbusMsg.Bus]
if !ok {
logger.Error("Unsupported D-Bus type.")
return
}
// Fetch the session path if requested.
if dbusMsg.UseSessionPath {
dbusMsg.Path, err = busMap["session"].GetSessionPath()
if err != nil {
logger.Error("Could not determine session path.", slog.Any("error", err))
return
}
}
logger.Info("Dispatching D-Bus command.")
// Call the method.
err = dbusx.NewMethod(bus, dbusMsg.Destination, dbusMsg.Path, dbusMsg.Method).Call(ctx, dbusMsg.Args...)
if err != nil {
logger.Warn("Error dispatching D-Bus command.", slog.Any("error", err))
}
},
Topic: "gohassagent/" + device.Name + "/dbuscommand",
},
nil
}