@homebridge/dbus-native 0.4.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.
@@ -0,0 +1,203 @@
1
+ const constants = require('./constants');
2
+ const parseSignature = require('./signature');
3
+
4
+ // TODO: use xmlbuilder
5
+
6
+ var xmlHeader =
7
+ '<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"\n' +
8
+ ' "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">';
9
+ var stdIfaces;
10
+
11
+ module.exports = function(msg, bus) {
12
+ if (
13
+ msg['interface'] === 'org.freedesktop.DBus.Introspectable' &&
14
+ msg.member === 'Introspect'
15
+ ) {
16
+ if (msg.path === '/') msg.path = '';
17
+
18
+ var resultXml = [xmlHeader];
19
+ var nodes = {};
20
+ // TODO: this is not very efficiant for large number of exported objects
21
+ // need to build objects tree as they are exported and walk this tree on introspect request
22
+ for (var path in bus.exportedObjects) {
23
+ if (path.indexOf(msg.path) === 0) {
24
+ // objects path starts with requested
25
+ var introspectableObj = bus.exportedObjects[msg.path];
26
+ if (introspectableObj) {
27
+ nodes[msg.path] = introspectableObj;
28
+ } else {
29
+ if (path[msg.path.length] !== '/') continue;
30
+ var localPath = path.substr(msg.path.length);
31
+ var pathParts = localPath.split('/');
32
+ var localName = pathParts[1];
33
+ nodes[localName] = null;
34
+ }
35
+ }
36
+ }
37
+
38
+ var length = Object.keys(nodes).length;
39
+ if (length === 0) {
40
+ resultXml.push('<node/>');
41
+ } else if (length === 1) {
42
+ var obj = nodes[Object.keys(nodes)[0]];
43
+ if (obj) {
44
+ resultXml.push('<node>');
45
+ for (var ifaceNode in obj) {
46
+ resultXml.push(interfaceToXML(obj[ifaceNode][0]));
47
+ }
48
+ resultXml.push(stdIfaces);
49
+ resultXml.push('</node>');
50
+ } else {
51
+ resultXml.push(
52
+ `<node>\n <node name="${Object.keys(nodes)[0]}"/>\n </node>`
53
+ );
54
+ }
55
+ } else {
56
+ resultXml.push('<node>');
57
+ for (var name in nodes) {
58
+ if (nodes[name] === null) {
59
+ resultXml.push(` <node name="${name}" />`);
60
+ } else {
61
+ obj = nodes[name];
62
+ resultXml.push(` <node name="${name}" >`);
63
+ for (var ifaceName in obj) {
64
+ resultXml.push(interfaceToXML(obj[ifaceName][0]));
65
+ }
66
+ resultXml.push(stdIfaces);
67
+ resultXml.push(' </node>');
68
+ }
69
+ }
70
+ resultXml.push('</node>');
71
+ }
72
+
73
+ const introspectableReply = {
74
+ type: constants.messageType.methodReturn,
75
+ serial: bus.serial++,
76
+ replySerial: msg.serial,
77
+ destination: msg.sender,
78
+ signature: 's',
79
+ body: [resultXml.join('\n')]
80
+ };
81
+ bus.connection.message(introspectableReply);
82
+ return 1;
83
+ } else if (msg['interface'] === 'org.freedesktop.DBus.Properties') {
84
+ var interfaceName = msg.body[0];
85
+ var propertiesObj = bus.exportedObjects[msg.path];
86
+ // TODO: !propertiesObj -> UnknownObject http://www.freedesktop.org/wiki/Software/DBusBindingErrors
87
+ if (!propertiesObj || !propertiesObj[interfaceName]) {
88
+ // TODO:
89
+ bus.sendError(
90
+ msg,
91
+ 'org.freedesktop.DBus.Error.UnknownMethod',
92
+ 'Uh oh oh'
93
+ );
94
+ return 1;
95
+ }
96
+ var impl = propertiesObj[interfaceName][1];
97
+
98
+ const propertiesReply = {
99
+ type: constants.messageType.methodReturn,
100
+ serial: bus.serial++,
101
+ replySerial: msg.serial,
102
+ destination: msg.sender
103
+ };
104
+ if (msg.member === 'Get' || msg.member === 'Set') {
105
+ var propertyName = msg.body[1];
106
+ var propType = propertiesObj[interfaceName][0].properties[propertyName];
107
+ if (msg.member === 'Get') {
108
+ var propValue = impl[propertyName];
109
+ propertiesReply.signature = 'v';
110
+ propertiesReply.body = [[propType, propValue]];
111
+ } else {
112
+ impl[propertyName] = 1234; // TODO: read variant and set property value
113
+ }
114
+ } else if (msg.member === 'GetAll') {
115
+ propertiesReply.signature = 'a{sv}';
116
+ var props = [];
117
+ for (var p in propertiesObj[interfaceName][0].properties) {
118
+ var propertySignature = propertiesObj[interfaceName][0].properties[p];
119
+ props.push([p, [propertySignature, impl[p]]]);
120
+ }
121
+ propertiesReply.body = [props];
122
+ }
123
+ bus.connection.message(propertiesReply);
124
+ return 1;
125
+ } else if (msg['interface'] === 'org.freedesktop.DBus.Peer') {
126
+ // TODO: implement bus.replyTo(srcMsg, signature, body) method
127
+ const peerReply = {
128
+ type: constants.messageType.methodReturn,
129
+ serial: bus.serial++,
130
+ replySerial: msg.serial,
131
+ destination: msg.sender
132
+ };
133
+ if (msg.member === 'Ping') {
134
+ // empty body
135
+ } else if (msg.member === 'GetMachineId') {
136
+ peerReply.signature = 's';
137
+ peerReply.body = ['This is a machine id. TODO: implement'];
138
+ }
139
+ bus.connection.message(peerReply);
140
+ return 1;
141
+ }
142
+ return 0;
143
+ };
144
+
145
+ // TODO: move to introspect.js
146
+ function interfaceToXML(iface) {
147
+ var result = [];
148
+ var dumpArgs = function(argsSignature, argsNames, direction) {
149
+ if (!argsSignature) return;
150
+ var args = parseSignature(argsSignature);
151
+ args.forEach(function(arg, num) {
152
+ var argName = argsNames ? argsNames[num] : direction + num;
153
+ var dirStr = direction === 'signal' ? '' : `" direction="${direction}`;
154
+ result.push(
155
+ ` <arg type="${dumpSignature([arg])}" name="${argName}${
156
+ dirStr
157
+ }" />`
158
+ );
159
+ });
160
+ };
161
+ result.push(` <interface name="${iface.name}">`);
162
+ if (iface.methods) {
163
+ for (var methodName in iface.methods) {
164
+ var method = iface.methods[methodName];
165
+ result.push(` <method name="${methodName}">`);
166
+ dumpArgs(method[0], method[2], 'in');
167
+ dumpArgs(method[1], method[3], 'out');
168
+ result.push(' </method>');
169
+ }
170
+ }
171
+ if (iface.signals) {
172
+ for (var signalName in iface.signals) {
173
+ var signal = iface.signals[signalName];
174
+ result.push(` <signal name="${signalName}">`);
175
+ dumpArgs(signal[0], signal.slice(1), 'signal');
176
+ result.push(' </signal>');
177
+ }
178
+ }
179
+ if (iface.properties) {
180
+ for (const propertyName in iface.properties) {
181
+ // TODO: decide how to encode access
182
+ result.push(
183
+ ` <property name="${propertyName}" type="${
184
+ iface.properties[propertyName]
185
+ }" access="readwrite"/>`
186
+ );
187
+ }
188
+ }
189
+ result.push(' </interface>');
190
+ return result.join('\n');
191
+ }
192
+
193
+ function dumpSignature(s) {
194
+ var result = [];
195
+ s.forEach(function(sig) {
196
+ result.push(sig.type + dumpSignature(sig.child));
197
+ if (sig.type === '{') result.push('}');
198
+ if (sig.type === '(') result.push(')');
199
+ });
200
+ return result.join('');
201
+ }
202
+ stdIfaces =
203
+ ' <interface name="org.freedesktop.DBus.Properties">\n <method name="Get">\n <arg type="s" name="interface_name" direction="in"/>\n <arg type="s" name="property_name" direction="in"/>\n <arg type="v" name="value" direction="out"/>\n </method>\n <method name="GetAll">\n <arg type="s" name="interface_name" direction="in"/>\n <arg type="a{sv}" name="properties" direction="out"/>\n </method>\n <method name="Set">\n <arg type="s" name="interface_name" direction="in"/>\n <arg type="s" name="property_name" direction="in"/>\n <arg type="v" name="value" direction="in"/>\n </method>\n <signal name="PropertiesChanged">\n <arg type="s" name="interface_name"/>\n <arg type="a{sv}" name="changed_properties"/>\n <arg type="as" name="invalidated_properties"/>\n </signal>\n </interface>\n <interface name="org.freedesktop.DBus.Introspectable">\n <method name="Introspect">\n <arg type="s" name="xml_data" direction="out"/>\n </method>\n </interface>\n <interface name="org.freedesktop.DBus.Peer">\n <method name="Ping"/>\n <method name="GetMachineId">\n <arg type="s" name="machine_uuid" direction="out"/>\n </method>\n </interface>';
@@ -0,0 +1,9 @@
1
+ const Buffer = require('safe-buffer').Buffer;
2
+ const DBusBuffer = require('./dbus-buffer');
3
+
4
+ module.exports = function unmarshall(buffer, signature, startPos, options) {
5
+ if (!startPos) startPos = 0;
6
+ if (signature === '') return Buffer.from('');
7
+ var dbuff = new DBusBuffer(buffer, startPos, options);
8
+ return dbuff.read(signature);
9
+ };
package/package.json ADDED
@@ -0,0 +1,90 @@
1
+ {
2
+ "name": "@homebridge/dbus-native",
3
+ "author": "Andrey Sidorov <sidorares@yandex.com>",
4
+ "version": "0.4.0",
5
+ "keywords": [
6
+ "dbus",
7
+ "dcop",
8
+ "d-bus",
9
+ "rpc",
10
+ "gnome",
11
+ "kde"
12
+ ],
13
+ "description": "D-bus protocol implementation in native javascript",
14
+ "files": [
15
+ "bin/dbus2js.js",
16
+ "lib/*",
17
+ "index.js",
18
+ "package.json"
19
+ ],
20
+ "directories": {
21
+ "lib": "lib",
22
+ "test": "test",
23
+ "examples": "examples"
24
+ },
25
+ "main": "index.js",
26
+ "maintainers": [
27
+ {
28
+ "name": "Andrey Sidorov",
29
+ "email": "sidoares@yandex.ru"
30
+ }
31
+ ],
32
+ "license": "MIT",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "https://github.com/homebridge/dbus-native.git"
36
+ },
37
+ "bin": {
38
+ "dbus2js": "./bin/dbus2js.js"
39
+ },
40
+ "dependencies": {
41
+ "event-stream": "^4.0.0",
42
+ "hexy": "^0.2.10",
43
+ "long": "^4.0.0",
44
+ "optimist": "^0.6.1",
45
+ "put": "0.0.6",
46
+ "safe-buffer": "^5.1.1",
47
+ "xml2js": "^0.4.17"
48
+ },
49
+ "uncomment": {
50
+ "optionalDependencies": {
51
+ "abstract-socket": "^2.0.0"
52
+ }
53
+ },
54
+ "devDependencies": {
55
+ "eslint": "^5.0.0",
56
+ "eslint-config-prettier": "^3.0.0",
57
+ "eslint-plugin-markdown": "^1.0.0-beta.6",
58
+ "eslint-plugin-prettier": "^3.0.0",
59
+ "husky": "^1.0.0",
60
+ "lint-staged": "^8.0.0",
61
+ "mocha": "*",
62
+ "prettier": "^1.7.4"
63
+ },
64
+ "scripts": {
65
+ "lint": "npm run lint:docs && npm run lint:code",
66
+ "lint:code": "eslint index.js 'bin/*.js' 'lib/**/*.js' 'test/**/*.js'",
67
+ "lint:docs": "eslint 'examples/**/*.js'",
68
+ "test": "npm run lint && npm run test:raw",
69
+ "test:raw": "mocha",
70
+ "prettier": "prettier --write index.js '{bin,lib,examples,test}/**/*.js'",
71
+ "prettier:docs": "prettier-markdown README.md",
72
+ "eslint-check": "eslint --print-config .eslintrc | eslint-config-prettier-check",
73
+ "precommit": "lint-staged",
74
+ "prepublish": "npm prune"
75
+ },
76
+ "lint-staged": {
77
+ "*.js": [
78
+ "prettier --write",
79
+ "git add"
80
+ ]
81
+ },
82
+ "prettier": {
83
+ "semi": true,
84
+ "singleQuote": true,
85
+ "trailingComma": "none"
86
+ },
87
+ "engine": {
88
+ "node": ">=8.0"
89
+ }
90
+ }