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
data/lib/dbus/bus_name.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) 2019 Martin Vidner
|
|
3
5
|
#
|
|
@@ -7,21 +9,23 @@
|
|
|
7
9
|
# See the file "COPYING" for the exact licensing terms.
|
|
8
10
|
|
|
9
11
|
module DBus
|
|
10
|
-
#
|
|
12
|
+
# D-Bus: a name for a connection, like ":1.3" or "org.example.ManagerManager".
|
|
13
|
+
# Implemented as a {::String} that validates at initialization time.
|
|
11
14
|
# @see https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names-bus
|
|
12
15
|
class BusName < String
|
|
13
16
|
# @raise Error if not a valid bus name
|
|
14
|
-
def initialize(
|
|
15
|
-
unless self.class.valid?(
|
|
16
|
-
raise DBus::Error, "Invalid bus name #{
|
|
17
|
+
def initialize(name)
|
|
18
|
+
unless self.class.valid?(name)
|
|
19
|
+
raise DBus::Error, "Invalid bus name #{name.inspect}"
|
|
17
20
|
end
|
|
21
|
+
|
|
18
22
|
super
|
|
19
23
|
end
|
|
20
24
|
|
|
21
|
-
def self.valid?(
|
|
22
|
-
|
|
23
|
-
(
|
|
24
|
-
|
|
25
|
+
def self.valid?(name)
|
|
26
|
+
name.size <= 255 &&
|
|
27
|
+
(name =~ /\A:[A-Za-z0-9_-]+(\.[A-Za-z0-9_-]+)+\z/ ||
|
|
28
|
+
name =~ /\A[A-Za-z_-][A-Za-z0-9_-]*(\.[A-Za-z_-][A-Za-z0-9_-]*)+\z/)
|
|
25
29
|
end
|
|
26
30
|
end
|
|
27
31
|
end
|
|
@@ -0,0 +1,363 @@
|
|
|
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
|
+
module DBus
|
|
13
|
+
# D-Bus main connection class
|
|
14
|
+
#
|
|
15
|
+
# Main class that maintains a connection to a bus and can handle incoming
|
|
16
|
+
# and outgoing messages.
|
|
17
|
+
class Connection
|
|
18
|
+
# pop and push messages here
|
|
19
|
+
# @return [MessageQueue]
|
|
20
|
+
attr_reader :message_queue
|
|
21
|
+
|
|
22
|
+
# Create a new connection to the bus for a given connect _path_. _path_
|
|
23
|
+
# format is described in the D-Bus specification:
|
|
24
|
+
# http://dbus.freedesktop.org/doc/dbus-specification.html#addresses
|
|
25
|
+
# and is something like:
|
|
26
|
+
# "transport1:key1=value1,key2=value2;transport2:key1=value1,key2=value2"
|
|
27
|
+
# e.g. "unix:path=/tmp/dbus-test" or "tcp:host=localhost,port=2687"
|
|
28
|
+
def initialize(path)
|
|
29
|
+
@message_queue = MessageQueue.new(path)
|
|
30
|
+
|
|
31
|
+
# @return [Hash{Integer => Proc}]
|
|
32
|
+
# key: message serial
|
|
33
|
+
# value: block to be run when the reply to that message is received
|
|
34
|
+
@method_call_replies = {}
|
|
35
|
+
|
|
36
|
+
# @return [Hash{Integer => Message}]
|
|
37
|
+
# for debugging only: messages for which a reply was not received yet;
|
|
38
|
+
# key == value.serial
|
|
39
|
+
@method_call_msgs = {}
|
|
40
|
+
@signal_matchrules = {}
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def object_server
|
|
44
|
+
@object_server ||= ObjectServer.new(self)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Dispatch all messages that are available in the queue,
|
|
48
|
+
# but do not block on the queue.
|
|
49
|
+
# Called by a main loop when something is available in the queue
|
|
50
|
+
def dispatch_message_queue
|
|
51
|
+
while (msg = @message_queue.pop(blocking: false)) # FIXME: EOFError
|
|
52
|
+
process(msg)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Tell a bus to register itself on the glib main loop
|
|
57
|
+
def glibize
|
|
58
|
+
require "glib2"
|
|
59
|
+
# Circumvent a ruby-glib bug
|
|
60
|
+
@channels ||= []
|
|
61
|
+
|
|
62
|
+
gio = GLib::IOChannel.new(@message_queue.socket.fileno)
|
|
63
|
+
@channels << gio
|
|
64
|
+
gio.add_watch(GLib::IOChannel::IN) do |_c, _ch|
|
|
65
|
+
dispatch_message_queue
|
|
66
|
+
true
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# NAME_FLAG_* and REQUEST_NAME_* belong to BusConnection
|
|
71
|
+
# but users will have referenced them in Connection so they need to stay here
|
|
72
|
+
|
|
73
|
+
# FIXME: describe the following names, flags and constants.
|
|
74
|
+
# See DBus spec for definition
|
|
75
|
+
NAME_FLAG_ALLOW_REPLACEMENT = 0x1
|
|
76
|
+
NAME_FLAG_REPLACE_EXISTING = 0x2
|
|
77
|
+
NAME_FLAG_DO_NOT_QUEUE = 0x4
|
|
78
|
+
|
|
79
|
+
REQUEST_NAME_REPLY_PRIMARY_OWNER = 0x1
|
|
80
|
+
REQUEST_NAME_REPLY_IN_QUEUE = 0x2
|
|
81
|
+
REQUEST_NAME_REPLY_EXISTS = 0x3
|
|
82
|
+
REQUEST_NAME_REPLY_ALREADY_OWNER = 0x4
|
|
83
|
+
|
|
84
|
+
# @api private
|
|
85
|
+
# Send a _message_.
|
|
86
|
+
# If _reply_handler_ is not given, wait for the reply
|
|
87
|
+
# and return the reply, or raise the error.
|
|
88
|
+
# If _reply_handler_ is given, it will be called when the reply
|
|
89
|
+
# eventually arrives, with the reply message as the 1st param
|
|
90
|
+
# and its params following
|
|
91
|
+
def send_sync_or_async(message, &reply_handler)
|
|
92
|
+
ret = nil
|
|
93
|
+
if reply_handler.nil?
|
|
94
|
+
send_sync(message) do |rmsg|
|
|
95
|
+
raise rmsg if rmsg.is_a?(Error)
|
|
96
|
+
|
|
97
|
+
ret = rmsg.params
|
|
98
|
+
end
|
|
99
|
+
else
|
|
100
|
+
on_return(message) do |rmsg|
|
|
101
|
+
if rmsg.is_a?(Error)
|
|
102
|
+
reply_handler.call(rmsg)
|
|
103
|
+
else
|
|
104
|
+
reply_handler.call(rmsg, * rmsg.params)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
@message_queue.push(message)
|
|
108
|
+
end
|
|
109
|
+
ret
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# @api private
|
|
113
|
+
def introspect_data(dest, path, &reply_handler)
|
|
114
|
+
m = DBus::Message.new(DBus::Message::METHOD_CALL)
|
|
115
|
+
m.path = path
|
|
116
|
+
m.interface = "org.freedesktop.DBus.Introspectable"
|
|
117
|
+
m.destination = dest
|
|
118
|
+
m.member = "Introspect"
|
|
119
|
+
m.sender = unique_name
|
|
120
|
+
if reply_handler.nil?
|
|
121
|
+
send_sync_or_async(m).first
|
|
122
|
+
else
|
|
123
|
+
send_sync_or_async(m) do |*args|
|
|
124
|
+
# TODO: test async introspection, is it used at all?
|
|
125
|
+
args.shift # forget the message, pass only the text
|
|
126
|
+
reply_handler.call(*args)
|
|
127
|
+
nil
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# @api private
|
|
133
|
+
# Issues a call to the org.freedesktop.DBus.Introspectable.Introspect method
|
|
134
|
+
# _dest_ is the service and _path_ the object path you want to introspect
|
|
135
|
+
# If a code block is given, the introspect call in asynchronous. If not
|
|
136
|
+
# data is returned
|
|
137
|
+
#
|
|
138
|
+
# FIXME: link to ProxyObject data definition
|
|
139
|
+
# The returned object is a ProxyObject that has methods you can call to
|
|
140
|
+
# issue somme METHOD_CALL messages, and to setup to receive METHOD_RETURN
|
|
141
|
+
def introspect(dest, path)
|
|
142
|
+
if !block_given?
|
|
143
|
+
# introspect in synchronous !
|
|
144
|
+
data = introspect_data(dest, path)
|
|
145
|
+
pof = DBus::ProxyObjectFactory.new(data, self, dest, path)
|
|
146
|
+
pof.build
|
|
147
|
+
else
|
|
148
|
+
introspect_data(dest, path) do |async_data|
|
|
149
|
+
yield(DBus::ProxyObjectFactory.new(async_data, self, dest, path).build)
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Exception raised when a service name is requested that is not available.
|
|
155
|
+
class NameRequestError < Exception
|
|
156
|
+
# @return [Integer] one of
|
|
157
|
+
# REQUEST_NAME_REPLY_IN_QUEUE
|
|
158
|
+
# REQUEST_NAME_REPLY_EXISTS
|
|
159
|
+
attr_reader :error_code
|
|
160
|
+
|
|
161
|
+
def initialize(error_code)
|
|
162
|
+
@error_code = error_code
|
|
163
|
+
super()
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# In case RequestName did not succeed, raise an exception but first ask the bus who owns the name instead of us
|
|
168
|
+
# @param ret [Integer] what RequestName returned
|
|
169
|
+
# @param name Name that was requested
|
|
170
|
+
# @return [REQUEST_NAME_REPLY_PRIMARY_OWNER,REQUEST_NAME_REPLY_ALREADY_OWNER] on success
|
|
171
|
+
# @raise [NameRequestError] with #error_code REQUEST_NAME_REPLY_EXISTS or REQUEST_NAME_REPLY_IN_QUEUE, on failure
|
|
172
|
+
# @api private
|
|
173
|
+
def handle_return_of_request_name(ret, name)
|
|
174
|
+
if [REQUEST_NAME_REPLY_EXISTS, REQUEST_NAME_REPLY_IN_QUEUE].include?(ret)
|
|
175
|
+
other = proxy.GetNameOwner(name).first
|
|
176
|
+
other_creds = proxy.GetConnectionCredentials(other).first
|
|
177
|
+
message = "Could not request #{name}, already owned by #{other}, #{other_creds.inspect}"
|
|
178
|
+
raise NameRequestError.new(ret), message
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
ret
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Attempt to request a service _name_.
|
|
185
|
+
# @raise NameRequestError which cannot really be rescued as it will be raised when dispatching a later call.
|
|
186
|
+
# @return [ObjectServer]
|
|
187
|
+
# @deprecated Use {BusConnection#request_name}.
|
|
188
|
+
def request_service(name)
|
|
189
|
+
# Use RequestName, but asynchronously!
|
|
190
|
+
# A synchronous call would not work with service activation, where
|
|
191
|
+
# method calls to be serviced arrive before the reply for RequestName
|
|
192
|
+
# (Ticket#29).
|
|
193
|
+
proxy.RequestName(name, NAME_FLAG_REPLACE_EXISTING) do |rmsg, r|
|
|
194
|
+
# check and report errors first
|
|
195
|
+
raise rmsg if rmsg.is_a?(Error)
|
|
196
|
+
|
|
197
|
+
handle_return_of_request_name(r, name)
|
|
198
|
+
end
|
|
199
|
+
object_server
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# @api private
|
|
203
|
+
# Wait for a message to arrive. Return it once it is available.
|
|
204
|
+
def wait_for_message
|
|
205
|
+
@message_queue.pop # FIXME: EOFError
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# @api private
|
|
209
|
+
# Send a message _msg_ on to the bus. This is done synchronously, thus
|
|
210
|
+
# the call will block until a reply message arrives.
|
|
211
|
+
# @param msg [Message]
|
|
212
|
+
# @param retc [Proc] the reply handler
|
|
213
|
+
# @yieldparam rmsg [MethodReturnMessage] the reply
|
|
214
|
+
# @yieldreturn [Array<Object>] the reply (out) parameters
|
|
215
|
+
def send_sync(msg, &retc) # :yields: reply/return message
|
|
216
|
+
return if msg.nil? # check if somethings wrong
|
|
217
|
+
|
|
218
|
+
@message_queue.push(msg)
|
|
219
|
+
@method_call_msgs[msg.serial] = msg
|
|
220
|
+
@method_call_replies[msg.serial] = retc
|
|
221
|
+
|
|
222
|
+
retm = wait_for_message
|
|
223
|
+
return if retm.nil? # check if somethings wrong
|
|
224
|
+
|
|
225
|
+
process(retm)
|
|
226
|
+
while @method_call_replies.key? msg.serial
|
|
227
|
+
retm = wait_for_message
|
|
228
|
+
process(retm)
|
|
229
|
+
end
|
|
230
|
+
rescue EOFError
|
|
231
|
+
new_err = DBus::Error.new("Connection dropped after we sent #{msg.inspect}")
|
|
232
|
+
raise new_err
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# @api private
|
|
236
|
+
# Specify a code block that has to be executed when a reply for
|
|
237
|
+
# message _msg_ is received.
|
|
238
|
+
# @param msg [Message]
|
|
239
|
+
def on_return(msg, &retc)
|
|
240
|
+
# Have a better exception here
|
|
241
|
+
if msg.message_type != Message::METHOD_CALL
|
|
242
|
+
raise "on_return should only get method_calls"
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
@method_call_msgs[msg.serial] = msg
|
|
246
|
+
@method_call_replies[msg.serial] = retc
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
# Asks bus to send us messages matching mr, and execute slot when
|
|
250
|
+
# received
|
|
251
|
+
# @param match_rule [MatchRule,#to_s]
|
|
252
|
+
# @return [void] actually return whether the rule existed, internal detail
|
|
253
|
+
def add_match(match_rule, &slot)
|
|
254
|
+
# check this is a signal.
|
|
255
|
+
mrs = match_rule.to_s
|
|
256
|
+
DBus.logger.debug "#{@signal_matchrules.size} rules, adding #{mrs.inspect}"
|
|
257
|
+
rule_existed = @signal_matchrules.key?(mrs)
|
|
258
|
+
@signal_matchrules[mrs] = slot
|
|
259
|
+
rule_existed
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# @param match_rule [MatchRule,#to_s]
|
|
263
|
+
# @return [void] actually return whether the rule existed, internal detail
|
|
264
|
+
def remove_match(match_rule)
|
|
265
|
+
mrs = match_rule.to_s
|
|
266
|
+
@signal_matchrules.delete(mrs).nil?
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
# @api private
|
|
270
|
+
# Process a message _msg_ based on its type.
|
|
271
|
+
# @param msg [Message]
|
|
272
|
+
def process(msg)
|
|
273
|
+
return if msg.nil? # check if somethings wrong
|
|
274
|
+
|
|
275
|
+
case msg.message_type
|
|
276
|
+
when Message::ERROR, Message::METHOD_RETURN
|
|
277
|
+
raise InvalidPacketException if msg.reply_serial.nil?
|
|
278
|
+
|
|
279
|
+
mcs = @method_call_replies[msg.reply_serial]
|
|
280
|
+
if !mcs
|
|
281
|
+
DBus.logger.debug "no return code for mcs: #{mcs.inspect} msg: #{msg.inspect}"
|
|
282
|
+
else
|
|
283
|
+
if msg.message_type == Message::ERROR
|
|
284
|
+
mcs.call(Error.new(msg))
|
|
285
|
+
else
|
|
286
|
+
mcs.call(msg)
|
|
287
|
+
end
|
|
288
|
+
@method_call_replies.delete(msg.reply_serial)
|
|
289
|
+
@method_call_msgs.delete(msg.reply_serial)
|
|
290
|
+
end
|
|
291
|
+
when DBus::Message::METHOD_CALL
|
|
292
|
+
if msg.path == "/org/freedesktop/DBus"
|
|
293
|
+
DBus.logger.debug "Got method call on /org/freedesktop/DBus"
|
|
294
|
+
end
|
|
295
|
+
node = object_server.get_node(msg.path, create: false)
|
|
296
|
+
# introspect a known path even if there is no object on it
|
|
297
|
+
if node &&
|
|
298
|
+
msg.interface == "org.freedesktop.DBus.Introspectable" &&
|
|
299
|
+
msg.member == "Introspect"
|
|
300
|
+
reply = Message.new(Message::METHOD_RETURN).reply_to(msg)
|
|
301
|
+
reply.sender = @unique_name
|
|
302
|
+
xml = node.to_xml(msg.path)
|
|
303
|
+
reply.add_param(Type::STRING, xml)
|
|
304
|
+
@message_queue.push(reply)
|
|
305
|
+
# dispatch for an object
|
|
306
|
+
elsif node&.object
|
|
307
|
+
node.object.dispatch(msg)
|
|
308
|
+
else
|
|
309
|
+
reply = Message.error(msg, "org.freedesktop.DBus.Error.UnknownObject",
|
|
310
|
+
"Object #{msg.path} doesn't exist")
|
|
311
|
+
@message_queue.push(reply)
|
|
312
|
+
end
|
|
313
|
+
when DBus::Message::SIGNAL
|
|
314
|
+
# the signal can match multiple different rules
|
|
315
|
+
# clone to allow new signale handlers to be registered
|
|
316
|
+
@signal_matchrules.dup.each do |mrs, slot|
|
|
317
|
+
if DBus::MatchRule.new.from_s(mrs).match(msg)
|
|
318
|
+
slot.call(msg)
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
else
|
|
322
|
+
# spec(Message Format): Unknown types must be ignored.
|
|
323
|
+
DBus.logger.debug "Unknown message type: #{msg.message_type}"
|
|
324
|
+
end
|
|
325
|
+
rescue Exception => e
|
|
326
|
+
raise msg.annotate_exception(e)
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
# @api private
|
|
330
|
+
# Emit a signal event for the given _service_, object _obj_, interface
|
|
331
|
+
# _intf_ and signal _sig_ with arguments _args_.
|
|
332
|
+
# @param _service unused
|
|
333
|
+
# @param obj [DBus::Object]
|
|
334
|
+
# @param intf [Interface]
|
|
335
|
+
# @param sig [Signal]
|
|
336
|
+
# @param args arguments for the signal
|
|
337
|
+
def emit(_service, obj, intf, sig, *args)
|
|
338
|
+
m = Message.new(DBus::Message::SIGNAL)
|
|
339
|
+
m.path = obj.path
|
|
340
|
+
m.interface = intf.name
|
|
341
|
+
m.member = sig.name
|
|
342
|
+
i = 0
|
|
343
|
+
sig.params.each do |par|
|
|
344
|
+
m.add_param(par.type, args[i])
|
|
345
|
+
i += 1
|
|
346
|
+
end
|
|
347
|
+
@message_queue.push(m)
|
|
348
|
+
end
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
# A {Connection} that is talking directly to a peer, with no bus daemon in between.
|
|
352
|
+
# A prominent example is the PulseAudio connection,
|
|
353
|
+
# see https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/Developer/Clients/DBus/
|
|
354
|
+
# When starting, it still starts with authentication but omits the Hello message.
|
|
355
|
+
class PeerConnection < Connection
|
|
356
|
+
# Get a {ProxyPeerService}, a dummy helper to get {ProxyObject}s for
|
|
357
|
+
# a {PeerConnection}.
|
|
358
|
+
# @return [ProxyPeerService]
|
|
359
|
+
def peer_service
|
|
360
|
+
ProxyPeerService.new(self)
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
end
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# copied from activesupport/core_ext from Rails, MIT license
|
|
3
3
|
# https://github.com/rails/rails/tree/9794e85351243cac6d4e78adaba634b8e4ecad0a/activesupport/lib/active_support/core_ext
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
require_relative "../module/redefine_method"
|
|
6
6
|
|
|
7
7
|
class Class
|
|
8
8
|
# Declare a class-level attribute whose value is inheritable by subclasses.
|