Cleanup portal controller

This commit is contained in:
Unrud 2025-03-18 09:18:16 +01:00
parent 16dc47b570
commit 5771f44b0e

View file

@ -55,7 +55,7 @@ const (
type portalController struct { type portalController struct {
bus *dbus.Conn bus *dbus.Conn
remoteDesktop dbus.BusObject portalDesktop dbus.BusObject
sessionHandle dbus.ObjectPath sessionHandle dbus.ObjectPath
} }
@ -82,15 +82,21 @@ func InitPortalController() (Controller, error) {
if err != nil { if err != nil {
return nil, &UnsupportedPlatformError{err} return nil, &UnsupportedPlatformError{err}
} }
remoteDesktop := bus.Object("org.freedesktop.portal.Desktop", portalDesktop := bus.Object("org.freedesktop.portal.Desktop",
"/org/freedesktop/portal/desktop") "/org/freedesktop/portal/desktop")
version, err := remoteDesktop.GetProperty( remoteDesktopVersionV, err := portalDesktop.GetProperty(
"org.freedesktop.portal.RemoteDesktop.version") "org.freedesktop.portal.RemoteDesktop.version")
if err != nil { if err != nil {
return nil, &UnsupportedPlatformError{err} return nil, &UnsupportedPlatformError{
fmt.Errorf("getting 'version' failed: %w", err)}
}
remoteDesktopVersion, ok := remoteDesktopVersionV.Value().(uint32)
if !ok {
return nil, &UnsupportedPlatformError{
errors.New("unexpected 'version' type")}
} }
restoreTokenStore, err := func() (*secretStore, error) { restoreTokenStore, err := func() (*secretStore, error) {
if version.Value().(uint32) < 2 { if remoteDesktopVersion < 2 {
return nil, nil return nil, nil
} }
cacheDirectory, err := os.UserCacheDir() cacheDirectory, err := os.UserCacheDir()
@ -110,92 +116,74 @@ func InitPortalController() (Controller, error) {
if err != nil { if err != nil {
log.Printf("Skipping restore token: %v", err) log.Printf("Skipping restore token: %v", err)
} }
availableDeviceTypesV, err := remoteDesktop.GetProperty( availableDeviceTypesV, err := portalDesktop.GetProperty(
"org.freedesktop.portal.RemoteDesktop.AvailableDeviceTypes") "org.freedesktop.portal.RemoteDesktop.AvailableDeviceTypes")
if err != nil { if err != nil {
return nil, &UnsupportedPlatformError{err} return nil, &UnsupportedPlatformError{
fmt.Errorf("getting 'AvailableDeviceTypes' failed: %w", err)}
} }
availableDeviceTypes, ok := availableDeviceTypesV.Value().(uint32) availableDeviceTypes, ok := availableDeviceTypesV.Value().(uint32)
if !ok { if !ok {
return nil, &UnsupportedPlatformError{ return nil, &UnsupportedPlatformError{
errors.New("unexpected 'AvailableDeviceTypes' return type")} errors.New("unexpected 'AvailableDeviceTypes' return type")}
} }
if availableDeviceTypes&deviceKeyboard == 0 && if availableDeviceTypes&deviceKeyboard == 0 ||
availableDeviceTypes&devicePointer == 0 { availableDeviceTypes&devicePointer == 0 {
return nil, &UnsupportedPlatformError{ return nil, &UnsupportedPlatformError{
errors.New("keyboard and pointer source type not supported")} errors.New("keyboard or pointer source type not supported")}
} }
if availableDeviceTypes&deviceKeyboard == 0 { createSessionResults, err := checkResponse(getResponse(bus, portalDesktop,
return nil, &UnsupportedPlatformError{ "org.freedesktop.portal.RemoteDesktop.CreateSession", 0,
errors.New("keyboard source type not supported")} map[string]dbus.Variant{"session_handle_token": dbus.MakeVariant("t")},
} ))
if availableDeviceTypes&devicePointer == 0 {
return nil, &UnsupportedPlatformError{
errors.New("pointer source type not supported")}
}
inVardict := make(map[string]dbus.Variant)
inVardict["session_handle_token"] = dbus.MakeVariant("t")
result, outVardict, err := getResponse(bus, remoteDesktop,
"org.freedesktop.portal.RemoteDesktop.CreateSession", 0, inVardict)
if err != nil { if err != nil {
return nil, &UnsupportedPlatformError{err}
}
if result != 0 {
return nil, &UnsupportedPlatformError{ return nil, &UnsupportedPlatformError{
fmt.Errorf("Calling 'CreateSession' failed (%v)", result)} fmt.Errorf("calling 'CreateSession' failed: %w", err)}
} }
sessionHandleV, ok := outVardict["session_handle"] sessionHandleString, ok := createSessionResults["session_handle"].Value().(string)
if !ok {
return nil, &UnsupportedPlatformError{
errors.New("'session_handle' missing from 'CreateSession' return value")}
}
sessionHandleS, ok := sessionHandleV.Value().(string)
if !ok { if !ok {
return nil, &UnsupportedPlatformError{ return nil, &UnsupportedPlatformError{
errors.New("unexpected 'session_handle' type in 'CreateSession' return value")} errors.New("unexpected 'session_handle' type in 'CreateSession' return value")}
} }
sessionHandle := dbus.ObjectPath(sessionHandleS) sessionHandle := dbus.ObjectPath(sessionHandleString)
inVardict = make(map[string]dbus.Variant) selectDevicesOptions := map[string]dbus.Variant{
inVardict["types"] = dbus.MakeVariant(deviceKeyboard | devicePointer) "types": dbus.MakeVariant(deviceKeyboard | devicePointer),
}
if restoreTokenStore != nil { if restoreTokenStore != nil {
if restoreToken, err := restoreTokenStore.Load(); err != nil { if restoreToken, err := restoreTokenStore.Load(); err != nil {
if !errors.Is(err, os.ErrNotExist) { if !errors.Is(err, os.ErrNotExist) {
log.Printf("Failed to load restore token: %v", err) log.Printf("Failed to load restore token: %v", err)
} }
} else if len(restoreToken) > 0 { } else if len(restoreToken) > 0 {
inVardict["restore_token"] = dbus.MakeVariant(string(restoreToken)) selectDevicesOptions["restore_token"] = dbus.MakeVariant(string(restoreToken))
} }
inVardict["persist_mode"] = dbus.MakeVariant(untilRevoked) selectDevicesOptions["persist_mode"] = dbus.MakeVariant(untilRevoked)
} }
result, outVardict, err = getResponse(bus, remoteDesktop, _, err = checkResponse(getResponse(bus, portalDesktop,
"org.freedesktop.portal.RemoteDesktop.SelectDevices", 0, sessionHandle, inVardict) "org.freedesktop.portal.RemoteDesktop.SelectDevices", 0,
sessionHandle, selectDevicesOptions,
))
if err != nil { if err != nil {
return nil, &UnsupportedPlatformError{err}
}
if result != 0 {
return nil, &UnsupportedPlatformError{ return nil, &UnsupportedPlatformError{
fmt.Errorf("Calling 'SelectDevices' failed (%v)", result)} fmt.Errorf("calling 'SelectDevices' failed: %w", err)}
} }
inVardict = make(map[string]dbus.Variant) startResponseStatus, startResults, err := getResponse(bus, portalDesktop,
result, outVardict, err = getResponse(bus, remoteDesktop, "org.freedesktop.portal.RemoteDesktop.Start", 0,
"org.freedesktop.portal.RemoteDesktop.Start", 0, sessionHandle, "", inVardict) sessionHandle, "", map[string]dbus.Variant{},
)
if err != nil { if err != nil {
return nil, &UnsupportedPlatformError{err} return nil, &UnsupportedPlatformError{
fmt.Errorf("calling 'Start' failed: %w", err)}
} }
if result != 0 { if startResponseStatus != 0 {
return nil, errors.New("keyboard or pointer access denied") return nil, errors.New("keyboard or pointer access denied")
} }
if restoreToken, _ := outVardict["restore_token"].Value().(string); restoreTokenStore != nil { if restoreToken, _ := startResults["restore_token"].Value().(string); restoreTokenStore != nil {
if err := restoreTokenStore.Store([]byte(restoreToken)); err != nil { if err := restoreTokenStore.Store([]byte(restoreToken)); err != nil {
log.Printf("Failed to store restore token: %v", err) log.Printf("Failed to store restore token: %v", err)
} }
} }
devicesV, ok := outVardict["devices"] devices, ok := startResults["devices"].Value().(uint32)
if !ok {
return nil, &UnsupportedPlatformError{
errors.New("'devices' missing from 'Start' return value")}
}
devices, ok := devicesV.Value().(uint32)
if !ok { if !ok {
return nil, &UnsupportedPlatformError{ return nil, &UnsupportedPlatformError{
errors.New("unexpected 'devices' type in 'Start' return value")} errors.New("unexpected 'devices' type in 'Start' return value")}
@ -204,7 +192,7 @@ func InitPortalController() (Controller, error) {
return nil, errors.New("keyboard or pointer access denied") return nil, errors.New("keyboard or pointer access denied")
} }
cleanupBus = false cleanupBus = false
return &portalController{bus: bus, remoteDesktop: remoteDesktop, return &portalController{bus: bus, portalDesktop: portalDesktop,
sessionHandle: sessionHandle}, nil sessionHandle: sessionHandle}, nil
} }
@ -217,14 +205,11 @@ func retrieveSecret(bus *dbus.Conn) ([]byte, error) {
} }
defer secretReader.Close() defer secretReader.Close()
defer secretWriter.Close() defer secretWriter.Close()
if result, _, err := getResponse(bus, portalDesktop, if _, err := checkResponse(getResponse(bus, portalDesktop,
"org.freedesktop.portal.Secret.RetrieveSecret", 0, "org.freedesktop.portal.Secret.RetrieveSecret", 0,
dbus.UnixFD(secretWriter.Fd()), dbus.UnixFD(secretWriter.Fd()), map[string]dbus.Variant{},
map[string]dbus.Variant{}, )); err != nil {
); err != nil { return nil, fmt.Errorf("calling 'RetrieveSecret' failed: %w", err)
return nil, err
} else if result != 0 {
return nil, fmt.Errorf("calling 'RetrieveSecret' failed (%v)", result)
} }
if err := secretWriter.Close(); err != nil { if err := secretWriter.Close(); err != nil {
return nil, err return nil, err
@ -299,32 +284,39 @@ func getResponse(bus *dbus.Conn, object dbus.BusObject, method string,
s := <-ch s := <-ch
if s.Path == requestPath && s.Name == "org.freedesktop.portal.Request.Response" { if s.Path == requestPath && s.Name == "org.freedesktop.portal.Request.Response" {
if len(s.Body) != 2 { if len(s.Body) != 2 {
return 0, nil, errors.New("unexpected 'Response' return length") return 0, nil, fmt.Errorf("unexpected 'Response' return length (%d)", len(s.Body))
} }
result, ok := s.Body[0].(uint32) responseStatus, ok := s.Body[0].(uint32)
if !ok { if !ok {
return 0, nil, errors.New("unexpected 'Response' return type") return 0, nil, errors.New("unexpected 'Response' return type")
} }
outVardict, ok := s.Body[1].(map[string]dbus.Variant) results, ok := s.Body[1].(map[string]dbus.Variant)
if !ok { if !ok {
return 0, nil, errors.New("unexpected 'Response' return type") return 0, nil, errors.New("unexpected 'Response' return type")
} }
return result, outVardict, nil return responseStatus, results, nil
} }
} }
} }
func checkResponse(responseStatus uint32, results map[string]dbus.Variant, err error) (map[string]dbus.Variant, error) {
if err == nil && responseStatus != 0 {
err = fmt.Errorf("unexpected 'Response' status (%d)", responseStatus)
}
return results, err
}
func (p *portalController) Close() error { func (p *portalController) Close() error {
return p.bus.Close() return p.bus.Close()
} }
func (p *portalController) keyboardKeys(keys []Keysym) error { func (p *portalController) keyboardKeys(keys []Keysym) error {
inVardict := make(map[string]dbus.Variant)
for _, keysym := range keys { for _, keysym := range keys {
for _, state := range [...]uint32{btnPressed, btnReleased} { for _, state := range [...]uint32{btnPressed, btnReleased} {
if err := p.remoteDesktop.Call( if err := p.portalDesktop.Call(
"org.freedesktop.portal.RemoteDesktop.NotifyKeyboardKeysym", "org.freedesktop.portal.RemoteDesktop.NotifyKeyboardKeysym", 0,
0, p.sessionHandle, inVardict, keysym, state).Store(); err != nil { p.sessionHandle, map[string]dbus.Variant{}, keysym, state,
).Store(); err != nil {
return err return err
} }
} }
@ -369,28 +361,27 @@ func (p *portalController) PointerButton(button PointerButton, press bool) error
if press { if press {
state = btnPressed state = btnPressed
} }
inVardict := make(map[string]dbus.Variant) if err := p.portalDesktop.Call("org.freedesktop.portal.RemoteDesktop.NotifyPointerButton", 0,
if err := p.remoteDesktop.Call("org.freedesktop.portal.RemoteDesktop.NotifyPointerButton", p.sessionHandle, map[string]dbus.Variant{}, btn, state,
0, p.sessionHandle, inVardict, btn, state).Store(); err != nil { ).Store(); err != nil {
return err return err
} }
return nil return nil
} }
func (p *portalController) PointerMove(deltaX, deltaY int) error { func (p *portalController) PointerMove(deltaX, deltaY int) error {
inVardict := make(map[string]dbus.Variant) if err := p.portalDesktop.Call("org.freedesktop.portal.RemoteDesktop.NotifyPointerMotion", 0,
if err := p.remoteDesktop.Call("org.freedesktop.portal.RemoteDesktop.NotifyPointerMotion", p.sessionHandle, map[string]dbus.Variant{}, float64(deltaX), float64(deltaY),
0, p.sessionHandle, inVardict, float64(deltaX), float64(deltaY)).Store(); err != nil { ).Store(); err != nil {
return err return err
} }
return nil return nil
} }
func (p *portalController) PointerScroll(deltaHorizontal, deltaVertical int, finish bool) error { func (p *portalController) PointerScroll(deltaHorizontal, deltaVertical int, finish bool) error {
inVardict := make(map[string]dbus.Variant) if err := p.portalDesktop.Call("org.freedesktop.portal.RemoteDesktop.NotifyPointerAxis", 0,
inVardict["finish"] = dbus.MakeVariant(finish) p.sessionHandle, map[string]dbus.Variant{"finish": dbus.MakeVariant(finish)}, float64(deltaHorizontal), float64(deltaVertical),
if err := p.remoteDesktop.Call("org.freedesktop.portal.RemoteDesktop.NotifyPointerAxis", ).Store(); err != nil {
0, p.sessionHandle, inVardict, float64(deltaHorizontal), float64(deltaVertical)).Store(); err != nil {
return err return err
} }
return nil return nil