ruby-dbus 0.14.0 → 0.17.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|