lib/dbus/proxy_service.rb
# frozen_string_literal: true
# This file is part of the ruby-dbus project
# Copyright (C) 2007 Arnaud Cornet and Paul van Tilburg
# Copyright (C) 2023 Martin Vidner
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License, version 2.1 as published by the Free Software Foundation.
# See the file "COPYING" for the exact licensing terms.
require_relative "node_tree"
module DBus
# Used by clients to represent a named service on the other side of the bus.
#
# Formerly this class was intermixed with {ObjectServer} as Service.
#
# @example Usage
# svc = DBus.system_bus["org.freedesktop.machine1"]
# manager = svc["/org/freedesktop/machine1"]
# p manager.ListImages
class ProxyService < NodeTree
# @return [BusName,nil] The service name.
# Will be nil for a {PeerConnection}
attr_reader :name
# @return [Connection] The connection we're using.
attr_reader :connection
# @param connection [Connection] The connection we're using.
def initialize(name, connection)
@name = BusName.new(name)
@connection = connection
super()
end
# Determine whether the service name already exists.
def exists?
bus = connection # TODO: raise a better error if this is a peer connection
bus.proxy.ListNames[0].member?(@name)
end
# Perform an introspection on all the objects on the service
# (starting recursively from the root).
def introspect
raise NotImplementedError if block_given?
rec_introspect(@root, "/")
self
end
# Retrieves an object at the given _path_.
# @param path [ObjectPath]
# @return [ProxyObject]
def [](path)
object(path, api: ApiOptions::A1)
end
# Retrieves an object at the given _path_
# whose methods always return an array.
# @param path [ObjectPath]
# @param api [ApiOptions]
# @return [ProxyObject]
def object(path, api: ApiOptions::A0)
node = get_node(path, create: true)
if node.object.nil? || node.object.api != api
node.object = ProxyObject.new(
@connection, @name, path,
api: api
)
end
node.object
end
private
# Perform a recursive retrospection on the given current _node_
# on the given _path_.
def rec_introspect(node, path)
xml = connection.introspect_data(@name, path)
intfs, subnodes = IntrospectXMLParser.new(xml).parse
subnodes.each do |nodename|
subnode = node[nodename] = Node.new(nodename)
subpath = if path == "/"
"/#{nodename}"
else
"#{path}/#{nodename}"
end
rec_introspect(subnode, subpath)
end
return if intfs.empty?
node.object = ProxyObjectFactory.new(xml, @connection, @name, path).build
end
end
# A hack for pretending that a {PeerConnection} has a single unnamed {ProxyService}
# so that we can get {ProxyObject}s from it.
class ProxyPeerService < ProxyService
# @param connection [Connection] The peer connection we're using.
def initialize(connection)
# this way we disallow ProxyService taking a nil name by accident
super(":0.0", connection)
@name = nil
end
end
end