ruby-dbus 0.17.0 → 0.18.0.beta1
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 +15 -0
- data/README.md +1 -1
- data/Rakefile +3 -11
- data/VERSION +1 -1
- data/doc/Reference.md +9 -2
- data/examples/doc/_extract_examples +2 -0
- data/examples/gdbus/gdbus +11 -5
- 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 +1 -0
- data/examples/service/service_newapi.rb +1 -1
- data/examples/simple/call_introspect.rb +1 -0
- data/examples/simple/get_id.rb +2 -1
- data/examples/simple/properties.rb +2 -0
- data/examples/utils/listnames.rb +1 -0
- data/examples/utils/notify.rb +1 -0
- data/lib/dbus/api_options.rb +9 -0
- data/lib/dbus/auth.rb +12 -7
- data/lib/dbus/bus.rb +114 -70
- data/lib/dbus/bus_name.rb +12 -8
- data/lib/dbus/error.rb +4 -2
- data/lib/dbus/introspect.rb +29 -18
- data/lib/dbus/logger.rb +3 -1
- data/lib/dbus/marshall.rb +118 -86
- data/lib/dbus/matchrule.rb +16 -16
- data/lib/dbus/message.rb +40 -27
- data/lib/dbus/message_queue.rb +10 -5
- data/lib/dbus/object.rb +34 -13
- data/lib/dbus/object_path.rb +9 -5
- data/lib/dbus/proxy_object.rb +18 -4
- data/lib/dbus/proxy_object_factory.rb +11 -7
- data/lib/dbus/proxy_object_interface.rb +26 -22
- data/lib/dbus/type.rb +41 -34
- data/lib/dbus/xml.rb +28 -17
- data/lib/dbus.rb +7 -7
- data/ruby-dbus.gemspec +4 -2
- data/spec/async_spec.rb +2 -0
- data/spec/binding_spec.rb +2 -0
- data/spec/bus_and_xml_backend_spec.rb +2 -0
- data/spec/bus_driver_spec.rb +2 -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/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 +2 -0
- data/spec/node_spec.rb +23 -0
- data/spec/object_path_spec.rb +2 -0
- data/spec/property_spec.rb +11 -2
- data/spec/proxy_object_spec.rb +2 -0
- data/spec/server_robustness_spec.rb +2 -0
- data/spec/server_spec.rb +2 -0
- data/spec/service_newapi.rb +19 -4
- data/spec/session_bus_spec.rb +3 -1
- data/spec/session_bus_spec_manual.rb +2 -0
- data/spec/signal_spec.rb +2 -0
- data/spec/spec_helper.rb +5 -3
- data/spec/thread_safety_spec.rb +2 -0
- data/spec/type_spec.rb +2 -0
- data/spec/value_spec.rb +16 -1
- data/spec/variant_spec.rb +4 -2
- metadata +8 -7
data/lib/dbus/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
|
#
|
@@ -6,11 +8,10 @@
|
|
6
8
|
# License, version 2.1 as published by the Free Software Foundation.
|
7
9
|
# See the file "COPYING" for the exact licensing terms.
|
8
10
|
|
9
|
-
require "thread"
|
10
11
|
require_relative "core_ext/class/attribute"
|
11
12
|
|
12
13
|
module DBus
|
13
|
-
PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties"
|
14
|
+
PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties"
|
14
15
|
|
15
16
|
# Exported object type
|
16
17
|
# = Exportable D-Bus object class
|
@@ -20,6 +21,7 @@ module DBus
|
|
20
21
|
class Object
|
21
22
|
# The path of the object.
|
22
23
|
attr_reader :path
|
24
|
+
|
23
25
|
# The interfaces that the object supports. Hash: String => Interface
|
24
26
|
my_class_attribute :intfs
|
25
27
|
self.intfs = {}
|
@@ -43,11 +45,13 @@ module DBus
|
|
43
45
|
when Message::METHOD_CALL
|
44
46
|
reply = nil
|
45
47
|
begin
|
46
|
-
|
48
|
+
iface = intfs[msg.interface]
|
49
|
+
if !iface
|
47
50
|
raise DBus.error("org.freedesktop.DBus.Error.UnknownMethod"),
|
48
51
|
"Interface \"#{msg.interface}\" of object \"#{msg.path}\" doesn't exist"
|
49
52
|
end
|
50
|
-
|
53
|
+
member_sym = msg.member.to_sym
|
54
|
+
meth = iface.methods[member_sym]
|
51
55
|
if !meth
|
52
56
|
raise DBus.error("org.freedesktop.DBus.Error.UnknownMethod"),
|
53
57
|
"Method \"#{msg.member}\" on interface \"#{msg.interface}\" of object \"#{msg.path}\" doesn't exist"
|
@@ -57,11 +61,20 @@ module DBus
|
|
57
61
|
retdata = [*retdata]
|
58
62
|
|
59
63
|
reply = Message.method_return(msg)
|
60
|
-
|
61
|
-
|
64
|
+
if iface.name == PROPERTY_INTERFACE && member_sym == :Get
|
65
|
+
# Use the specific property type instead of the generic variant
|
66
|
+
# returned by Get.
|
67
|
+
# TODO: GetAll and Set still missing
|
68
|
+
property = dbus_lookup_property(msg.params[0], msg.params[1])
|
69
|
+
rsigs = [property.type]
|
70
|
+
else
|
71
|
+
rsigs = meth.rets.map(&:type)
|
72
|
+
end
|
73
|
+
rsigs.zip(retdata).each do |rsig, rdata|
|
74
|
+
reply.add_param(rsig, rdata)
|
62
75
|
end
|
63
|
-
rescue StandardError =>
|
64
|
-
dbus_msg_exc = msg.annotate_exception(
|
76
|
+
rescue StandardError => e
|
77
|
+
dbus_msg_exc = msg.annotate_exception(e)
|
65
78
|
reply = ErrorMessage.from_exception(dbus_msg_exc).reply_to(msg)
|
66
79
|
end
|
67
80
|
@service.bus.message_queue.push(reply)
|
@@ -70,17 +83,19 @@ module DBus
|
|
70
83
|
|
71
84
|
# Select (and create) the interface that the following defined methods
|
72
85
|
# belong to.
|
73
|
-
|
86
|
+
# @param name [String] interface name like "org.example.ManagerManager"
|
87
|
+
# @see https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names-interface
|
88
|
+
def self.dbus_interface(name)
|
74
89
|
@@intfs_mutex.synchronize do
|
75
|
-
@@cur_intf = intfs[
|
90
|
+
@@cur_intf = intfs[name]
|
76
91
|
if !@@cur_intf
|
77
|
-
@@cur_intf = Interface.new(
|
92
|
+
@@cur_intf = Interface.new(name) # validates the name
|
78
93
|
# As this is a mutable class_attr, we cannot use
|
79
|
-
# self.intfs[
|
94
|
+
# self.intfs[name] = @@cur_intf # Hash#[]=
|
80
95
|
# as that would modify parent class attr in place.
|
81
96
|
# Using the setter lets a subclass have the new value
|
82
97
|
# while the superclass keeps the old one.
|
83
|
-
self.intfs = intfs.merge(
|
98
|
+
self.intfs = intfs.merge(name => @@cur_intf)
|
84
99
|
end
|
85
100
|
yield
|
86
101
|
@@cur_intf = nil
|
@@ -110,6 +125,7 @@ module DBus
|
|
110
125
|
# @return [void]
|
111
126
|
def self.dbus_attr_accessor(ruby_name, type, dbus_name: nil)
|
112
127
|
attr_accessor(ruby_name)
|
128
|
+
|
113
129
|
dbus_accessor(ruby_name, type, dbus_name: dbus_name)
|
114
130
|
end
|
115
131
|
|
@@ -129,6 +145,7 @@ module DBus
|
|
129
145
|
# @return (see .dbus_attr_accessor)
|
130
146
|
def self.dbus_attr_reader(ruby_name, type, dbus_name: nil)
|
131
147
|
attr_reader(ruby_name)
|
148
|
+
|
132
149
|
dbus_reader(ruby_name, type, dbus_name: dbus_name)
|
133
150
|
end
|
134
151
|
|
@@ -139,6 +156,7 @@ module DBus
|
|
139
156
|
# @return (see .dbus_attr_accessor)
|
140
157
|
def self.dbus_attr_writer(ruby_name, type, dbus_name: nil)
|
141
158
|
attr_writer(ruby_name)
|
159
|
+
|
142
160
|
dbus_writer(ruby_name, type, dbus_name: dbus_name)
|
143
161
|
end
|
144
162
|
|
@@ -211,6 +229,7 @@ module DBus
|
|
211
229
|
# @return [void]
|
212
230
|
def self.dbus_watcher(ruby_name, dbus_name: nil)
|
213
231
|
raise UndefinedInterface, ruby_name if @@cur_intf.nil?
|
232
|
+
|
214
233
|
cur_intf = @@cur_intf
|
215
234
|
|
216
235
|
ruby_name = ruby_name.to_s.sub(/=$/, "").to_sym
|
@@ -235,6 +254,7 @@ module DBus
|
|
235
254
|
# @param prototype [Prototype]
|
236
255
|
def self.dbus_method(sym, prototype = "", &block)
|
237
256
|
raise UndefinedInterface, sym if @@cur_intf.nil?
|
257
|
+
|
238
258
|
@@cur_intf.define(Method.new(sym.to_s).from_prototype(prototype))
|
239
259
|
|
240
260
|
ruby_name = Object.make_method_name(@@cur_intf.name, sym.to_s)
|
@@ -254,6 +274,7 @@ module DBus
|
|
254
274
|
# Defines a signal for the object with a given name _sym_ and _prototype_.
|
255
275
|
def self.dbus_signal(sym, prototype = "")
|
256
276
|
raise UndefinedInterface, sym if @@cur_intf.nil?
|
277
|
+
|
257
278
|
cur_intf = @@cur_intf
|
258
279
|
signal = Signal.new(sym.to_s).from_prototype(prototype)
|
259
280
|
cur_intf.define(Signal.new(sym.to_s).from_prototype(prototype))
|
data/lib/dbus/object_path.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
|
#
|
@@ -8,17 +10,19 @@
|
|
8
10
|
|
9
11
|
module DBus
|
10
12
|
# A {::String} that validates at initialization time
|
13
|
+
# @see https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-marshaling-object-path
|
11
14
|
class ObjectPath < String
|
12
15
|
# @raise Error if not a valid object path
|
13
|
-
def initialize(
|
14
|
-
unless self.class.valid?(
|
15
|
-
raise DBus::Error, "Invalid object path #{
|
16
|
+
def initialize(str)
|
17
|
+
unless self.class.valid?(str)
|
18
|
+
raise DBus::Error, "Invalid object path #{str.inspect}"
|
16
19
|
end
|
20
|
+
|
17
21
|
super
|
18
22
|
end
|
19
23
|
|
20
|
-
def self.valid?(
|
21
|
-
|
24
|
+
def self.valid?(str)
|
25
|
+
str == "/" || str =~ %r{\A(/[A-Za-z0-9_]+)+\z}
|
22
26
|
end
|
23
27
|
end
|
24
28
|
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
|
@@ -57,6 +59,7 @@ module DBus
|
|
57
59
|
introspect unless introspected
|
58
60
|
ifc = @interfaces[intfname]
|
59
61
|
raise DBus::Error, "no such interface `#{intfname}' on object `#{@path}'" unless ifc
|
62
|
+
|
60
63
|
ifc
|
61
64
|
end
|
62
65
|
|
@@ -93,6 +96,7 @@ module DBus
|
|
93
96
|
# don't overwrite instance methods!
|
94
97
|
next if dup_meths.include?(name)
|
95
98
|
next if self.class.instance_methods.include?(name)
|
99
|
+
|
96
100
|
if univocal_meths.include? name
|
97
101
|
univocal_meths.delete name
|
98
102
|
dup_meths << name
|
@@ -124,14 +128,17 @@ module DBus
|
|
124
128
|
def on_signal(name, &block)
|
125
129
|
# TODO: improve
|
126
130
|
raise NoMethodError unless @default_iface && has_iface?(@default_iface)
|
131
|
+
|
127
132
|
@interfaces[@default_iface].on_signal(name, &block)
|
128
133
|
end
|
129
134
|
|
130
135
|
####################################################
|
131
136
|
private
|
132
137
|
|
133
|
-
# rubocop:disable
|
134
|
-
#
|
138
|
+
# rubocop:disable Lint/MissingSuper
|
139
|
+
# as this should forward everything
|
140
|
+
#
|
141
|
+
# https://github.com/rubocop-hq/ruby-style-guide#no-method-missing
|
135
142
|
# and http://blog.marc-andre.ca/2010/11/15/methodmissing-politely/
|
136
143
|
# have a point to be investigated
|
137
144
|
|
@@ -152,10 +159,17 @@ module DBus
|
|
152
159
|
# interesting, foo.method("unknown")
|
153
160
|
# raises NameError, not NoMethodError
|
154
161
|
raise unless e.to_s =~ /undefined method `#{name}'/
|
162
|
+
|
155
163
|
# BTW e.exception("...") would preserve the class.
|
156
164
|
raise NoMethodError, "undefined method `#{name}' for DBus interface `#{@default_iface}' on object `#{@path}'"
|
157
165
|
end
|
158
166
|
end
|
159
|
-
# rubocop:enable
|
160
|
-
|
167
|
+
# rubocop:enable Lint/MissingSuper
|
168
|
+
|
169
|
+
def respond_to_missing?(name, _include_private = false)
|
170
|
+
@default_iface &&
|
171
|
+
has_iface?(@default_iface) &&
|
172
|
+
@interfaces[@default_iface].methods.key?(name) or super
|
173
|
+
end
|
174
|
+
end
|
161
175
|
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,19 @@ 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, pobj.subnodes = IntrospectXMLParser.new(xml).parse
|
29
33
|
intfs.each do |i|
|
30
|
-
poi = ProxyObjectInterface.new(
|
34
|
+
poi = ProxyObjectInterface.new(pobj, i.name)
|
31
35
|
i.methods.each_value { |m| poi.define(m) }
|
32
36
|
i.signals.each_value { |s| poi.define(s) }
|
33
|
-
|
37
|
+
pobj[i.name] = poi
|
34
38
|
end
|
35
|
-
|
39
|
+
pobj.introspected = true
|
36
40
|
end
|
37
41
|
|
38
42
|
# Generates, sets up and returns the proxy object.
|
@@ -41,5 +45,5 @@ module DBus
|
|
41
45
|
ProxyObjectFactory.introspect_into(po, @xml)
|
42
46
|
po
|
43
47
|
end
|
44
|
-
end
|
48
|
+
end
|
45
49
|
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
|
@@ -36,27 +38,28 @@ module DBus
|
|
36
38
|
@name
|
37
39
|
end
|
38
40
|
|
39
|
-
# Defines a method on the interface from the Method descriptor
|
40
|
-
|
41
|
-
|
41
|
+
# Defines a method on the interface from the Method descriptor _method_.
|
42
|
+
# @param method [Method]
|
43
|
+
def define_method_from_descriptor(method)
|
44
|
+
method.params.each do |fpar|
|
42
45
|
par = fpar.type
|
43
46
|
# This is the signature validity check
|
44
47
|
Type::Parser.new(par).parse
|
45
48
|
end
|
46
49
|
|
47
50
|
singleton_class.class_eval do
|
48
|
-
define_method
|
49
|
-
if
|
50
|
-
raise ArgumentError, "wrong number of arguments (#{args.size} for #{
|
51
|
+
define_method method.name do |*args, &reply_handler|
|
52
|
+
if method.params.size != args.size
|
53
|
+
raise ArgumentError, "wrong number of arguments (#{args.size} for #{method.params.size})"
|
51
54
|
end
|
52
55
|
|
53
56
|
msg = Message.new(Message::METHOD_CALL)
|
54
57
|
msg.path = @object.path
|
55
58
|
msg.interface = @name
|
56
59
|
msg.destination = @object.destination
|
57
|
-
msg.member =
|
60
|
+
msg.member = method.name
|
58
61
|
msg.sender = @object.bus.unique_name
|
59
|
-
|
62
|
+
method.params.each do |fpar|
|
60
63
|
par = fpar.type
|
61
64
|
msg.add_param(par, args.shift)
|
62
65
|
end
|
@@ -64,30 +67,31 @@ module DBus
|
|
64
67
|
if ret.nil? || @object.api.proxy_method_returns_array
|
65
68
|
ret
|
66
69
|
else
|
67
|
-
|
70
|
+
method.rets.size == 1 ? ret.first : ret
|
68
71
|
end
|
69
72
|
end
|
70
73
|
end
|
71
74
|
|
72
|
-
@methods[
|
75
|
+
@methods[method.name] = method
|
73
76
|
end
|
74
77
|
|
75
|
-
# Defines a signal from the descriptor
|
76
|
-
|
77
|
-
|
78
|
+
# Defines a signal from the descriptor _sig_.
|
79
|
+
# @param sig [Signal]
|
80
|
+
def define_signal_from_descriptor(sig)
|
81
|
+
@signals[sig.name] = sig
|
78
82
|
end
|
79
83
|
|
80
|
-
# Defines a signal or method based on the descriptor
|
81
|
-
def define(
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
84
|
+
# Defines a signal or method based on the descriptor _ifc_el_.
|
85
|
+
def define(ifc_el)
|
86
|
+
case ifc_el
|
87
|
+
when Method
|
88
|
+
define_method_from_descriptor(ifc_el)
|
89
|
+
when Signal
|
90
|
+
define_signal_from_descriptor(ifc_el)
|
86
91
|
end
|
87
92
|
end
|
88
93
|
|
89
94
|
# Defines a proxied method on the interface.
|
90
|
-
# Better name: declare_method
|
91
95
|
def define_method(methodname, prototype)
|
92
96
|
m = Method.new(methodname)
|
93
97
|
m.from_prototype(prototype)
|
@@ -110,7 +114,7 @@ module DBus
|
|
110
114
|
end
|
111
115
|
end
|
112
116
|
|
113
|
-
PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties"
|
117
|
+
PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties"
|
114
118
|
|
115
119
|
# Read a property.
|
116
120
|
# @param propname [String]
|
@@ -142,5 +146,5 @@ module DBus
|
|
142
146
|
ret
|
143
147
|
end
|
144
148
|
end
|
145
|
-
end
|
149
|
+
end
|
146
150
|
end
|
data/lib/dbus/type.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# dbus/type.rb - module containing low-level D-Bus data type information
|
2
4
|
#
|
3
5
|
# This file is part of the ruby-dbus project
|
@@ -33,7 +35,7 @@ module DBus
|
|
33
35
|
# protocol.
|
34
36
|
module Type
|
35
37
|
# Mapping from type number to name and alignment.
|
36
|
-
|
38
|
+
TYPE_MAPPING = {
|
37
39
|
0 => ["INVALID", nil],
|
38
40
|
"y" => ["BYTE", 1],
|
39
41
|
"b" => ["BOOLEAN", 4],
|
@@ -54,7 +56,7 @@ module DBus
|
|
54
56
|
"h" => ["UNIX_FD", 4]
|
55
57
|
}.freeze
|
56
58
|
# Defines the set of constants
|
57
|
-
|
59
|
+
TYPE_MAPPING.each_pair do |key, value|
|
58
60
|
Type.const_set(value.first, key)
|
59
61
|
end
|
60
62
|
|
@@ -73,16 +75,17 @@ module DBus
|
|
73
75
|
|
74
76
|
# Create a new type instance for type number _sigtype_.
|
75
77
|
def initialize(sigtype)
|
76
|
-
if !
|
78
|
+
if !TYPE_MAPPING.keys.member?(sigtype)
|
77
79
|
raise SignatureException, "Unknown key in signature: #{sigtype.chr}"
|
78
80
|
end
|
81
|
+
|
79
82
|
@sigtype = sigtype
|
80
83
|
@members = []
|
81
84
|
end
|
82
85
|
|
83
86
|
# Return the required alignment for the type.
|
84
87
|
def alignment
|
85
|
-
|
88
|
+
TYPE_MAPPING[@sigtype].last
|
86
89
|
end
|
87
90
|
|
88
91
|
# Return a string representation of the type according to the
|
@@ -90,36 +93,38 @@ module DBus
|
|
90
93
|
def to_s
|
91
94
|
case @sigtype
|
92
95
|
when STRUCT
|
93
|
-
"(
|
96
|
+
"(#{@members.collect(&:to_s).join})"
|
94
97
|
when ARRAY
|
95
|
-
"a"
|
98
|
+
"a#{child}"
|
96
99
|
when DICT_ENTRY
|
97
|
-
"{
|
100
|
+
"{#{@members.collect(&:to_s).join}}"
|
98
101
|
else
|
99
|
-
if !
|
102
|
+
if !TYPE_MAPPING.keys.member?(@sigtype)
|
100
103
|
raise NotImplementedError
|
101
104
|
end
|
105
|
+
|
102
106
|
@sigtype.chr
|
103
107
|
end
|
104
108
|
end
|
105
109
|
|
106
|
-
# Add a new member type
|
107
|
-
def <<(
|
110
|
+
# Add a new member type _item_.
|
111
|
+
def <<(item)
|
108
112
|
if ![STRUCT, ARRAY, DICT_ENTRY].member?(@sigtype)
|
109
113
|
raise SignatureException
|
110
114
|
end
|
111
115
|
raise SignatureException if @sigtype == ARRAY && !@members.empty?
|
116
|
+
|
112
117
|
if @sigtype == DICT_ENTRY
|
113
|
-
|
118
|
+
case @members.size
|
119
|
+
when 2
|
114
120
|
raise SignatureException, "Dict entries have exactly two members"
|
115
|
-
|
116
|
-
|
117
|
-
if [STRUCT, ARRAY, DICT_ENTRY].member?(a.sigtype)
|
121
|
+
when 0
|
122
|
+
if [STRUCT, ARRAY, DICT_ENTRY].member?(item.sigtype)
|
118
123
|
raise SignatureException, "Dict entry keys must be basic types"
|
119
124
|
end
|
120
125
|
end
|
121
126
|
end
|
122
|
-
@members <<
|
127
|
+
@members << item
|
123
128
|
end
|
124
129
|
|
125
130
|
# Return the first contained member type.
|
@@ -128,19 +133,20 @@ module DBus
|
|
128
133
|
end
|
129
134
|
|
130
135
|
def inspect
|
131
|
-
s =
|
136
|
+
s = TYPE_MAPPING[@sigtype].first
|
132
137
|
if [STRUCT, ARRAY].member?(@sigtype)
|
133
|
-
s += ":
|
138
|
+
s += ": #{@members.inspect}"
|
134
139
|
end
|
135
140
|
s
|
136
141
|
end
|
137
|
-
end
|
142
|
+
end
|
138
143
|
|
139
144
|
# = D-Bus type parser class
|
140
145
|
#
|
141
146
|
# Helper class to parse a type signature in the protocol.
|
142
147
|
class Parser
|
143
148
|
# Create a new parser for the given _signature_.
|
149
|
+
# @param signature [Signature]
|
144
150
|
def initialize(signature)
|
145
151
|
@signature = signature
|
146
152
|
@idx = 0
|
@@ -153,30 +159,31 @@ module DBus
|
|
153
159
|
c
|
154
160
|
end
|
155
161
|
|
156
|
-
# Parse one character
|
157
|
-
def parse_one(
|
162
|
+
# Parse one character _char_ of the signature.
|
163
|
+
def parse_one(char)
|
158
164
|
res = nil
|
159
|
-
case
|
165
|
+
case char
|
160
166
|
when "a"
|
161
167
|
res = Type.new(ARRAY)
|
162
|
-
|
163
|
-
raise SignatureException, "Parse error in #{@signature}" if
|
164
|
-
|
168
|
+
char = nextchar
|
169
|
+
raise SignatureException, "Parse error in #{@signature}" if char.nil?
|
170
|
+
|
171
|
+
child = parse_one(char)
|
165
172
|
res << child
|
166
173
|
when "("
|
167
174
|
res = Type.new(STRUCT)
|
168
|
-
while (
|
169
|
-
res << parse_one(
|
175
|
+
while (char = nextchar) && char != ")"
|
176
|
+
res << parse_one(char)
|
170
177
|
end
|
171
|
-
raise SignatureException, "Parse error in #{@signature}" if
|
178
|
+
raise SignatureException, "Parse error in #{@signature}" if char.nil?
|
172
179
|
when "{"
|
173
180
|
res = Type.new(DICT_ENTRY)
|
174
|
-
while (
|
175
|
-
res << parse_one(
|
181
|
+
while (char = nextchar) && char != "}"
|
182
|
+
res << parse_one(char)
|
176
183
|
end
|
177
|
-
raise SignatureException, "Parse error in #{@signature}" if
|
184
|
+
raise SignatureException, "Parse error in #{@signature}" if char.nil?
|
178
185
|
else
|
179
|
-
res = Type.new(
|
186
|
+
res = Type.new(char)
|
180
187
|
end
|
181
188
|
res
|
182
189
|
end
|
@@ -190,8 +197,8 @@ module DBus
|
|
190
197
|
end
|
191
198
|
ret
|
192
199
|
end
|
193
|
-
end
|
194
|
-
end
|
200
|
+
end
|
201
|
+
end
|
195
202
|
|
196
203
|
# shortcuts
|
197
204
|
|
@@ -206,4 +213,4 @@ module DBus
|
|
206
213
|
[type(string_type), value]
|
207
214
|
end
|
208
215
|
module_function :variant
|
209
|
-
end
|
216
|
+
end
|
data/lib/dbus/xml.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# dbus/xml.rb - introspection parser, rexml/nokogiri abstraction
|
2
4
|
#
|
3
5
|
# This file is part of the ruby-dbus project
|
@@ -26,14 +28,23 @@ module DBus
|
|
26
28
|
attr_accessor :backend
|
27
29
|
end
|
28
30
|
# Creates a new parser for XML data in string _xml_.
|
31
|
+
# @param xml [String]
|
29
32
|
def initialize(xml)
|
30
33
|
@xml = xml
|
31
34
|
end
|
32
35
|
|
33
36
|
class AbstractXML
|
37
|
+
# @!method initialize(xml)
|
38
|
+
# @abstract
|
39
|
+
|
40
|
+
# @!method each(xpath)
|
41
|
+
# @abstract
|
42
|
+
# yields nodes which match xpath of type AbstractXML::Node
|
43
|
+
|
34
44
|
def self.have_nokogiri?
|
35
45
|
Object.const_defined?("Nokogiri")
|
36
46
|
end
|
47
|
+
|
37
48
|
class Node
|
38
49
|
def initialize(node)
|
39
50
|
@node = node
|
@@ -46,12 +57,6 @@ module DBus
|
|
46
57
|
# yields child nodes which match xpath of type AbstractXML::Node
|
47
58
|
def each(xpath); end
|
48
59
|
end
|
49
|
-
# required methods
|
50
|
-
# initialize parser with xml string
|
51
|
-
def initialize(xml); end
|
52
|
-
|
53
|
-
# yields nodes which match xpath of type AbstractXML::Node
|
54
|
-
def each(xpath); end
|
55
60
|
end
|
56
61
|
|
57
62
|
class NokogiriParser < AbstractXML
|
@@ -64,7 +69,9 @@ module DBus
|
|
64
69
|
@node.search(path).each { |node| block.call NokogiriNode.new(node) }
|
65
70
|
end
|
66
71
|
end
|
72
|
+
|
67
73
|
def initialize(xml)
|
74
|
+
super()
|
68
75
|
@doc = Nokogiri.XML(xml)
|
69
76
|
end
|
70
77
|
|
@@ -83,7 +90,9 @@ module DBus
|
|
83
90
|
@node.elements.each(path) { |node| block.call REXMLNode.new(node) }
|
84
91
|
end
|
85
92
|
end
|
93
|
+
|
86
94
|
def initialize(xml)
|
95
|
+
super()
|
87
96
|
@doc = REXML::Document.new(xml)
|
88
97
|
end
|
89
98
|
|
@@ -136,28 +145,30 @@ module DBus
|
|
136
145
|
######################################################################
|
137
146
|
private
|
138
147
|
|
139
|
-
# Parses a method signature XML element
|
140
|
-
# method/signal
|
141
|
-
|
142
|
-
|
148
|
+
# Parses a method signature XML element *elem* and initialises
|
149
|
+
# method/signal *methsig*.
|
150
|
+
# @param elem [AbstractXML::Node]
|
151
|
+
def parse_methsig(elem, methsig)
|
152
|
+
elem.each("arg") do |ae|
|
143
153
|
name = ae["name"]
|
144
154
|
dir = ae["direction"]
|
145
155
|
sig = ae["type"]
|
146
|
-
|
156
|
+
case methsig
|
157
|
+
when DBus::Signal
|
147
158
|
# Direction can only be "out", ignore it
|
148
|
-
|
149
|
-
|
159
|
+
methsig.add_fparam(name, sig)
|
160
|
+
when DBus::Method
|
150
161
|
case dir
|
151
162
|
# This is a method, so dir defaults to "in"
|
152
163
|
when "in", nil
|
153
|
-
|
164
|
+
methsig.add_fparam(name, sig)
|
154
165
|
when "out"
|
155
|
-
|
166
|
+
methsig.add_return(name, sig)
|
156
167
|
end
|
157
168
|
else
|
158
169
|
raise NotImplementedError, dir
|
159
170
|
end
|
160
171
|
end
|
161
172
|
end
|
162
|
-
end
|
163
|
-
end
|
173
|
+
end
|
174
|
+
end
|
data/lib/dbus.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# dbus.rb - Module containing the low-level D-Bus implementation
|
2
4
|
#
|
3
5
|
# This file is part of the ruby-dbus project
|
@@ -28,22 +30,20 @@ require_relative "dbus/type"
|
|
28
30
|
require_relative "dbus/xml"
|
29
31
|
|
30
32
|
require "socket"
|
31
|
-
require "thread"
|
32
|
-
|
33
33
|
# = D-Bus main module
|
34
34
|
#
|
35
35
|
# Module containing all the D-Bus modules and classes.
|
36
36
|
module DBus
|
37
37
|
# Default socket name for the system bus.
|
38
|
-
|
38
|
+
SYSTEM_BUS_ADDRESS = "unix:path=/var/run/dbus/system_bus_socket"
|
39
39
|
|
40
40
|
# Byte signifying big endianness.
|
41
|
-
BIG_END = "B"
|
41
|
+
BIG_END = "B"
|
42
42
|
# Byte signifying little endianness.
|
43
|
-
LIL_END = "l"
|
43
|
+
LIL_END = "l"
|
44
44
|
|
45
45
|
# Byte signifying the host's endianness.
|
46
|
-
HOST_END = if [0x01020304].pack("L").
|
46
|
+
HOST_END = if [0x01020304].pack("L").unpack1("V") == 0x01020304
|
47
47
|
LIL_END
|
48
48
|
else
|
49
49
|
BIG_END
|
@@ -69,4 +69,4 @@ module DBus
|
|
69
69
|
# Exception raised when invalid introspection data is parsed/used.
|
70
70
|
class InvalidIntrospectionData < Exception
|
71
71
|
end
|
72
|
-
end
|
72
|
+
end
|