Files

86 lines
3.6 KiB
Go

// Cthulhu screen reader.
// Copyright (c) 2026 Storm Dragon
// Authors: Storm Dragon, Angus Kola
// SPDX-License-Identifier: GPL-3.0-or-later
package remote
import "github.com/godbus/dbus/v5/introspect"
// service_bindings builds exports in their existing registration order. Start
// performs exports and rollback; Stop reverses this list before releasing names.
func service_bindings(endpoint *endpoint, orca bool, handler Handler) []serviceBinding {
path, iface := ObjectPath, InterfaceName
if orca {
path, iface = OrcaObjectPath, OrcaInterfaceName
}
var mainEndpoint any = endpoint
if orca {
mainEndpoint = &orcaServiceEndpoint{endpoint: endpoint}
}
registrations := []serviceBinding{
{path, iface, mainEndpoint},
{path, "org.freedesktop.DBus.Introspectable", introspect.NewIntrospectable(&introspect.Node{
Name: string(path),
Interfaces: []introspect.Interface{{Name: iface, Methods: serviceMethods(orca)}},
})},
}
if !orca {
registrations[1].value = introspect.NewIntrospectable(&introspect.Node{
Name: string(path), Interfaces: []introspect.Interface{{Name: iface, Methods: serviceMethods(false)}},
Children: []introspect.Node{{Name: "SpeechManager"}},
})
registrations = append(registrations, serviceBinding{SpeechManagerPath, SpeechManagerInterface, &speechManagerEndpoint{endpoint: endpoint}})
registrations = append(registrations, serviceBinding{SpeechManagerPath, "org.freedesktop.DBus.Introspectable", introspect.NewIntrospectable(&introspect.Node{
Name: string(SpeechManagerPath),
Interfaces: []introspect.Interface{{Name: SpeechManagerInterface, Methods: []introspect.Method{
{Name: "InterruptSpeech", Args: []introspect.Arg{
{Name: "notify_user", Type: "b", Direction: "in"},
{Name: "accepted", Type: "b", Direction: "out"},
}},
}}},
})})
}
_, hasModules := handler.(ModuleHandler)
if available, ok := handler.(ModuleAvailability); ok && !available.RemoteModulesAvailable() {
hasModules = false
}
if hasModules {
children := make([]introspect.Node, 0, len(modules))
for _, spec := range modules {
module := &moduleEndpoint{endpoint: endpoint, spec: spec}
moduleObjectPath := modulePath(path, spec.name)
moduleIface := "org.stormux.Cthulhu1." + spec.name
var object any
if orca {
moduleIface = orcaModuleInterface
object = module
} else if spec.name == "SpeechManager" {
// SpeechManager was registered above for existing self-voice clients.
object = nil
} else {
object = &typingEchoEndpoint{endpoint: endpoint}
}
if object != nil {
registrations = append(registrations, serviceBinding{moduleObjectPath, moduleIface, object})
}
registrations = append(registrations, serviceBinding{moduleObjectPath, "org.freedesktop.DBus.Properties", &modulePropertiesEndpoint{module: module, iface: moduleIface}})
introspection := introspect.NewIntrospectable(&introspect.Node{
Name: string(moduleObjectPath), Interfaces: []introspect.Interface{spec.introspection(orca)},
})
if !orca && spec.name == "SpeechManager" {
registrations[3].value = introspection
} else {
registrations = append(registrations, serviceBinding{moduleObjectPath, "org.freedesktop.DBus.Introspectable", introspection})
}
children = append(children, introspect.Node{Name: spec.name})
}
root := &introspect.Node{Name: string(path), Interfaces: []introspect.Interface{{Name: iface, Methods: serviceMethods(orca)}}, Children: children}
registrations[1].value = introspect.NewIntrospectable(root)
if orca {
registrations[0].value = &orcaServiceEndpoint{endpoint: endpoint, modules: sortedModuleNames()}
}
}
return registrations
}