ruby-dbus 0.14.0 → 0.17.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 +5 -5
- data/NEWS.md +44 -0
- data/README.md +3 -5
- data/Rakefile +26 -8
- data/VERSION +1 -1
- data/doc/Reference.md +84 -1
- data/examples/doc/_extract_examples +5 -0
- data/examples/gdbus/gdbus +21 -20
- data/examples/service/call_service.rb +1 -1
- data/lib/dbus/auth.rb +8 -8
- data/lib/dbus/bus.rb +23 -11
- data/lib/dbus/bus_name.rb +27 -0
- data/lib/dbus/core_ext/class/attribute.rb +23 -41
- data/lib/dbus/core_ext/module/redefine_method.rb +51 -0
- data/lib/dbus/introspect.rb +71 -26
- data/lib/dbus/marshall.rb +2 -1
- data/lib/dbus/message_queue.rb +17 -14
- data/lib/dbus/object.rb +380 -0
- data/lib/dbus/object_path.rb +24 -0
- data/lib/dbus/proxy_object.rb +11 -2
- data/lib/dbus/proxy_object_interface.rb +1 -0
- data/lib/dbus/type.rb +18 -0
- data/lib/dbus/xml.rb +4 -8
- data/lib/dbus.rb +3 -2
- data/ruby-dbus.gemspec +11 -9
- data/spec/binding_spec.rb +6 -2
- data/spec/bus_name_spec.rb +25 -0
- data/spec/client_robustness_spec.rb +25 -0
- data/spec/introspect_xml_parser_spec.rb +13 -13
- data/spec/main_loop_spec.rb +1 -1
- data/spec/object_path_spec.rb +23 -0
- data/spec/property_spec.rb +53 -3
- data/spec/proxy_object_spec.rb +9 -0
- data/spec/service_newapi.rb +20 -66
- data/spec/session_bus_spec.rb +6 -6
- data/spec/signal_spec.rb +33 -18
- data/spec/spec_helper.rb +23 -11
- data/spec/tools/dbus-limited-session.conf +4 -0
- data/spec/type_spec.rb +2 -2
- metadata +32 -15
- data/lib/dbus/core_ext/array/extract_options.rb +0 -31
- data/lib/dbus/core_ext/kernel/singleton_class.rb +0 -8
- data/lib/dbus/core_ext/module/remove_method.rb +0 -14
- data/lib/dbus/export.rb +0 -130
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# copied from activesupport/core_ext from Rails, MIT license
|
3
|
+
# https://github.com/rails/rails/tree/a713fdae4eb4f7ccd34932edc61561a96b8d9f35/activesupport/lib/active_support/core_ext/module
|
4
|
+
|
5
|
+
class Module
|
6
|
+
if RUBY_VERSION >= "2.3"
|
7
|
+
# Marks the named method as intended to be redefined, if it exists.
|
8
|
+
# Suppresses the Ruby method redefinition warning. Prefer
|
9
|
+
# #redefine_method where possible.
|
10
|
+
def silence_redefinition_of_method(method)
|
11
|
+
if method_defined?(method) || private_method_defined?(method)
|
12
|
+
# This suppresses the "method redefined" warning; the self-alias
|
13
|
+
# looks odd, but means we don't need to generate a unique name
|
14
|
+
alias_method method, method
|
15
|
+
end
|
16
|
+
end
|
17
|
+
else
|
18
|
+
def silence_redefinition_of_method(method)
|
19
|
+
if method_defined?(method) || private_method_defined?(method)
|
20
|
+
alias_method :__rails_redefine, method
|
21
|
+
remove_method :__rails_redefine
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Replaces the existing method definition, if there is one, with the passed
|
27
|
+
# block as its body.
|
28
|
+
def redefine_method(method, &block)
|
29
|
+
visibility = method_visibility(method)
|
30
|
+
silence_redefinition_of_method(method)
|
31
|
+
define_method(method, &block)
|
32
|
+
send(visibility, method)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Replaces the existing singleton method definition, if there is one, with
|
36
|
+
# the passed block as its body.
|
37
|
+
def redefine_singleton_method(method, &block)
|
38
|
+
singleton_class.redefine_method(method, &block)
|
39
|
+
end
|
40
|
+
|
41
|
+
def method_visibility(method) # :nodoc:
|
42
|
+
case
|
43
|
+
when private_method_defined?(method)
|
44
|
+
:private
|
45
|
+
when protected_method_defined?(method)
|
46
|
+
:protected
|
47
|
+
else
|
48
|
+
:public
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/dbus/introspect.rb
CHANGED
@@ -14,10 +14,6 @@ module DBus
|
|
14
14
|
# Regular expressions that should match all interface names.
|
15
15
|
INTERFACE_ELEMENT_RE = /^[A-Za-z][A-Za-z0-9_]*$/
|
16
16
|
|
17
|
-
# Exception raised when an unknown signal is used.
|
18
|
-
class UnknownSignal < Exception
|
19
|
-
end
|
20
|
-
|
21
17
|
# Exception raised when an invalid class definition is encountered.
|
22
18
|
class InvalidClassDefinition < Exception
|
23
19
|
end
|
@@ -30,19 +26,23 @@ module DBus
|
|
30
26
|
# It also is the local definition of interface exported by the program.
|
31
27
|
# At the client side, see ProxyObjectInterface
|
32
28
|
class Interface
|
33
|
-
# The name of the interface.
|
29
|
+
# @return [String] The name of the interface.
|
34
30
|
attr_reader :name
|
35
|
-
# The methods that are part of the interface.
|
31
|
+
# @return [Hash{Symbol => DBus::Method}] The methods that are part of the interface.
|
36
32
|
attr_reader :methods
|
37
|
-
# The signals that are part of the interface.
|
33
|
+
# @return [Hash{Symbol => Signal}] The signals that are part of the interface.
|
38
34
|
attr_reader :signals
|
39
35
|
|
36
|
+
# @return [Hash{Symbol => Property}]
|
37
|
+
attr_reader :properties
|
38
|
+
|
40
39
|
# Creates a new interface with a given _name_.
|
41
40
|
def initialize(name)
|
42
41
|
validate_name(name)
|
43
42
|
@name = name
|
44
43
|
@methods = {}
|
45
44
|
@signals = {}
|
45
|
+
@properties = {}
|
46
46
|
end
|
47
47
|
|
48
48
|
# Validates a service _name_.
|
@@ -50,29 +50,37 @@ module DBus
|
|
50
50
|
raise InvalidIntrospectionData if name.bytesize > 255
|
51
51
|
raise InvalidIntrospectionData if name =~ /^\./ || name =~ /\.$/
|
52
52
|
raise InvalidIntrospectionData if name =~ /\.\./
|
53
|
-
raise InvalidIntrospectionData if
|
53
|
+
raise InvalidIntrospectionData if name !~ /\./
|
54
54
|
name.split(".").each do |element|
|
55
|
-
raise InvalidIntrospectionData if
|
55
|
+
raise InvalidIntrospectionData if element !~ INTERFACE_ELEMENT_RE
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
-
#
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
59
|
+
# Add _ie_ as a known {Method}, {Signal} or {Property}
|
60
|
+
# @param ie [InterfaceElement]
|
61
|
+
def define(ie)
|
62
|
+
name = ie.name.to_sym
|
63
|
+
category = if ie.is_a?(Method)
|
64
|
+
@methods
|
65
|
+
elsif ie.is_a?(Signal)
|
66
|
+
@signals
|
67
|
+
elsif ie.is_a?(Property)
|
68
|
+
@properties
|
69
|
+
end
|
70
|
+
category[name] = ie
|
66
71
|
end
|
72
|
+
alias declare define
|
67
73
|
alias << define
|
68
74
|
|
69
75
|
# Defines a method with name _id_ and a given _prototype_ in the
|
70
76
|
# interface.
|
77
|
+
# Better name: declare_method
|
71
78
|
def define_method(id, prototype)
|
72
79
|
m = Method.new(id)
|
73
80
|
m.from_prototype(prototype)
|
74
81
|
define(m)
|
75
82
|
end
|
83
|
+
alias declare_method define_method
|
76
84
|
end # class Interface
|
77
85
|
|
78
86
|
# = A formal parameter has a name and a type
|
@@ -148,6 +156,7 @@ module DBus
|
|
148
156
|
end
|
149
157
|
|
150
158
|
# Add parameter types by parsing the given _prototype_.
|
159
|
+
# @param prototype [Prototype]
|
151
160
|
def from_prototype(prototype)
|
152
161
|
prototype.split(/, */).each do |arg|
|
153
162
|
arg = arg.split(" ")
|
@@ -171,16 +180,16 @@ module DBus
|
|
171
180
|
|
172
181
|
# Return an XML string representation of the method interface elment.
|
173
182
|
def to_xml
|
174
|
-
xml =
|
183
|
+
xml = " <method name=\"#{@name}\">\n"
|
175
184
|
@params.each do |param|
|
176
|
-
name = param.name ?
|
177
|
-
xml +=
|
185
|
+
name = param.name ? "name=\"#{param.name}\" " : ""
|
186
|
+
xml += " <arg #{name}direction=\"in\" type=\"#{param.type}\"/>\n"
|
178
187
|
end
|
179
188
|
@rets.each do |param|
|
180
|
-
name = param.name ?
|
181
|
-
xml +=
|
189
|
+
name = param.name ? "name=\"#{param.name}\" " : ""
|
190
|
+
xml += " <arg #{name}direction=\"out\" type=\"#{param.type}\"/>\n"
|
182
191
|
end
|
183
|
-
xml +=
|
192
|
+
xml += " </method>\n"
|
184
193
|
xml
|
185
194
|
end
|
186
195
|
end # class Method
|
@@ -205,13 +214,49 @@ module DBus
|
|
205
214
|
|
206
215
|
# Return an XML string representation of the signal interface elment.
|
207
216
|
def to_xml
|
208
|
-
xml =
|
217
|
+
xml = " <signal name=\"#{@name}\">\n"
|
209
218
|
@params.each do |param|
|
210
|
-
name = param.name ?
|
211
|
-
xml +=
|
219
|
+
name = param.name ? "name=\"#{param.name}\" " : ""
|
220
|
+
xml += " <arg #{name}type=\"#{param.type}\"/>\n"
|
212
221
|
end
|
213
|
-
xml +=
|
222
|
+
xml += " </signal>\n"
|
214
223
|
xml
|
215
224
|
end
|
216
225
|
end # class Signal
|
226
|
+
|
227
|
+
# An (exported) property
|
228
|
+
# https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties
|
229
|
+
class Property
|
230
|
+
# @return [String] The name of the property, for example FooBar.
|
231
|
+
attr_reader :name
|
232
|
+
attr_reader :type
|
233
|
+
# @return [Symbol] :read :write or :readwrite
|
234
|
+
attr_reader :access
|
235
|
+
|
236
|
+
# @return [Symbol] What to call at Ruby side.
|
237
|
+
# (Always without the trailing `=`)
|
238
|
+
attr_reader :ruby_name
|
239
|
+
|
240
|
+
def initialize(name, type, access, ruby_name:)
|
241
|
+
@name = name
|
242
|
+
@type = type
|
243
|
+
@access = access
|
244
|
+
@ruby_name = ruby_name
|
245
|
+
end
|
246
|
+
|
247
|
+
# @return [Boolean]
|
248
|
+
def readable?
|
249
|
+
access == :read || access == :readwrite
|
250
|
+
end
|
251
|
+
|
252
|
+
# @return [Boolean]
|
253
|
+
def writable?
|
254
|
+
access == :write || access == :readwrite
|
255
|
+
end
|
256
|
+
|
257
|
+
# Return introspection XML string representation of the property.
|
258
|
+
def to_xml
|
259
|
+
" <property type=\"#{@type}\" name=\"#{@name}\" access=\"#{@access}\"/>\n"
|
260
|
+
end
|
261
|
+
end
|
217
262
|
end # module DBus
|
data/lib/dbus/marshall.rb
CHANGED
@@ -69,6 +69,7 @@ module DBus
|
|
69
69
|
def align(a)
|
70
70
|
case a
|
71
71
|
when 1
|
72
|
+
nil
|
72
73
|
when 2, 4, 8
|
73
74
|
bits = a - 1
|
74
75
|
@idx = @idx + bits & ~bits
|
@@ -421,7 +422,7 @@ module DBus
|
|
421
422
|
["s", value.to_str]
|
422
423
|
elsif value.respond_to? :to_int
|
423
424
|
i = value.to_int
|
424
|
-
if -2_147_483_648
|
425
|
+
if (-2_147_483_648...2_147_483_648).cover?(i)
|
425
426
|
["i", i]
|
426
427
|
else
|
427
428
|
["x", i]
|
data/lib/dbus/message_queue.rb
CHANGED
@@ -11,6 +11,7 @@ require "fcntl"
|
|
11
11
|
require "socket"
|
12
12
|
|
13
13
|
module DBus
|
14
|
+
# Encapsulates a socket so that we can {#push} and {#pop} {Message}s.
|
14
15
|
class MessageQueue
|
15
16
|
# The socket that is used to connect with the bus.
|
16
17
|
attr_reader :socket
|
@@ -22,10 +23,10 @@ module DBus
|
|
22
23
|
connect
|
23
24
|
end
|
24
25
|
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
26
|
+
# @param non_block [Boolean] if true, return nil instead of waiting
|
27
|
+
# @return [Message,nil] one message or nil if unavailable
|
28
|
+
# @raise EOFError
|
29
|
+
# @todo failure modes
|
29
30
|
def pop(non_block = false)
|
30
31
|
buffer_from_socket_nonblock
|
31
32
|
message = message_from_buffer_nonblock
|
@@ -80,22 +81,23 @@ module DBus
|
|
80
81
|
|
81
82
|
# Connect to a bus over tcp and initialize the connection.
|
82
83
|
def connect_to_tcp(params)
|
83
|
-
|
84
|
-
|
84
|
+
host = params["host"]
|
85
|
+
port = params["port"]
|
86
|
+
if host && port
|
85
87
|
begin
|
86
88
|
# initialize the tcp socket
|
87
|
-
@socket = TCPSocket.new(
|
89
|
+
@socket = TCPSocket.new(host, port.to_i)
|
88
90
|
@socket.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
89
91
|
init_connection
|
90
92
|
@is_tcp = true
|
91
93
|
rescue Exception => e
|
92
94
|
puts "Oops:", e
|
93
|
-
puts "Error: Could not establish connection to: #{
|
95
|
+
puts "Error: Could not establish connection to: #{host}:#{port}, will now exit."
|
94
96
|
exit(1) # a little harsh
|
95
97
|
end
|
96
98
|
else
|
97
99
|
# Danger, Will Robinson: the specified "path" is not usable
|
98
|
-
puts "Error: supplied
|
100
|
+
puts "Error: supplied params: #{@params}, unusable! sorry."
|
99
101
|
end
|
100
102
|
end
|
101
103
|
|
@@ -124,14 +126,14 @@ module DBus
|
|
124
126
|
|
125
127
|
# Initialize the connection to the bus.
|
126
128
|
def init_connection
|
127
|
-
|
128
|
-
|
129
|
+
client = Client.new(@socket)
|
130
|
+
client.authenticate
|
129
131
|
end
|
130
132
|
|
131
133
|
public # FIXME: fix Main loop instead
|
132
134
|
|
133
135
|
# Get and remove one message from the buffer.
|
134
|
-
#
|
136
|
+
# @return [Message,nil] the message or nil if unavailable
|
135
137
|
def message_from_buffer_nonblock
|
136
138
|
return nil if @buffer.empty?
|
137
139
|
ret = nil
|
@@ -139,7 +141,7 @@ module DBus
|
|
139
141
|
ret, size = Message.new.unmarshall_buffer(@buffer)
|
140
142
|
@buffer.slice!(0, size)
|
141
143
|
rescue IncompleteBufferException
|
142
|
-
# fall through, let ret
|
144
|
+
# fall through, let ret remain nil
|
143
145
|
end
|
144
146
|
ret
|
145
147
|
end
|
@@ -149,7 +151,8 @@ module DBus
|
|
149
151
|
|
150
152
|
# Fill (append) the buffer from data that might be available on the
|
151
153
|
# socket.
|
152
|
-
#
|
154
|
+
# @return [void]
|
155
|
+
# @raise EOFError
|
153
156
|
def buffer_from_socket_nonblock
|
154
157
|
@buffer += @socket.read_nonblock(MSG_BUF_SIZE)
|
155
158
|
rescue EOFError
|