chultun/internal/budget/bus.go

113 lines
2.6 KiB
Go
Raw Normal View History

package budget
import (
"errors"
"strings"
"github.com/godbus/dbus/v5"
)
const api = "org.freedesktop.systemd1"
const noUnit = api + ".NoSuchUnit"
const noPID = "org.freedesktop.DBus.Error.UnixProcessIdUnknown"
type unit struct {
Name string
Description string
Load string
Active string
Sub string
Following string
Path dbus.ObjectPath
Job uint32
JobType string
JobPath dbus.ObjectPath
}
type unitState struct {
Active string
Group string
}
type unitCtl interface {
Units() ([]unit, error)
Group(string) (string, error)
Set(string, []property) error
Start(string, []property) error
State(string) (unitState, error)
Stop(string) error
}
type manager struct {
conn *dbus.Conn
obj dbus.BusObject
}
type auxiliary struct {
Name string
Properties []property
}
func connect() (*manager, error) {
conn, err := dbus.ConnectSessionBus()
if err != nil {
return nil, err
}
return &manager{conn: conn, obj: conn.Object(api, "/org/freedesktop/systemd1")}, nil
}
func busError(err error, name string) bool {
var e dbus.Error
return errors.As(err, &e) && e.Name == name
}
func (m *manager) Units() ([]unit, error) {
var units []unit
err := m.obj.Call(api+".Manager.ListUnits", 0).Store(&units)
return units, err
}
func (m *manager) object(name string) (dbus.BusObject, error) {
var path dbus.ObjectPath
if err := m.obj.Call(api+".Manager.GetUnit", 0, name).Store(&path); err != nil {
return nil, err
}
return m.conn.Object(api, path), nil
}
func (m *manager) Group(name string) (string, error) {
obj, err := m.object(name)
if err != nil {
return "", err
}
kind := name[strings.LastIndex(name, ".")+1:]
kind = strings.ToUpper(kind[:1]) + kind[1:]
var group string
err = obj.StoreProperty(api+"."+kind+".ControlGroup", &group)
return group, err
}
func (m *manager) Set(name string, values []property) error {
return m.obj.Call(api+".Manager.SetUnitProperties", 0, name, true, values).Err
}
func (m *manager) Start(name string, values []property) error {
return m.obj.Call(api+".Manager.StartTransientUnit", 0, name, "fail", values, []auxiliary{}).Err
}
func (m *manager) State(name string) (unitState, error) {
obj, err := m.object(name)
if err != nil {
return unitState{}, err
}
var state unitState
if err = obj.StoreProperty(api+".Unit.ActiveState", &state.Active); err != nil {
return unitState{}, err
}
err = obj.StoreProperty(api+".Scope.ControlGroup", &state.Group)
return state, err
}
func (m *manager) Stop(name string) error {
return m.obj.Call(api+".Manager.StopUnit", 0, name, "replace").Err
}