Skip to content

Commit 142ea69

Browse files
committed
Throw or return errors on disconnected connection
When an operation is attempted on a closed connection, throw a Node-level error instead of allowing the C++ to surface an error. In order to do this, we keep track of whether a bus is still connected or whether it has already been disconnected. serviceInterface.emitSignal does not have a callback and will throw an error if the connection is already disconnected. All other methods that try to use a disconnected connection will return the error in the callback.
1 parent 4e93c4d commit 142ea69

File tree

6 files changed

+126
-0
lines changed

6 files changed

+126
-0
lines changed

lib/bus.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ var Bus = module.exports = function(dbus, busName) {
5151

5252
util.inherits(Bus, events.EventEmitter);
5353

54+
Object.defineProperty(Bus.prototype, 'connected', {
55+
get: function() {
56+
return this.connection !== null;
57+
}
58+
});
59+
5460
Bus.prototype.disconnect = function(callback) {
5561
var self = this;
5662

@@ -97,6 +103,13 @@ Bus.prototype.reconnect = function(callback) {
97103
Bus.prototype.introspect = function(serviceName, objectPath, callback) {
98104
var self = this;
99105

106+
if (!self.connected) {
107+
process.nextTick(function() {
108+
callback(new Error('Bus is no longer connected'));
109+
});
110+
return;
111+
}
112+
100113
// Getting scheme of specific object
101114
self.dbus.callMethod(self.connection,
102115
serviceName,

lib/interface.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ var Interface = module.exports = function(bus, serviceName, objectPath, interfac
1515

1616
util.inherits(Interface, events.EventEmitter);
1717

18+
Object.defineProperty(Interface.prototype, 'connected', {
19+
get: function() {
20+
return this.bus.connected;
21+
}
22+
});
23+
1824
Interface.prototype.init = function(callback) {
1925
var self = this;
2026

@@ -48,6 +54,10 @@ Interface.prototype.init = function(callback) {
4854
var error = this[method].error || null
4955

5056
process.nextTick(function() {
57+
if (!self.connected) {
58+
callback(new Error('Bus is no longer connected'));
59+
return;
60+
}
5161

5262
try {
5363
self.bus.dbus.callMethod(self.bus.connection,
@@ -90,6 +100,13 @@ Interface.prototype.init = function(callback) {
90100
Interface.prototype.setProperty = function(propertyName, value, callback) {
91101
var self = this;
92102

103+
if (!self.connected) {
104+
process.nextTick(function() {
105+
callback(new Error('Bus is no longer connected'));
106+
});
107+
return;
108+
}
109+
93110
self.bus.dbus.callMethod(self.bus.connection,
94111
self.serviceName,
95112
self.objectPath,
@@ -108,6 +125,13 @@ Interface.prototype.setProperty = function(propertyName, value, callback) {
108125
Interface.prototype.getProperty = function(propertyName, callback) {
109126
var self = this;
110127

128+
if (!self.connected) {
129+
process.nextTick(function() {
130+
callback(new Error('Bus is no longer connected'));
131+
});
132+
return;
133+
}
134+
111135
self.bus.dbus.callMethod(self.bus.connection,
112136
self.serviceName,
113137
self.objectPath,
@@ -126,6 +150,13 @@ Interface.prototype.getProperty = function(propertyName, callback) {
126150
Interface.prototype.getProperties = function(callback) {
127151
var self = this;
128152

153+
if (!self.connected) {
154+
process.nextTick(function() {
155+
callback(new Error('Bus is no longer connected'));
156+
});
157+
return;
158+
}
159+
129160
self.bus.dbus.callMethod(self.bus.connection,
130161
self.serviceName,
131162
self.objectPath,

lib/service.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ var Service = module.exports = function(bus, serviceName) {
2222

2323
util.inherits(Service, events.EventEmitter);
2424

25+
Object.defineProperty(Service.prototype, 'connected', {
26+
get: function() {
27+
return this.bus.connected;
28+
}
29+
});
30+
2531
Service.prototype.createObject = function(objectPath) {
2632
var self = this;
2733

lib/service_interface.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,11 @@ ServiceInterface.prototype.getProperties = function(callback) {
166166
ServiceInterface.prototype.emitSignal = function() {
167167
var self = this;
168168

169+
var service = self.object.service;
170+
if (!service.connected) {
171+
throw new Error('Service is no longer connected');
172+
}
173+
169174
var conn = self.object.service.bus.connection;
170175
var objPath = self.object.path;
171176
var interfaceName = self.name;
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
var tap = require('tap');
2+
var DBus = require('../');
3+
4+
var dbus = new DBus();
5+
var bus = dbus.getBus('session');
6+
7+
tap.plan(11);
8+
9+
var timeout = setTimeout(function() {
10+
tap.fail('Should have disconnected by now');
11+
process.exit();
12+
}, 1000);
13+
timeout.unref();
14+
15+
tap.ok('This is a dummy test. The real test is whether the tap.fail gets called on the timeout.');
16+
17+
bus.getInterface('org.freedesktop.DBus', '/', 'org.freedesktop.DBus', function(err, iface) {
18+
setTimeout(function() {
19+
bus.disconnect();
20+
}, 50);
21+
22+
setTimeout(function() {
23+
iface.getProperty('Test', function(err, value) {
24+
tap.type(err, Error);
25+
tap.match(err.message, /no.*connected/, 'getProperty returns the correct error');
26+
});
27+
iface.setProperty('Test', 'Value', function(err) {
28+
tap.type(err, Error);
29+
tap.match(err.message, /no.*connected/, 'setProperty returns the correct error');
30+
});
31+
iface.getProperties(function(err, values) {
32+
tap.type(err, Error);
33+
tap.match(err.message, /no.*connected/, 'getProperties returns the correct error');
34+
});
35+
iface.NameHasOwner('Test', function(err, result) {
36+
tap.type(err, Error);
37+
tap.match(err.message, /no.*connected/, 'call returns the correct error');
38+
});
39+
bus.getInterface('org.freedesktop.DBus', '/obj', 'org.freedesktop.DBus', function(err, iface) {
40+
tap.type(err, Error);
41+
tap.match(err.message, /no.*connected/, 'getInterface returns the correct error');
42+
});
43+
}, 100);
44+
});
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
var tap = require('tap');
2+
var DBus = require('../');
3+
4+
tap.plan(2);
5+
6+
var dbus = new DBus();
7+
var service = dbus.registerService('session', 'test.dbus.TestService');
8+
var object = service.createObject('/test/dbus/TestService');
9+
var iface = object.createInterface('test.dbus.TestService.Interface1');
10+
11+
iface.addSignal('Test', { types: [DBus.Define(String)] });
12+
13+
var timeout = setTimeout(function() {
14+
tap.fail('Should have disconnected by now');
15+
process.exit();
16+
}, 1000);
17+
timeout.unref();
18+
19+
tap.ok('This is a dummy test. The real test is whether the tap.fail gets called on the timeout.');
20+
setTimeout(function() {
21+
service.disconnect();
22+
}, 50);
23+
setTimeout(function() {
24+
tap.throws(function() {
25+
iface.emitSignal('Test', 'test');
26+
}, /no.*connected/, 'Emit throws an error after disconnect');
27+
}, 100);

0 commit comments

Comments
 (0)