1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
|
# 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
# The part of a {Connection} that can export {DBus::Object}s to provide
# services to clients.
#
# Note that an ObjectServer does not have a name. Typically a {Connection}
# has one well known name, but can have none or more.
#
# Formerly this class was intermixed with {ProxyService} as Service.
#
# @example Usage
# bus = DBus.session_bus
# obj = DBus::Object.new("/path") # a subclass more likely
# bus.object_server.export(obj)
# bus.request_name("org.example.Test")
class ObjectServer < NodeTree
# @return [Connection] The connection we're using.
attr_reader :connection
def initialize(connection)
@connection = connection
super()
end
# Retrieves an object at the given _path_
# @param path [ObjectPath]
# @return [DBus::Object,nil]
def object(path)
node = get_node(path, create: false)
node&.object
end
alias [] object
# Export an object
# @param obj [DBus::Object]
# @raise RuntimeError if there's already an exported object at the same path
def export(obj)
node = get_node(obj.path, create: true)
raise "At #{obj.path} there is already an object #{node.object.inspect}" if node.object
node.object = obj
obj.object_server = self
object_manager_for(obj)&.object_added(obj)
end
# Undo exporting an object *obj_or_path*.
# Raises ArgumentError if it is not a DBus::Object.
# Returns the object, or false if _obj_ was not exported.
# @param obj_or_path [DBus::Object,ObjectPath,String] an object or a valid object path
def unexport(obj_or_path)
path = self.class.path_of(obj_or_path)
parent_path, _separator, node_name = path.rpartition("/")
parent_node = get_node(parent_path, create: false)
return false unless parent_node
node = if node_name == "" # path == "/"
parent_node
else
parent_node[node_name]
end
obj = node&.object
raise ArgumentError, "Cannot unexport, no object at #{path}" unless obj
object_manager_for(obj)&.object_removed(obj)
obj.object_server = nil
node.object = nil
# node can be deleted if
# - it has no children
# - it is not root
if node.empty? && !node.equal?(parent_node)
parent_node.delete(node_name)
end
obj
end
# Find the (closest) parent of *object*
# implementing the ObjectManager interface, or nil
# @return [DBus::Object,nil]
def object_manager_for(object)
path = object.path
node_chain = get_node_chain(path)
om_node = node_chain.reverse_each.find do |node|
node.object&.is_a? DBus::ObjectManager
end
om_node&.object
end
# All objects (not paths) under this path (except itself).
# @param path [ObjectPath]
# @return [Array<DBus::Object>]
# @raise ArgumentError if the *path* does not exist
def descendants_for(path)
node = get_node(path, create: false)
raise ArgumentError, "Object path #{path} doesn't exist" if node.nil?
node.descendant_objects
end
# @param obj_or_path [DBus::Object,ObjectPath,String] an object or a valid object path
# @return [ObjectPath]
# @api private
def self.path_of(obj_or_path)
case obj_or_path
when ObjectPath
obj_or_path
when String
ObjectPath.new(obj_or_path)
when DBus::Object
obj_or_path.path
else
raise ArgumentError, "Expecting a DBus::Object argument or DBus::ObjectPath or String which parses as one"
end
end
#########
private
#########
# @param path [ObjectPath] a path that must exist
# @return [Array<Node>] nodes from the root to the leaf
def get_node_chain(path)
n = @root
result = [n]
path.sub(%r{^/}, "").split("/").each do |elem|
n = n[elem]
result.push(n)
end
result
end
end
end
|