ruby-dbus 0.23.0.beta2 → 0.23.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c671b06e04452129a899cd4b7877cf43f9c05b8e7bc6597e75bc460e250c97e7
4
- data.tar.gz: 18f660c6e5804fd133cf8351d801f8e0d4e332f1473cc390bedf77341d71845d
3
+ metadata.gz: 2465a9a90d0b4837640d475566edfde23aee4dc1d7d439d76d1f861b71f13033
4
+ data.tar.gz: 906288ee9d180ff0bfd4e53f45982040f240da983e23c818acd91d449d9f7f05
5
5
  SHA512:
6
- metadata.gz: 5cff2ab01f4db3d069a73b28f46cf861dcc81302ed239a7fc4332f46a7583b2394d679d5d73ab13f080b674e46f8961c89fa3fccc58ce9043d0bd33c4c2d02c4
7
- data.tar.gz: 495c060e5161c2c5267b723598d3185b14d4c6517e41504f5b49971d3c355acec1ee3ab6285b7796bb7aa8cb61dfb5bd24535a2613a9f22cfb80f65ec8a1cf49
6
+ metadata.gz: f2939e81cff3f5db2dd768f9e0f1c04159b0285501c73840f14dd8f61ad9f539fbbbf35d7e408cca11847dcd31848131c1c4df69705798860f03e4255f02dedf
7
+ data.tar.gz: 553f1d4c97a284371d7a10a0f439a40d2861ff8c40c2318c09f6f818f5911644db05142dc7a8d5e377dac355ddc389fcc9858647a568184e8598fd3d3bb71154
data/NEWS.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## Ruby D-Bus 0.23.1 - 2023-10-03
6
+
7
+ API:
8
+ * Add DBus::Object.dbus_reader_attr_accessor to declare a common use case
9
+ with a single call ([#140][]).
10
+ * BusConnection#request_name defaults to the simple use case: single owner
11
+ without queuing, failing fast; documented the complex use cases.
12
+
13
+ [#140]: https://github.com/mvidner/ruby-dbus/pull/140
14
+
5
15
  ## Ruby D-Bus 0.23.0.beta2 - 2023-06-23
6
16
 
7
17
  License:
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.23.0.beta2
1
+ 0.23.1
@@ -8,4 +8,12 @@ d = if ARGV.member?("--system")
8
8
  else
9
9
  DBus::SessionBus.instance
10
10
  end
11
- d.proxy.ListNames[0].each { |n| puts "\t#{n}" }
11
+ d.proxy.ListNames[0].each do |n|
12
+ puts "\t#{n}"
13
+ qns = d.proxy.ListQueuedOwners(n)[0]
14
+ next if qns.size == 1 && qns.first == n
15
+
16
+ qns.each do |qn|
17
+ puts "\t\t#{qn}"
18
+ end
19
+ end
data/lib/dbus/bus.rb CHANGED
@@ -55,20 +55,107 @@ module DBus
55
55
  @proxy
56
56
  end
57
57
 
58
+ # Request a well-known name so that clients can find us.
59
+ # @note Parameters other than *name* are advanced, you probably don't need them.
60
+ #
61
+ # With no boolean flags, running a second instance of a program that calls `request_name`
62
+ # will result in the second one failing, which this library translates to an exception.
63
+ # If you want the second instance to take over, you need both
64
+ # `allow_replacement: true` and `replace_existing: true.`
65
+ #
58
66
  # @param name [BusName] the requested name
59
- # @param flags [Integer] TODO: explain and add a better non-numeric API for this
60
- # @raise NameRequestError if we could not get the name
61
- # @example Usage
67
+ # @param replace_existing [Boolean]
68
+ # Replace an existing owner of the name, if that owner set *allow_replacement*.
69
+ # @param allow_replacement [Boolean]
70
+ # Other connections that specify *replace_existing* will be able to take
71
+ # the name from us. We will get {#on_name_lost NameLost}. If we specified *queue*
72
+ # we may get the name again, with {#on_name_acquired NameAcquired}.
73
+ # @param queue [Boolean]
74
+ # Affects the behavior when the bus denies the name (sooner or later).
75
+ # - If `false` (default), it is recommended to let the `NameRequestError` fall through and end your program.
76
+ # - If `true`, you should `rescue` the `NameRequestError` and set up
77
+ # {#on_name_acquired NameAcquired} and {#on_name_lost NameLost} handlers.
78
+ # Meanwhile, the bus will put us in a queue waiting for *name* (this is the "sooner" case).
79
+ # Also, if we had `allow_replacement: true`, another connection can cause us
80
+ # to lose the name. We will be moved back to the queue, waiting for when the other owners give up
81
+ # (the "later" case).
82
+ # @param flags [Integer,nil]
83
+ # If specified, overrides the boolean parameters.
84
+ # Use a bitwise sum `|` of:
85
+ # - NAME_FLAG_ALLOW_REPLACEMENT
86
+ # - NAME_FLAG_REPLACE_EXISTING
87
+ # - NAME_FLAG_DO_NOT_QUEUE
88
+ # Note that `0` implies `queue: true`.
89
+ #
90
+ # @return [REQUEST_NAME_REPLY_PRIMARY_OWNER,REQUEST_NAME_REPLY_ALREADY_OWNER] on success
91
+ # @raise [NameRequestError] with #error_code REQUEST_NAME_REPLY_EXISTS or REQUEST_NAME_REPLY_IN_QUEUE, on failure
92
+ # @raise DBus::Error another way to fail is being prohibited to own the name
93
+ # which is the default on the system bus
94
+ #
95
+ # @see https://dbus.freedesktop.org/doc/dbus-specification.html#bus-messages-request-name
96
+ #
97
+ # @example Simple usage
62
98
  # bus = DBus.session_bus
63
99
  # bus.object_server.export(DBus::Object.new("/org/example/Test"))
64
100
  # bus.request_name("org.example.Test")
65
- # @see https://dbus.freedesktop.org/doc/dbus-specification.html#bus-messages-request-name
66
- def request_name(name, flags: 0)
101
+ # # main loop
102
+ #
103
+ # @example Second instance taking over
104
+ # bus = DBus.session_bus
105
+ # bus.object_server.export(DBus::Object.new("/org/example/Test"))
106
+ # bus.on_name_lost { exit }
107
+ # bus.request_name("org.example.Test", allow_replacement: true, replace_existing: true)
108
+ # # main loop
109
+ #
110
+ # @example Second instance waiting for its turn
111
+ # bus = DBus.session_bus
112
+ # bus.object_server.export(DBus::Object.new("/org/example/Test"))
113
+ # bus.on_name_acquired { @owner = true }
114
+ # begin
115
+ # bus.request_name("org.example.Test", queue: true)
116
+ # rescue DBus::Connection::NameRequestError => e
117
+ # @owner = false
118
+ # end
119
+ # # main loop
120
+ def request_name(name,
121
+ allow_replacement: false,
122
+ replace_existing: false,
123
+ queue: false,
124
+ flags: nil)
125
+ if flags.nil?
126
+ flags = (allow_replacement ? NAME_FLAG_ALLOW_REPLACEMENT : 0) |
127
+ (replace_existing ? NAME_FLAG_REPLACE_EXISTING : 0) |
128
+ (queue ? 0 : NAME_FLAG_DO_NOT_QUEUE)
129
+ end
67
130
  name = BusName.new(name)
68
131
  r = proxy.RequestName(name, flags).first
69
132
  handle_return_of_request_name(r, name)
70
133
  end
71
134
 
135
+ # The caller has released his claim on the given name.
136
+ # Either the caller was the primary owner of the name, and the name is now unused
137
+ # or taken by somebody waiting in the queue for the name,
138
+ # or the caller was waiting in the queue for the name and has now been removed from the queue.
139
+ RELEASE_NAME_REPLY_RELEASED = 1
140
+ # The given name does not exist on this bus.
141
+ RELEASE_NAME_REPLY_NON_EXISTENT = 2
142
+ # The caller was not the primary owner of this name, and was also not waiting in the queue to own this name.
143
+ RELEASE_NAME_REPLY_NOT_OWNER = 3
144
+
145
+ # @param name [BusName] the name to release
146
+ def release_name(name)
147
+ name = BusName.new(name)
148
+ proxy.ReleaseName(name).first
149
+ end
150
+
151
+ def on_name_acquired(&handler)
152
+ proxy.on_signal("NameAcquired", &handler)
153
+ end
154
+
155
+ def on_name_lost(&handler)
156
+ proxy.on_signal("NameLost", &handler)
157
+ end
158
+
72
159
  # Asks bus to send us messages matching mr, and execute slot when
73
160
  # received
74
161
  # @param match_rule [MatchRule,#to_s]
@@ -153,17 +153,30 @@ module DBus
153
153
 
154
154
  # Exception raised when a service name is requested that is not available.
155
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
156
165
  end
157
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
158
173
  def handle_return_of_request_name(ret, name)
159
- details = if ret == REQUEST_NAME_REPLY_IN_QUEUE
160
- other = proxy.GetNameOwner(name).first
161
- other_creds = proxy.GetConnectionCredentials(other).first
162
- "already owned by #{other}, #{other_creds.inspect}"
163
- else
164
- "error code #{ret}"
165
- end
166
- raise NameRequestError, "Could not request #{name}, #{details}" unless ret == REQUEST_NAME_REPLY_PRIMARY_OWNER
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
167
180
 
168
181
  ret
169
182
  end
data/lib/dbus/object.rb CHANGED
@@ -156,18 +156,32 @@ module DBus
156
156
  dbus_accessor(ruby_name, type, dbus_name: dbus_name, emits_changed_signal: emits_changed_signal)
157
157
  end
158
158
 
159
+ # A read-only property accessing a read-write instance variable.
160
+ # A combination of `attr_accessor` and {.dbus_reader}.
161
+ #
162
+ # @param (see .dbus_attr_accessor)
163
+ # @return (see .dbus_attr_accessor)
164
+ def self.dbus_reader_attr_accessor(ruby_name, type, dbus_name: nil, emits_changed_signal: nil)
165
+ attr_accessor(ruby_name)
166
+
167
+ dbus_reader(ruby_name, type, dbus_name: dbus_name, emits_changed_signal: emits_changed_signal)
168
+ end
169
+
159
170
  # A read-only property accessing an instance variable.
160
171
  # A combination of `attr_reader` and {.dbus_reader}.
161
172
  #
173
+ # You may be instead looking for a variant which is read-write from the Ruby side:
174
+ # {.dbus_reader_attr_accessor}.
175
+ #
162
176
  # Whenever the property value gets changed from "inside" the object,
163
177
  # you should emit the `PropertiesChanged` signal by calling
164
178
  # {#dbus_properties_changed}.
165
179
  #
166
- # dbus_properties_changed(interface_name, {dbus_name.to_s => value}, [])
180
+ # dbus_properties_changed(interface_name, {dbus_name.to_s => value}, [])
167
181
  #
168
182
  # or, omitting the value in the signal,
169
183
  #
170
- # dbus_properties_changed(interface_name, {}, [dbus_name.to_s])
184
+ # dbus_properties_changed(interface_name, {}, [dbus_name.to_s])
171
185
  #
172
186
  # @param (see .dbus_attr_accessor)
173
187
  # @return (see .dbus_attr_accessor)
@@ -213,18 +227,22 @@ module DBus
213
227
  # implement it with a read-write attr_accessor. In that case this method
214
228
  # uses {.dbus_watcher} to set up the PropertiesChanged signal.
215
229
  #
216
- # attr_accessor :foo_bar
217
- # dbus_reader :foo_bar, "s"
230
+ # attr_accessor :foo_bar
231
+ # dbus_reader :foo_bar, "s"
232
+ #
233
+ # The above two declarations have a shorthand:
234
+ #
235
+ # dbus_reader_attr_accessor :foo_bar, "s"
218
236
  #
219
237
  # If the property value should change by other means than its attr_writer,
220
238
  # you should emit the `PropertiesChanged` signal by calling
221
239
  # {#dbus_properties_changed}.
222
240
  #
223
- # dbus_properties_changed(interface_name, {dbus_name.to_s => value}, [])
241
+ # dbus_properties_changed(interface_name, {dbus_name.to_s => value}, [])
224
242
  #
225
243
  # or, omitting the value in the signal,
226
244
  #
227
- # dbus_properties_changed(interface_name, {}, [dbus_name.to_s])
245
+ # dbus_properties_changed(interface_name, {}, [dbus_name.to_s])
228
246
  #
229
247
  # @param (see .dbus_attr_accessor)
230
248
  # @return (see .dbus_attr_accessor)
@@ -21,7 +21,6 @@ describe DBus::BusConnection do
21
21
  end
22
22
 
23
23
  context "when the name is taken already", tag_service: true do
24
- # formerly it returned Service, now ObjectServer takes its role
25
24
  it "raises NameRequestError... too late" do
26
25
  name = "org.ruby.service"
27
26
  expect do
@@ -50,21 +49,35 @@ describe DBus::BusConnection do
50
49
 
51
50
  describe "#request_name", tag_bus: true do
52
51
  context "when the name request succeeds" do
53
- it "returns something which can export objects" do
52
+ it "returns a success code" do
54
53
  name = "org.rubygems.ruby_dbus.RequestNameTest"
55
- expect { bus.request_name(name) }.to_not raise_error
56
- bus.proxy.ReleaseName(name)
54
+ expect(bus.request_name(name)).to eq DBus::Connection::REQUEST_NAME_REPLY_PRIMARY_OWNER
55
+ # second time, considered also a success
56
+ expect(bus.request_name(name)).to eq DBus::Connection::REQUEST_NAME_REPLY_ALREADY_OWNER
57
+ bus.release_name(name)
57
58
  end
58
59
  end
59
60
 
60
61
  context "when the name is taken already", tag_service: true do
61
- # formerly it returned Service, now ObjectServer takes its role
62
62
  it "raises NameRequestError" do
63
63
  name = "org.ruby.service"
64
64
  expect do
65
- # flags: avoid getting the name sometime later, unexpectedly
66
- bus.request_name(name, flags: DBus::Connection::NAME_FLAG_DO_NOT_QUEUE)
65
+ bus.request_name(name)
66
+ end.to raise_error(DBus::Connection::NameRequestError)
67
+ end
68
+ end
69
+
70
+ context "when the name is taken already but we request queuing", tag_service: true do
71
+ it "raises NameRequestError but we are queued" do
72
+ name = "org.ruby.service"
73
+ owning = nil
74
+ # TODO: we do not expect the handlers to run
75
+ bus.on_name_acquired { owning = true }
76
+ bus.on_name_lost { owning = false }
77
+ expect do
78
+ bus.request_name(name, queue: true)
67
79
  end.to raise_error(DBus::Connection::NameRequestError)
80
+ expect(bus.release_name(name)).to eq DBus::BusConnection::RELEASE_NAME_REPLY_RELEASED
68
81
  end
69
82
  end
70
83
 
@@ -23,7 +23,7 @@ class TestChild < DBus::Object
23
23
  end
24
24
 
25
25
  dbus_interface "org.ruby.TestChild" do
26
- dbus_attr_reader :name, "s"
26
+ dbus_reader_attr_accessor :name, "s"
27
27
  end
28
28
  end
29
29
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-dbus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.23.0.beta2
4
+ version: 0.23.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ruby DBus Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-23 00:00:00.000000000 Z
11
+ date: 2023-10-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rexml
@@ -235,9 +235,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
235
235
  version: 2.4.0
236
236
  required_rubygems_version: !ruby/object:Gem::Requirement
237
237
  requirements:
238
- - - ">"
238
+ - - ">="
239
239
  - !ruby/object:Gem::Version
240
- version: 1.3.1
240
+ version: '0'
241
241
  requirements: []
242
242
  rubygems_version: 3.3.26
243
243
  signing_key: