ruby-dbus 0.16.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/NEWS.md +288 -3
- data/README.md +3 -5
- data/Rakefile +27 -12
- data/VERSION +1 -1
- data/doc/Reference.md +109 -10
- data/examples/doc/_extract_examples +7 -0
- data/examples/no-bus/pulseaudio.rb +50 -0
- data/examples/no-introspect/nm-test.rb +2 -0
- data/examples/no-introspect/tracker-test.rb +3 -1
- data/examples/rhythmbox/playpause.rb +2 -1
- data/examples/service/call_service.rb +2 -1
- data/examples/service/complex-property.rb +21 -0
- data/examples/service/service_newapi.rb +3 -3
- data/examples/simple/call_introspect.rb +1 -0
- data/examples/simple/get_id.rb +6 -3
- data/examples/simple/properties.rb +2 -0
- data/examples/utils/listnames.rb +10 -1
- data/examples/utils/notify.rb +1 -0
- data/lib/dbus/api_options.rb +9 -0
- data/lib/dbus/auth.rb +307 -217
- data/lib/dbus/bus.rb +155 -588
- data/lib/dbus/bus_name.rb +12 -8
- data/lib/dbus/connection.rb +363 -0
- data/lib/dbus/core_ext/class/attribute.rb +1 -1
- data/lib/dbus/data.rb +821 -0
- data/lib/dbus/emits_changed_signal.rb +83 -0
- data/lib/dbus/error.rb +4 -2
- data/lib/dbus/introspect.rb +133 -31
- data/lib/dbus/logger.rb +6 -3
- data/lib/dbus/main.rb +66 -0
- data/lib/dbus/marshall.rb +247 -296
- data/lib/dbus/matchrule.rb +16 -16
- data/lib/dbus/message.rb +66 -57
- data/lib/dbus/message_queue.rb +40 -25
- data/lib/dbus/node_tree.rb +105 -0
- data/lib/dbus/object.rb +442 -33
- data/lib/dbus/object_manager.rb +61 -0
- data/lib/dbus/object_path.rb +11 -6
- data/lib/dbus/object_server.rb +149 -0
- data/lib/dbus/org.freedesktop.DBus.xml +97 -0
- data/lib/dbus/platform.rb +26 -0
- data/lib/dbus/proxy_object.rb +30 -11
- data/lib/dbus/proxy_object_factory.rb +13 -7
- data/lib/dbus/proxy_object_interface.rb +63 -30
- data/lib/dbus/proxy_service.rb +107 -0
- data/lib/dbus/raw_message.rb +91 -0
- data/lib/dbus/type.rb +319 -86
- data/lib/dbus/xml.rb +40 -19
- data/lib/dbus.rb +28 -17
- data/ruby-dbus.gemspec +13 -6
- data/spec/async_spec.rb +2 -0
- data/spec/auth_spec.rb +225 -0
- data/spec/binding_spec.rb +2 -0
- data/spec/bus_and_xml_backend_spec.rb +5 -1
- data/spec/bus_connection_spec.rb +93 -0
- data/spec/bus_name_spec.rb +3 -1
- data/spec/bus_spec.rb +2 -0
- data/spec/byte_array_spec.rb +2 -0
- data/spec/client_robustness_spec.rb +4 -2
- data/spec/connection_spec.rb +37 -0
- data/spec/coverage_helper.rb +39 -0
- data/spec/data/marshall.yaml +1667 -0
- data/spec/data_spec.rb +673 -0
- data/spec/dbus_spec.rb +22 -0
- data/spec/emits_changed_signal_spec.rb +58 -0
- data/spec/err_msg_spec.rb +2 -0
- data/spec/introspect_xml_parser_spec.rb +2 -0
- data/spec/introspection_spec.rb +2 -0
- data/spec/main_loop_spec.rb +17 -1
- data/spec/message_spec.rb +21 -0
- data/spec/mock-service/cockpit-dbustests.rb +29 -0
- data/spec/mock-service/com.redhat.Cockpit.DBusTests.xml +180 -0
- data/spec/mock-service/org.ruby.service.service +4 -0
- data/spec/mock-service/org.rubygems.ruby_dbus.DBusTests.service +4 -0
- data/spec/{service_newapi.rb → mock-service/spaghetti-monster.rb} +122 -75
- data/spec/node_spec.rb +65 -0
- data/spec/object_manager_spec.rb +33 -0
- data/spec/object_path_spec.rb +3 -0
- data/spec/object_server_spec.rb +138 -0
- data/spec/object_spec.rb +194 -0
- data/spec/packet_marshaller_spec.rb +41 -0
- data/spec/packet_unmarshaller_spec.rb +248 -0
- data/spec/platform_spec.rb +14 -0
- data/spec/property_spec.rb +214 -12
- data/spec/proxy_object_interface_spec.rb +35 -0
- data/spec/proxy_object_spec.rb +2 -0
- data/spec/{bus_driver_spec.rb → proxy_service_spec.rb} +15 -8
- data/spec/raw_message_spec.rb +32 -0
- data/spec/server_robustness_spec.rb +20 -6
- data/spec/session_bus_spec.rb +36 -1
- data/spec/session_bus_spec_manual.rb +2 -0
- data/spec/signal_spec.rb +16 -3
- data/spec/spec_helper.rb +25 -33
- data/spec/thread_safety_spec.rb +55 -12
- data/spec/tools/dbus-launch-simple +9 -6
- data/spec/tools/dbus-limited-session.conf +32 -0
- data/spec/tools/test_env +26 -6
- data/spec/type_spec.rb +214 -6
- data/spec/value_spec.rb +16 -1
- data/spec/variant_spec.rb +4 -2
- data/spec/zzz_quit_spec.rb +16 -0
- metadata +92 -20
- data/examples/gdbus/gdbus +0 -257
- data/examples/gdbus/gdbus.glade +0 -98
- data/examples/gdbus/launch.sh +0 -4
- data/spec/server_spec.rb +0 -53
- data/spec/tools/test_server +0 -39
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This file is part of the ruby-dbus project
|
|
4
|
+
# Copyright (C) 2007 Arnaud Cornet and Paul van Tilburg
|
|
5
|
+
# Copyright (C) 2023 Martin Vidner
|
|
6
|
+
#
|
|
7
|
+
# This library is free software; you can redistribute it and/or
|
|
8
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
9
|
+
# License, version 2.1 as published by the Free Software Foundation.
|
|
10
|
+
# See the file "COPYING" for the exact licensing terms.
|
|
11
|
+
|
|
12
|
+
require_relative "node_tree"
|
|
13
|
+
|
|
14
|
+
module DBus
|
|
15
|
+
# The part of a {Connection} that can export {DBus::Object}s to provide
|
|
16
|
+
# services to clients.
|
|
17
|
+
#
|
|
18
|
+
# Note that an ObjectServer does not have a name. Typically a {Connection}
|
|
19
|
+
# has one well known name, but can have none or more.
|
|
20
|
+
#
|
|
21
|
+
# Formerly this class was intermixed with {ProxyService} as Service.
|
|
22
|
+
#
|
|
23
|
+
# @example Usage
|
|
24
|
+
# bus = DBus.session_bus
|
|
25
|
+
# obj = DBus::Object.new("/path") # a subclass more likely
|
|
26
|
+
# bus.object_server.export(obj)
|
|
27
|
+
# bus.request_name("org.example.Test")
|
|
28
|
+
class ObjectServer < NodeTree
|
|
29
|
+
# @return [Connection] The connection we're using.
|
|
30
|
+
attr_reader :connection
|
|
31
|
+
|
|
32
|
+
def initialize(connection)
|
|
33
|
+
@connection = connection
|
|
34
|
+
super()
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Retrieves an object at the given _path_
|
|
38
|
+
# @param path [ObjectPath]
|
|
39
|
+
# @return [DBus::Object,nil]
|
|
40
|
+
def object(path)
|
|
41
|
+
node = get_node(path, create: false)
|
|
42
|
+
node&.object
|
|
43
|
+
end
|
|
44
|
+
alias [] object
|
|
45
|
+
|
|
46
|
+
# Export an object
|
|
47
|
+
# @param obj [DBus::Object]
|
|
48
|
+
# @raise RuntimeError if there's already an exported object at the same path
|
|
49
|
+
def export(obj)
|
|
50
|
+
node = get_node(obj.path, create: true)
|
|
51
|
+
raise "At #{obj.path} there is already an object #{node.object.inspect}" if node.object
|
|
52
|
+
|
|
53
|
+
node.object = obj
|
|
54
|
+
|
|
55
|
+
obj.object_server = self
|
|
56
|
+
object_manager_for(obj)&.object_added(obj)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Undo exporting an object *obj_or_path*.
|
|
60
|
+
# Raises ArgumentError if it is not a DBus::Object.
|
|
61
|
+
# Returns the object, or false if _obj_ was not exported.
|
|
62
|
+
# @param obj_or_path [DBus::Object,ObjectPath,String] an object or a valid object path
|
|
63
|
+
def unexport(obj_or_path)
|
|
64
|
+
path = self.class.path_of(obj_or_path)
|
|
65
|
+
parent_path, _separator, node_name = path.rpartition("/")
|
|
66
|
+
|
|
67
|
+
parent_node = get_node(parent_path, create: false)
|
|
68
|
+
return false unless parent_node
|
|
69
|
+
|
|
70
|
+
node = if node_name == "" # path == "/"
|
|
71
|
+
parent_node
|
|
72
|
+
else
|
|
73
|
+
parent_node[node_name]
|
|
74
|
+
end
|
|
75
|
+
obj = node&.object
|
|
76
|
+
raise ArgumentError, "Cannot unexport, no object at #{path}" unless obj
|
|
77
|
+
|
|
78
|
+
object_manager_for(obj)&.object_removed(obj)
|
|
79
|
+
obj.object_server = nil
|
|
80
|
+
node.object = nil
|
|
81
|
+
|
|
82
|
+
# node can be deleted if
|
|
83
|
+
# - it has no children
|
|
84
|
+
# - it is not root
|
|
85
|
+
if node.empty? && !node.equal?(parent_node)
|
|
86
|
+
parent_node.delete(node_name)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
obj
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Find the (closest) parent of *object*
|
|
93
|
+
# implementing the ObjectManager interface, or nil
|
|
94
|
+
# @return [DBus::Object,nil]
|
|
95
|
+
def object_manager_for(object)
|
|
96
|
+
path = object.path
|
|
97
|
+
node_chain = get_node_chain(path)
|
|
98
|
+
om_node = node_chain.reverse_each.find do |node|
|
|
99
|
+
node.object&.is_a? DBus::ObjectManager
|
|
100
|
+
end
|
|
101
|
+
om_node&.object
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# All objects (not paths) under this path (except itself).
|
|
105
|
+
# @param path [ObjectPath]
|
|
106
|
+
# @return [Array<DBus::Object>]
|
|
107
|
+
# @raise ArgumentError if the *path* does not exist
|
|
108
|
+
def descendants_for(path)
|
|
109
|
+
node = get_node(path, create: false)
|
|
110
|
+
raise ArgumentError, "Object path #{path} doesn't exist" if node.nil?
|
|
111
|
+
|
|
112
|
+
node.descendant_objects
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# @param obj_or_path [DBus::Object,ObjectPath,String] an object or a valid object path
|
|
116
|
+
# @return [ObjectPath]
|
|
117
|
+
# @api private
|
|
118
|
+
def self.path_of(obj_or_path)
|
|
119
|
+
case obj_or_path
|
|
120
|
+
when ObjectPath
|
|
121
|
+
obj_or_path
|
|
122
|
+
when String
|
|
123
|
+
ObjectPath.new(obj_or_path)
|
|
124
|
+
when DBus::Object
|
|
125
|
+
obj_or_path.path
|
|
126
|
+
else
|
|
127
|
+
raise ArgumentError, "Expecting a DBus::Object argument or DBus::ObjectPath or String which parses as one"
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
#########
|
|
132
|
+
|
|
133
|
+
private
|
|
134
|
+
|
|
135
|
+
#########
|
|
136
|
+
|
|
137
|
+
# @param path [ObjectPath] a path that must exist
|
|
138
|
+
# @return [Array<Node>] nodes from the root to the leaf
|
|
139
|
+
def get_node_chain(path)
|
|
140
|
+
n = @root
|
|
141
|
+
result = [n]
|
|
142
|
+
path.sub(%r{^/}, "").split("/").each do |elem|
|
|
143
|
+
n = n[elem]
|
|
144
|
+
result.push(n)
|
|
145
|
+
end
|
|
146
|
+
result
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
|
2
|
+
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
|
3
|
+
<node>
|
|
4
|
+
<interface name="org.freedesktop.DBus.Introspectable">
|
|
5
|
+
<method name="Introspect">
|
|
6
|
+
<arg direction="out" type="s"/>
|
|
7
|
+
</method>
|
|
8
|
+
</interface>
|
|
9
|
+
<interface name="org.freedesktop.DBus">
|
|
10
|
+
<method name="Hello">
|
|
11
|
+
<arg direction="out" type="s"/>
|
|
12
|
+
</method>
|
|
13
|
+
<method name="RequestName">
|
|
14
|
+
<arg direction="in" type="s"/>
|
|
15
|
+
<arg direction="in" type="u"/>
|
|
16
|
+
<arg direction="out" type="u"/>
|
|
17
|
+
</method>
|
|
18
|
+
<method name="ReleaseName">
|
|
19
|
+
<arg direction="in" type="s"/>
|
|
20
|
+
<arg direction="out" type="u"/>
|
|
21
|
+
</method>
|
|
22
|
+
<method name="StartServiceByName">
|
|
23
|
+
<arg direction="in" type="s"/>
|
|
24
|
+
<arg direction="in" type="u"/>
|
|
25
|
+
<arg direction="out" type="u"/>
|
|
26
|
+
</method>
|
|
27
|
+
<method name="UpdateActivationEnvironment">
|
|
28
|
+
<arg direction="in" type="a{ss}"/>
|
|
29
|
+
</method>
|
|
30
|
+
<method name="NameHasOwner">
|
|
31
|
+
<arg direction="in" type="s"/>
|
|
32
|
+
<arg direction="out" type="b"/>
|
|
33
|
+
</method>
|
|
34
|
+
<method name="ListNames">
|
|
35
|
+
<arg direction="out" type="as"/>
|
|
36
|
+
</method>
|
|
37
|
+
<method name="ListActivatableNames">
|
|
38
|
+
<arg direction="out" type="as"/>
|
|
39
|
+
</method>
|
|
40
|
+
<method name="AddMatch">
|
|
41
|
+
<arg direction="in" type="s"/>
|
|
42
|
+
</method>
|
|
43
|
+
<method name="RemoveMatch">
|
|
44
|
+
<arg direction="in" type="s"/>
|
|
45
|
+
</method>
|
|
46
|
+
<method name="GetNameOwner">
|
|
47
|
+
<arg direction="in" type="s"/>
|
|
48
|
+
<arg direction="out" type="s"/>
|
|
49
|
+
</method>
|
|
50
|
+
<method name="ListQueuedOwners">
|
|
51
|
+
<arg direction="in" type="s"/>
|
|
52
|
+
<arg direction="out" type="as"/>
|
|
53
|
+
</method>
|
|
54
|
+
<method name="GetConnectionUnixUser">
|
|
55
|
+
<arg direction="in" type="s"/>
|
|
56
|
+
<arg direction="out" type="u"/>
|
|
57
|
+
</method>
|
|
58
|
+
<method name="GetConnectionUnixProcessID">
|
|
59
|
+
<arg direction="in" type="s"/>
|
|
60
|
+
<arg direction="out" type="u"/>
|
|
61
|
+
</method>
|
|
62
|
+
<method name="GetAdtAuditSessionData">
|
|
63
|
+
<arg direction="in" type="s"/>
|
|
64
|
+
<arg direction="out" type="ay"/>
|
|
65
|
+
</method>
|
|
66
|
+
<method name="GetConnectionSELinuxSecurityContext">
|
|
67
|
+
<arg direction="in" type="s"/>
|
|
68
|
+
<arg direction="out" type="ay"/>
|
|
69
|
+
</method>
|
|
70
|
+
<method name="ReloadConfig">
|
|
71
|
+
</method>
|
|
72
|
+
<method name="GetId">
|
|
73
|
+
<arg direction="out" type="s"/>
|
|
74
|
+
</method>
|
|
75
|
+
<method name="GetConnectionCredentials">
|
|
76
|
+
<arg direction="in" type="s"/>
|
|
77
|
+
<arg direction="out" type="a{sv}"/>
|
|
78
|
+
</method>
|
|
79
|
+
<property name="Features" type="as" access="read">
|
|
80
|
+
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
|
|
81
|
+
</property>
|
|
82
|
+
<property name="Interfaces" type="as" access="read">
|
|
83
|
+
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
|
|
84
|
+
</property>
|
|
85
|
+
<signal name="NameOwnerChanged">
|
|
86
|
+
<arg type="s"/>
|
|
87
|
+
<arg type="s"/>
|
|
88
|
+
<arg type="s"/>
|
|
89
|
+
</signal>
|
|
90
|
+
<signal name="NameLost">
|
|
91
|
+
<arg type="s"/>
|
|
92
|
+
</signal>
|
|
93
|
+
<signal name="NameAcquired">
|
|
94
|
+
<arg type="s"/>
|
|
95
|
+
</signal>
|
|
96
|
+
</interface>
|
|
97
|
+
</node>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This file is part of the ruby-dbus project
|
|
4
|
+
# Copyright (C) 2023 Martin Vidner
|
|
5
|
+
#
|
|
6
|
+
# This library is free software; you can redistribute it and/or
|
|
7
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
8
|
+
# License, version 2.1 as published by the Free Software Foundation.
|
|
9
|
+
# See the file "COPYING" for the exact licensing terms.
|
|
10
|
+
|
|
11
|
+
require "rbconfig"
|
|
12
|
+
|
|
13
|
+
module DBus
|
|
14
|
+
# Platform detection
|
|
15
|
+
module Platform
|
|
16
|
+
module_function
|
|
17
|
+
|
|
18
|
+
def freebsd?
|
|
19
|
+
RbConfig::CONFIG["target_os"] =~ /freebsd/
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def macos?
|
|
23
|
+
RbConfig::CONFIG["target_os"] =~ /darwin/
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
data/lib/dbus/proxy_object.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# This file is part of the ruby-dbus project
|
|
2
4
|
# Copyright (C) 2007 Arnaud Cornet and Paul van Tilburg
|
|
3
5
|
# Copyright (C) 2009-2014 Martin Vidner
|
|
@@ -8,20 +10,20 @@
|
|
|
8
10
|
# See the file "COPYING" for the exact licensing terms.
|
|
9
11
|
|
|
10
12
|
module DBus
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
# Class representing a remote object in an external application.
|
|
13
|
+
# Represents a remote object in an external application.
|
|
14
14
|
# Typically, calling a method on an instance of a ProxyObject sends a message
|
|
15
|
-
# over the bus so that the method is executed remotely on the
|
|
15
|
+
# over the bus so that the method is executed remotely on the corresponding
|
|
16
16
|
# object.
|
|
17
17
|
class ProxyObject
|
|
18
18
|
# The names of direct subnodes of the object in the tree.
|
|
19
19
|
attr_accessor :subnodes
|
|
20
20
|
# Flag determining whether the object has been introspected.
|
|
21
|
+
# @return [Boolean]
|
|
21
22
|
attr_accessor :introspected
|
|
22
23
|
# The (remote) destination of the object.
|
|
23
24
|
attr_reader :destination
|
|
24
25
|
# The path to the object.
|
|
26
|
+
# @return [ObjectPath]
|
|
25
27
|
attr_reader :path
|
|
26
28
|
# The bus the object is reachable via.
|
|
27
29
|
attr_reader :bus
|
|
@@ -31,6 +33,8 @@ module DBus
|
|
|
31
33
|
# @return [ApiOptions]
|
|
32
34
|
attr_reader :api
|
|
33
35
|
|
|
36
|
+
OPEN_QUOTE = RUBY_VERSION >= "3.4" ? "'" : "`"
|
|
37
|
+
|
|
34
38
|
# Creates a new proxy object living on the given _bus_ at destination _dest_
|
|
35
39
|
# on the given _path_.
|
|
36
40
|
def initialize(bus, dest, path, api: ApiOptions::CURRENT)
|
|
@@ -44,6 +48,7 @@ module DBus
|
|
|
44
48
|
end
|
|
45
49
|
|
|
46
50
|
# Returns the interfaces of the object.
|
|
51
|
+
# @return [Array<String>] names of the interfaces
|
|
47
52
|
def interfaces
|
|
48
53
|
introspect unless introspected
|
|
49
54
|
@interfaces.keys
|
|
@@ -55,7 +60,8 @@ module DBus
|
|
|
55
60
|
def [](intfname)
|
|
56
61
|
introspect unless introspected
|
|
57
62
|
ifc = @interfaces[intfname]
|
|
58
|
-
raise DBus::Error, "no such interface
|
|
63
|
+
raise DBus::Error, "no such interface #{OPEN_QUOTE}#{intfname}' on object #{OPEN_QUOTE}#{@path}'" unless ifc
|
|
64
|
+
|
|
59
65
|
ifc
|
|
60
66
|
end
|
|
61
67
|
|
|
@@ -92,6 +98,7 @@ module DBus
|
|
|
92
98
|
# don't overwrite instance methods!
|
|
93
99
|
next if dup_meths.include?(name)
|
|
94
100
|
next if self.class.instance_methods.include?(name)
|
|
101
|
+
|
|
95
102
|
if univocal_meths.include? name
|
|
96
103
|
univocal_meths.delete name
|
|
97
104
|
dup_meths << name
|
|
@@ -121,8 +128,11 @@ module DBus
|
|
|
121
128
|
# It uses _default_iface_ which must have been set.
|
|
122
129
|
# @return [void]
|
|
123
130
|
def on_signal(name, &block)
|
|
124
|
-
|
|
125
|
-
|
|
131
|
+
unless @default_iface && has_iface?(@default_iface)
|
|
132
|
+
raise NoMethodError, "undefined signal #{OPEN_QUOTE}#{name}' for DBus interface " \
|
|
133
|
+
"#{OPEN_QUOTE}#{@default_iface}' on object #{OPEN_QUOTE}#{@path}'"
|
|
134
|
+
end
|
|
135
|
+
|
|
126
136
|
@interfaces[@default_iface].on_signal(name, &block)
|
|
127
137
|
end
|
|
128
138
|
|
|
@@ -137,7 +147,8 @@ module DBus
|
|
|
137
147
|
# - di not specified
|
|
138
148
|
# TODO
|
|
139
149
|
# - di is specified but not found in introspection data
|
|
140
|
-
raise NoMethodError, "undefined method
|
|
150
|
+
raise NoMethodError, "undefined method #{OPEN_QUOTE}#{name}' for DBus interface " \
|
|
151
|
+
"#{OPEN_QUOTE}#{@default_iface}' on object #{OPEN_QUOTE}#{@path}'"
|
|
141
152
|
end
|
|
142
153
|
|
|
143
154
|
begin
|
|
@@ -145,10 +156,18 @@ module DBus
|
|
|
145
156
|
rescue NameError => e
|
|
146
157
|
# interesting, foo.method("unknown")
|
|
147
158
|
# raises NameError, not NoMethodError
|
|
148
|
-
raise unless e.to_s =~ /undefined method
|
|
159
|
+
raise unless e.to_s =~ /undefined method #{OPEN_QUOTE}#{name}'/
|
|
160
|
+
|
|
149
161
|
# BTW e.exception("...") would preserve the class.
|
|
150
|
-
raise NoMethodError, "undefined method
|
|
162
|
+
raise NoMethodError, "undefined method #{OPEN_QUOTE}#{name}' for DBus interface " \
|
|
163
|
+
"#{OPEN_QUOTE}#{@default_iface}' on object #{OPEN_QUOTE}#{@path}'"
|
|
151
164
|
end
|
|
152
165
|
end
|
|
153
|
-
|
|
166
|
+
|
|
167
|
+
def respond_to_missing?(name, _include_private = false)
|
|
168
|
+
(@default_iface &&
|
|
169
|
+
has_iface?(@default_iface) &&
|
|
170
|
+
@interfaces[@default_iface].methods.key?(name)) or super
|
|
171
|
+
end
|
|
172
|
+
end
|
|
154
173
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# This file is part of the ruby-dbus project
|
|
2
4
|
# Copyright (C) 2007 Arnaud Cornet and Paul van Tilburg
|
|
3
5
|
# Copyright (C) 2009-2014 Martin Vidner
|
|
@@ -22,17 +24,21 @@ module DBus
|
|
|
22
24
|
@api = api
|
|
23
25
|
end
|
|
24
26
|
|
|
25
|
-
# Investigates the sub-nodes of the proxy object
|
|
27
|
+
# Investigates the sub-nodes of the proxy object _pobj_ based on the
|
|
26
28
|
# introspection XML data _xml_ and sets them up recursively.
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
# @param pobj [ProxyObject]
|
|
30
|
+
# @param xml [String]
|
|
31
|
+
def self.introspect_into(pobj, xml)
|
|
32
|
+
# intfs [Array<Interface>], subnodes [Array<String>]
|
|
33
|
+
intfs, pobj.subnodes = IntrospectXMLParser.new(xml).parse
|
|
29
34
|
intfs.each do |i|
|
|
30
|
-
poi = ProxyObjectInterface.new(
|
|
35
|
+
poi = ProxyObjectInterface.new(pobj, i.name)
|
|
31
36
|
i.methods.each_value { |m| poi.define(m) }
|
|
32
37
|
i.signals.each_value { |s| poi.define(s) }
|
|
33
|
-
|
|
38
|
+
i.properties.each_value { |p| poi.define(p) }
|
|
39
|
+
pobj[i.name] = poi
|
|
34
40
|
end
|
|
35
|
-
|
|
41
|
+
pobj.introspected = true
|
|
36
42
|
end
|
|
37
43
|
|
|
38
44
|
# Generates, sets up and returns the proxy object.
|
|
@@ -41,5 +47,5 @@ module DBus
|
|
|
41
47
|
ProxyObjectFactory.introspect_into(po, @xml)
|
|
42
48
|
po
|
|
43
49
|
end
|
|
44
|
-
end
|
|
50
|
+
end
|
|
45
51
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# This file is part of the ruby-dbus project
|
|
2
4
|
# Copyright (C) 2007 Arnaud Cornet and Paul van Tilburg
|
|
3
5
|
# Copyright (C) 2009-2014 Martin Vidner
|
|
@@ -13,13 +15,16 @@ module DBus
|
|
|
13
15
|
# A class similar to the normal Interface used as a proxy for remote
|
|
14
16
|
# object interfaces.
|
|
15
17
|
class ProxyObjectInterface
|
|
16
|
-
#
|
|
17
|
-
|
|
18
|
-
#
|
|
19
|
-
|
|
20
|
-
#
|
|
18
|
+
# @return [Hash{String => DBus::Method}]
|
|
19
|
+
attr_reader :methods
|
|
20
|
+
# @return [Hash{String => Signal}]
|
|
21
|
+
attr_reader :signals
|
|
22
|
+
# @return [Hash{Symbol => Property}]
|
|
23
|
+
attr_reader :properties
|
|
24
|
+
|
|
25
|
+
# @return [ProxyObject] The proxy object to which this interface belongs.
|
|
21
26
|
attr_reader :object
|
|
22
|
-
# The name of the interface.
|
|
27
|
+
# @return [String] The name of the interface.
|
|
23
28
|
attr_reader :name
|
|
24
29
|
|
|
25
30
|
# Creates a new proxy interface for the given proxy _object_
|
|
@@ -29,6 +34,7 @@ module DBus
|
|
|
29
34
|
@name = name
|
|
30
35
|
@methods = {}
|
|
31
36
|
@signals = {}
|
|
37
|
+
@properties = {}
|
|
32
38
|
end
|
|
33
39
|
|
|
34
40
|
# Returns the string representation of the interface (the name).
|
|
@@ -36,27 +42,28 @@ module DBus
|
|
|
36
42
|
@name
|
|
37
43
|
end
|
|
38
44
|
|
|
39
|
-
# Defines a method on the interface from the Method descriptor
|
|
40
|
-
|
|
41
|
-
|
|
45
|
+
# Defines a method on the interface from the Method descriptor _method_.
|
|
46
|
+
# @param method [Method]
|
|
47
|
+
def define_method_from_descriptor(method)
|
|
48
|
+
method.params.each do |fpar|
|
|
42
49
|
par = fpar.type
|
|
43
50
|
# This is the signature validity check
|
|
44
51
|
Type::Parser.new(par).parse
|
|
45
52
|
end
|
|
46
53
|
|
|
47
54
|
singleton_class.class_eval do
|
|
48
|
-
define_method
|
|
49
|
-
if
|
|
50
|
-
raise ArgumentError, "wrong number of arguments (#{args.size} for #{
|
|
55
|
+
define_method method.name do |*args, &reply_handler|
|
|
56
|
+
if method.params.size != args.size
|
|
57
|
+
raise ArgumentError, "wrong number of arguments (#{args.size} for #{method.params.size})"
|
|
51
58
|
end
|
|
52
59
|
|
|
53
60
|
msg = Message.new(Message::METHOD_CALL)
|
|
54
61
|
msg.path = @object.path
|
|
55
62
|
msg.interface = @name
|
|
56
63
|
msg.destination = @object.destination
|
|
57
|
-
msg.member =
|
|
64
|
+
msg.member = method.name
|
|
58
65
|
msg.sender = @object.bus.unique_name
|
|
59
|
-
|
|
66
|
+
method.params.each do |fpar|
|
|
60
67
|
par = fpar.type
|
|
61
68
|
msg.add_param(par, args.shift)
|
|
62
69
|
end
|
|
@@ -64,25 +71,35 @@ module DBus
|
|
|
64
71
|
if ret.nil? || @object.api.proxy_method_returns_array
|
|
65
72
|
ret
|
|
66
73
|
else
|
|
67
|
-
|
|
74
|
+
method.rets.size == 1 ? ret.first : ret
|
|
68
75
|
end
|
|
69
76
|
end
|
|
70
77
|
end
|
|
71
78
|
|
|
72
|
-
@methods[
|
|
79
|
+
@methods[method.name] = method
|
|
73
80
|
end
|
|
74
81
|
|
|
75
|
-
# Defines a signal from the descriptor
|
|
76
|
-
|
|
77
|
-
|
|
82
|
+
# Defines a signal from the descriptor _sig_.
|
|
83
|
+
# @param sig [Signal]
|
|
84
|
+
def define_signal_from_descriptor(sig)
|
|
85
|
+
@signals[sig.name] = sig
|
|
78
86
|
end
|
|
79
87
|
|
|
80
|
-
#
|
|
81
|
-
def
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
88
|
+
# @param prop [Property]
|
|
89
|
+
def define_property_from_descriptor(prop)
|
|
90
|
+
@properties[prop.name] = prop
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Defines a signal or method based on the descriptor _ifc_el_.
|
|
94
|
+
# @param ifc_el [DBus::Method,Signal,Property]
|
|
95
|
+
def define(ifc_el)
|
|
96
|
+
case ifc_el
|
|
97
|
+
when Method
|
|
98
|
+
define_method_from_descriptor(ifc_el)
|
|
99
|
+
when Signal
|
|
100
|
+
define_signal_from_descriptor(ifc_el)
|
|
101
|
+
when Property
|
|
102
|
+
define_property_from_descriptor(ifc_el)
|
|
86
103
|
end
|
|
87
104
|
end
|
|
88
105
|
|
|
@@ -109,7 +126,7 @@ module DBus
|
|
|
109
126
|
end
|
|
110
127
|
end
|
|
111
128
|
|
|
112
|
-
PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties"
|
|
129
|
+
PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties"
|
|
113
130
|
|
|
114
131
|
# Read a property.
|
|
115
132
|
# @param propname [String]
|
|
@@ -124,10 +141,26 @@ module DBus
|
|
|
124
141
|
end
|
|
125
142
|
|
|
126
143
|
# Write a property.
|
|
127
|
-
# @param
|
|
144
|
+
# @param property_name [String]
|
|
128
145
|
# @param value [Object]
|
|
129
|
-
def []=(
|
|
130
|
-
|
|
146
|
+
def []=(property_name, value)
|
|
147
|
+
property = properties[property_name.to_sym]
|
|
148
|
+
if !property
|
|
149
|
+
raise DBus.error("org.freedesktop.DBus.Error.UnknownProperty"),
|
|
150
|
+
"Property '#{name}.#{property_name}' (on object '#{object.path}') not found"
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
case value
|
|
154
|
+
# accommodate former need to explicitly make a variant with the right type
|
|
155
|
+
when Data::Variant
|
|
156
|
+
variant = value
|
|
157
|
+
else
|
|
158
|
+
type = property.type
|
|
159
|
+
typed_value = Data.make_typed(type, value)
|
|
160
|
+
variant = Data::Variant.new(typed_value, member_type: type)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
object[PROPERTY_INTERFACE].Set(name, property_name, variant)
|
|
131
164
|
end
|
|
132
165
|
|
|
133
166
|
# Read all properties at once, as a hash.
|
|
@@ -141,5 +174,5 @@ module DBus
|
|
|
141
174
|
ret
|
|
142
175
|
end
|
|
143
176
|
end
|
|
144
|
-
end
|
|
177
|
+
end
|
|
145
178
|
end
|