Skip to content

Commit 2280d4e

Browse files
author
Tony Crisci
committed
Expose the low-level api
fixes #20
1 parent 5234d19 commit 2280d4e

File tree

8 files changed

+163
-59
lines changed

8 files changed

+163
-59
lines changed

README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,47 @@ To emit a signal, just call the method marked with the `signal` decorator and th
169169

170170
If you have an interface xml description, which can be gotten from the `org.freedesktop.DBus.Introspect` method on an exported interface, you can generate dbus-next JavaScript classes from the xml file with the `bin/generate-interfaces.js` utility.
171171

172+
## The Low-Level Interface
173+
174+
The low-level interface can be used to interact with messages directly. Create new messages with the `Message` class to be sent on the bus as method calls, signals, method returns, or errors. Method calls can be called with the `call()` method of the `MessageBus` to await a reply and `send()` can be use for messages that don't expect a reply.
175+
176+
```js
177+
let dbus = require('dbus-next');
178+
let Message = dbus.Message;
179+
180+
let bus = dbus.sessionBus();
181+
182+
// send a method call to list the names on the bus
183+
let methodCall = new Message({
184+
destination: 'org.freedesktop.DBus',
185+
path: '/org/freedesktop/DBus',
186+
interface: 'org.freedesktop.DBus',
187+
member: 'ListNames'
188+
});
189+
190+
let reply = await bus.call(message);
191+
console.log('names on the bus: ', reply.body[0]);
192+
193+
// add a custom handler for a particular method
194+
bus.addMethodHandler((msg) => {
195+
if (msg.path === '/org/test/path' &&
196+
msg.interface === 'org.test.interface'
197+
&& msg.member === 'SomeMethod') {
198+
// handle the method by sending a reply
199+
let someMethodReply = Message.newMethodReturn(msg, 's', ['hello']);
200+
bus.send(someMethodReply);
201+
return true;
202+
}
203+
});
204+
205+
// listen to any messages that are sent to the bus
206+
bus.on('message', (msg) => {
207+
console.log('got a message: ', msg);
208+
});
209+
```
210+
211+
For a complete example of how to use the low-level interface to send messages, see the `dbus-next-send.js` script in the `bin` directory.
212+
172213
## Contributing
173214

174215
Contributions are welcome. Development happens on [Github](https://github.com/acrisci/node-dbus-next).

bin/dbus-next-send.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ let message = new Message({
128128
});
129129

130130
if (type === MESSAGE_TYPE_METHOD_CALL) {
131-
bus._call(message)
131+
bus.call(message)
132132
.then((reply) => {
133133
console.log(JSON.stringify(reply, null, 2));
134134
process.exit(0);
@@ -138,6 +138,6 @@ if (type === MESSAGE_TYPE_METHOD_CALL) {
138138
process.exit(1);
139139
});
140140
} else {
141-
bus._send(message);
141+
bus.send(message);
142142
process.exit(0);
143143
}

lib/bus.js

Lines changed: 81 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,13 @@ let { Interface } = require('./service/interface');
2424
* created with `dbus.sessionBus()` or `dbus.systemBus()` methods of the
2525
* dbus-next module.
2626
*
27-
* The `MessageBus` is an `EventEmitter` which may receive an `error` event
28-
* with the underlying connection error as the argument. After receiving an
29-
* `error` event, the `MessageBus` may be disconnected.
27+
* The `MessageBus` is an `EventEmitter` which emits the following events:
28+
* * `error` - The underlying connection to the bus has errored. After
29+
* receiving an `error` event, the `MessageBus` may be disconnected.
30+
* * `connected` - The bus is connected and ready to send and receive messages.
31+
* Before this event, messages are buffered.
32+
* * `message` - The bus has received a message. Called with the {@link
33+
* Message} that was received. This is part of the low-level api.
3034
*
3135
* @example
3236
* const dbus = require('dbus-next');
@@ -103,7 +107,7 @@ class MessageBus extends EventEmitter {
103107
}
104108

105109
if (!handled) {
106-
this._send(Message.newError(msg,
110+
this.send(Message.newError(msg,
107111
'org.freedesktop.DBus.Error.UnknownMethod',
108112
`Method '${msg.member}' on interface '${msg.interface || '(none)'}' does not exist`));
109113
}
@@ -116,7 +120,7 @@ class MessageBus extends EventEmitter {
116120
this.emit('message', msg);
117121
handleMessage(msg);
118122
} catch (e) {
119-
this._send(Message.newError(msg, 'com.github.dbus_next.Error', `The DBus library encountered an error.\n${e.stack}`));
123+
this.send(Message.newError(msg, 'com.github.dbus_next.Error', `The DBus library encountered an error.\n${e.stack}`));
120124
}
121125
});
122126

@@ -132,7 +136,7 @@ class MessageBus extends EventEmitter {
132136
member: 'Hello'
133137
});
134138

135-
this._call(helloMessage)
139+
this.call(helloMessage)
136140
.then((msg) => {
137141
this.name = msg.body[0];
138142
// TODO document this signal
@@ -145,9 +149,9 @@ class MessageBus extends EventEmitter {
145149
}
146150

147151
/**
148-
* Get a `ProxyObject` on the bus for the given name and path for interacting
152+
* Get a {@link ProxyObject} on the bus for the given name and path for interacting
149153
* with a service as a client. The proxy object contains a list of the
150-
* `ProxyInterface`s exported at the name and object path as well as a list
154+
* [`ProxyInterface`s]{@link ProxyInterface} exported at the name and object path as well as a list
151155
* of `node`s.
152156
*
153157
* @param name {string} - the well-known name on the bus.
@@ -187,7 +191,7 @@ class MessageBus extends EventEmitter {
187191
signature: 'su',
188192
body: [name, flags]
189193
});
190-
this._call(requestNameMessage)
194+
this.call(requestNameMessage)
191195
.then((msg) => {
192196
let result = msg.body[0];
193197
if (result === constants.DBUS_REQUEST_NAME_REPLY_EXISTS) {
@@ -215,33 +219,81 @@ class MessageBus extends EventEmitter {
215219
this._connection.stream.end();
216220
}
217221

218-
_newSerial() {
222+
/**
223+
* Get a new serial for this bus. These can be used to set the {@link
224+
* Message#serial} member to send the message on this bus.
225+
*
226+
* @returns {int} - A new serial for this bus.
227+
*/
228+
newSerial() {
219229
return this._serial++;
220230
}
221231

222-
_addMethodHandler(fn) {
232+
/**
233+
* A function to call when a message of type {@link
234+
* MESSAGE_TYPE_METHOD_RETURN} is received. User handlers are run before
235+
* default handlers.
236+
*
237+
* @callback methodHandler
238+
* @param {Message} msg - The message to handle.
239+
* @returns {boolean} Return `true` if the message is handled and no further
240+
* handlers will run.
241+
*/
242+
243+
/**
244+
* Add a user method return handler. Remove the handler with {@link
245+
* MessageBus#removeMethodHandler}
246+
*
247+
* @param {methodHandler} - A function to handle a {@link Message} of type
248+
* {@link MESSAGE_TYPE_METHOD_RETURN}. Takes the `Message` as the first
249+
* argument. Return `true` if the method is handled and no further handlers
250+
* will run.
251+
*/
252+
addMethodHandler(fn) {
223253
this._methodHandlers.push(fn);
224254
}
225255

226-
_removeMethodHandler(fn) {
256+
/**
257+
* Remove a user method return handler that was previously added with {@link
258+
* MessageBus#addMethodHandler}.
259+
*
260+
* @param {methodHandler} - A function that was previously added as a method handler with {@link
261+
*/
262+
removeMethodHandler(fn) {
227263
for (let i = 0; i < this._methodHandlers.length; ++i) {
228264
if (this._methodHandlers[i] === fn) {
229265
this._methodHandlers.splice(i, 1);
230266
}
231267
}
232268
}
233269

234-
_call(msg) {
270+
/**
271+
* Send a {@link Message} of type {@link MESSAGE_TYPE_METHOD_CALL} to the bus
272+
* and wait for the reply.
273+
*
274+
* @example
275+
* let message = new Message({
276+
* destination: 'org.freedesktop.DBus',
277+
* path: '/org/freedesktop/DBus',
278+
* interface: 'org.freedesktop.DBus',
279+
* member: 'ListNames'
280+
* });
281+
* let reply = await bus.call(message);
282+
*
283+
* @param {Message} msg - The message to send. Must be a METHOD_CALL.
284+
* @returns {Promise} reply - A `Promise` that resolves to the `Message`
285+
* which is a reply to the call.
286+
*/
287+
call(msg) {
235288
return new Promise((resolve, reject) => {
236-
// TODO: if the NO_REPLY_EXPECTED flag is set, resolve immediately after sending the message.
237289
if (!(msg instanceof Message)) {
238290
throw new Error('The call() method takes a Message class as the first argument.');
239291
}
240292
if (msg.type !== constants.messageType.METHOD_CALL) {
241293
throw new Error('Only messages of type METHOD_CALL can expect a call reply.');
242294
}
243295
if (msg.serial === null || msg._sent) {
244-
msg.serial = this._newSerial();
296+
msg.serial = this.newSerial();
245297
}
246298
msg._sent = true;
247299
if (msg.flags & constants.flags.noReplyExpected) {
@@ -260,12 +312,23 @@ class MessageBus extends EventEmitter {
260312
});
261313
};
262314

263-
_send(msg) {
315+
/**
316+
* Send a {@link Message} on the bus that does not expect a reply.
317+
*
318+
* @example
319+
* let message = Message.newSignal('/org/test/path/,
320+
* 'org.test.interface',
321+
* 'SomeSignal');
322+
* bus.send(message);
323+
*
324+
* @param {Message} msg - The message to send.
325+
*/
326+
send(msg) {
264327
if (!(msg instanceof Message)) {
265328
throw new Error('The send() method takes a Message class as the first argument.');
266329
}
267330
if (msg.serial === null || msg._sent) {
268-
msg.serial = this._newSerial();
331+
msg.serial = this.newSerial();
269332
}
270333
this._connection.message(msg);
271334
}
@@ -279,7 +342,7 @@ class MessageBus extends EventEmitter {
279342
signature: 's',
280343
body: [match]
281344
});
282-
return this._call(msg);
345+
return this.call(msg);
283346
};
284347
};
285348

lib/client/proxy-object.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ class ProxyObject {
142142
body: []
143143
});
144144

145-
this.bus._call(introspectMessage)
145+
this.bus.call(introspectMessage)
146146
.then((msg) => {
147147
let xml = msg.body[0];
148148
this._parser.parseString(xml, (err, data) => {
@@ -172,7 +172,7 @@ class ProxyObject {
172172
body: args
173173
});
174174

175-
this.bus._call(methodCallMessage)
175+
this.bus.call(methodCallMessage)
176176
.then((msg) => {
177177
let outSignatureTree = parseSignature(outSignature);
178178
if (outSignatureTree.length === 0) {

0 commit comments

Comments
 (0)