@lakutata/dbus 2.3.1 → 3.0.0-beta.1
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.
- package/LICENSE +23 -0
- package/README.md +253 -25
- package/dist/cjs/adapters/DBusEntrypoint.d.ts +89 -0
- package/dist/cjs/adapters/DBusEntrypoint.js +280 -0
- package/dist/cjs/channel/DBusChannel.d.ts +36 -0
- package/dist/cjs/channel/DBusChannel.js +70 -0
- package/dist/cjs/components/DBusClientComponent.d.ts +494 -0
- package/dist/cjs/components/DBusClientComponent.js +272 -0
- package/dist/cjs/components/DBusObjectManager.d.ts +164 -0
- package/dist/cjs/components/DBusObjectManager.js +200 -0
- package/dist/cjs/context/DBusContext.d.ts +52 -0
- package/dist/cjs/context/DBusContext.js +68 -0
- package/dist/cjs/decorators/DBusInterface.d.ts +74 -0
- package/dist/cjs/decorators/DBusInterface.js +63 -0
- package/dist/cjs/decorators/DBusMethod.d.ts +115 -0
- package/dist/cjs/decorators/DBusMethod.js +20 -0
- package/dist/cjs/exports/DBus.d.ts +11 -0
- package/dist/cjs/exports/DBus.js +42 -0
- package/dist/cjs/lib/DBusClientOptions.d.ts +30 -0
- package/dist/cjs/lib/Declarations.d.ts +187 -0
- package/dist/cjs/lib/Declarations.js +113 -0
- package/dist/cjs/lib/Names.d.ts +35 -0
- package/dist/cjs/lib/Names.js +80 -0
- package/dist/cjs/lib/Signature.d.ts +14 -0
- package/dist/cjs/lib/Signature.js +53 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/types/DBusContextParams.d.ts +22 -0
- package/dist/cjs/types/DBusContextParams.js +2 -0
- package/dist/esm/adapters/DBusEntrypoint.js +274 -0
- package/dist/esm/channel/DBusChannel.js +67 -0
- package/dist/esm/components/DBusClientComponent.js +267 -0
- package/dist/esm/components/DBusObjectManager.js +197 -0
- package/dist/esm/context/DBusContext.js +64 -0
- package/dist/esm/decorators/DBusInterface.js +60 -0
- package/dist/esm/decorators/DBusMethod.js +17 -0
- package/dist/esm/exports/DBus.js +12 -0
- package/dist/esm/lib/DBusClientOptions.js +1 -0
- package/dist/esm/lib/Declarations.js +107 -0
- package/dist/esm/lib/Names.js +73 -0
- package/dist/esm/lib/Signature.js +49 -0
- package/dist/esm/types/DBusContextParams.js +1 -0
- package/dist/types/adapters/DBusEntrypoint.d.ts +89 -0
- package/dist/types/channel/DBusChannel.d.ts +36 -0
- package/dist/types/components/DBusClientComponent.d.ts +494 -0
- package/dist/types/components/DBusObjectManager.d.ts +164 -0
- package/dist/types/context/DBusContext.d.ts +52 -0
- package/dist/types/decorators/DBusInterface.d.ts +74 -0
- package/dist/types/decorators/DBusMethod.d.ts +115 -0
- package/dist/types/exports/DBus.d.ts +11 -0
- package/dist/types/lib/DBusClientOptions.d.ts +30 -0
- package/dist/types/lib/Declarations.d.ts +187 -0
- package/dist/types/lib/Names.d.ts +35 -0
- package/dist/types/lib/Signature.d.ts +14 -0
- package/dist/types/types/DBusContextParams.d.ts +22 -0
- package/package.json +38 -39
- package/CHANGELOG.md +0 -153
- package/dist/CommonExports.d.ts +0 -2
- package/dist/CommonExports.d.ts.map +0 -1
- package/dist/CommonExports.js +0 -44
- package/dist/ComponentExports.d.ts +0 -2
- package/dist/ComponentExports.d.ts.map +0 -1
- package/dist/ComponentExports.js +0 -5
- package/dist/ProviderExports.d.ts +0 -2
- package/dist/ProviderExports.d.ts.map +0 -1
- package/dist/ProviderExports.js +0 -5
- package/dist/components/DBusClientComponent.d.ts +0 -75
- package/dist/components/DBusClientComponent.d.ts.map +0 -1
- package/dist/components/DBusClientComponent.js +0 -125
- package/dist/interfaces/DBusClientOptions.d.ts +0 -7
- package/dist/interfaces/DBusClientOptions.d.ts.map +0 -1
- package/dist/providers/DBusClientProvider.d.ts +0 -75
- package/dist/providers/DBusClientProvider.d.ts.map +0 -1
- package/dist/providers/DBusClientProvider.js +0 -125
- package/dist/tests/DBusTest.spec.d.ts +0 -2
- package/dist/tests/DBusTest.spec.d.ts.map +0 -1
- package/dist/tests/DBusTest.spec.js +0 -26
- package/dist/tests/Test.d.ts +0 -9
- package/dist/tests/Test.d.ts.map +0 -1
- package/dist/tests/Test.js +0 -80
- package/tsconfig.json +0 -7
- /package/dist/{interfaces → cjs/lib}/DBusClientOptions.js +0 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.dbusEntrypoint = dbusEntrypoint;
|
|
7
|
+
const node_events_1 = __importDefault(require("node:events"));
|
|
8
|
+
const dtos_1 = require("@lakutata/core/dtos");
|
|
9
|
+
const dbus_sdk_1 = require("dbus-sdk");
|
|
10
|
+
const DBusChannel_js_1 = require("../channel/DBusChannel.js");
|
|
11
|
+
const DBusContext_js_1 = require("../context/DBusContext.js");
|
|
12
|
+
const DBusObjectManager_js_1 = require("../components/DBusObjectManager.js");
|
|
13
|
+
const Declarations_js_1 = require("../lib/Declarations.js");
|
|
14
|
+
const Names_js_1 = require("../lib/Names.js");
|
|
15
|
+
const Signature_js_1 = require("../lib/Signature.js");
|
|
16
|
+
/**
|
|
17
|
+
* The connection options of a bus
|
|
18
|
+
* @param bus
|
|
19
|
+
*/
|
|
20
|
+
function connectOptions(bus) {
|
|
21
|
+
if (bus === 'session')
|
|
22
|
+
return { busAddress: process.env.DBUS_SESSION_BUS_ADDRESS };
|
|
23
|
+
if (bus === 'system')
|
|
24
|
+
return { busAddress: process.env.DBUS_SYSTEM_BUS_ADDRESS ?? 'unix:path=/var/run/dbus/system_bus_socket' };
|
|
25
|
+
if (/^[a-z]+:/.test(bus))
|
|
26
|
+
return { busAddress: bus };
|
|
27
|
+
return { socket: bus };
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The error given to the caller of a method
|
|
31
|
+
* @param error
|
|
32
|
+
*/
|
|
33
|
+
function toMethodError(error) {
|
|
34
|
+
const { errMsg, message } = (error && typeof error === 'object' ? error : {});
|
|
35
|
+
const methodError = new Error(typeof errMsg === 'string' && errMsg ? errMsg : typeof message === 'string' ? message : String(error));
|
|
36
|
+
methodError.name = (0, Names_js_1.errorName)(error);
|
|
37
|
+
return methodError;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Build the D-Bus adapter of the entrypoint (its `dbus` option): the application owns a service name on a bus and
|
|
41
|
+
* serves the controllers declared with `@DBusInterface` as the interfaces of its objects, their `@DBusMethod` actions
|
|
42
|
+
* as the methods. The objects of the paths without variables are exported when the adapter starts, until it stops
|
|
43
|
+
* ({@link DBusObjectManager.removeObject} does not remove them); the objects of the path templates are exported when
|
|
44
|
+
* they are added with {@link DBusObjectManager.addObject}, before or after the start.
|
|
45
|
+
*
|
|
46
|
+
* Starting connects to the bus and requests the name. The adapter stops gracefully with the entrypoint: it releases the
|
|
47
|
+
* name (no new call reaches it), the calls in progress end, then the connection closes. It needs a D-Bus daemon, as on
|
|
48
|
+
* Linux: the system bus, a session bus, or a private `dbus-daemon`.
|
|
49
|
+
* @param options The bus, the service name and how it is owned, the adapter's middlewares.
|
|
50
|
+
* @returns The adapter, to give to the `dbus` option of `buildEntrypoints()`.
|
|
51
|
+
* @throws {TypeError} At once, when the service name is invalid; when the adapter starts, when an action declared with
|
|
52
|
+
* `@DBusMethod` belongs to a controller without `@DBusInterface`.
|
|
53
|
+
* @throws {Error} When the adapter starts, if the bus cannot be reached, or if another connection owns the name
|
|
54
|
+
* (`The DBus name … is owned by another service`): the entrypoint fails to start.
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* import {Application} from 'lakutata'
|
|
58
|
+
* import {buildEntrypoints, Controller} from 'lakutata/com/entrypoint'
|
|
59
|
+
* import {dbusEntrypoint, DBusInterface, DBusMethod} from '@lakutata/dbus'
|
|
60
|
+
*
|
|
61
|
+
* @DBusInterface('com.example.Manager', {path: '/com/example/Manager'})
|
|
62
|
+
* class ManagerController extends Controller {
|
|
63
|
+
* @DBusMethod('Ping', {returns: 's'})
|
|
64
|
+
* public async ping(): Promise<string> {
|
|
65
|
+
* return 'pong'
|
|
66
|
+
* }
|
|
67
|
+
* }
|
|
68
|
+
*
|
|
69
|
+
* //busctl --system call com.example.DeviceService /com/example/Manager com.example.Manager Ping
|
|
70
|
+
* Application.run(() => ({
|
|
71
|
+
* id: 'devices.app',
|
|
72
|
+
* name: 'Devices',
|
|
73
|
+
* components: {
|
|
74
|
+
* entrypoint: buildEntrypoints({
|
|
75
|
+
* controllers: [ManagerController],
|
|
76
|
+
* dbus: dbusEntrypoint({bus: 'system', service: 'com.example.DeviceService'})
|
|
77
|
+
* })
|
|
78
|
+
* },
|
|
79
|
+
* bootstrap: ['entrypoint']
|
|
80
|
+
* }))
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
function dbusEntrypoint(options) {
|
|
84
|
+
(0, Names_js_1.checkInterfaceName)(options.service);
|
|
85
|
+
let service;
|
|
86
|
+
let detach;
|
|
87
|
+
const exported = new Map();
|
|
88
|
+
/**
|
|
89
|
+
* The interfaces of the controllers and of the actions, by path template
|
|
90
|
+
* @param runtime
|
|
91
|
+
*/
|
|
92
|
+
const collect = (runtime) => {
|
|
93
|
+
const templates = new Map();
|
|
94
|
+
const interfacesAt = (path, name) => {
|
|
95
|
+
let template = templates.get(path);
|
|
96
|
+
if (!template) {
|
|
97
|
+
template = { template: (0, Names_js_1.compilePathTemplate)(path), interfaces: new Map() };
|
|
98
|
+
templates.set(path, template);
|
|
99
|
+
}
|
|
100
|
+
let interfaces = template.interfaces.get(name);
|
|
101
|
+
if (!interfaces) {
|
|
102
|
+
interfaces = { methods: [] };
|
|
103
|
+
template.interfaces.set(name, interfaces);
|
|
104
|
+
}
|
|
105
|
+
return interfaces;
|
|
106
|
+
};
|
|
107
|
+
for (const controller of runtime.controllers) {
|
|
108
|
+
const declaration = (0, Declarations_js_1.getDBusInterfaceDeclaration)(controller);
|
|
109
|
+
if (declaration)
|
|
110
|
+
interfacesAt(declaration.path, declaration.interface).declaration = declaration;
|
|
111
|
+
}
|
|
112
|
+
for (const action of runtime.actions) {
|
|
113
|
+
const { path, interface: interfaceName, member } = action.address;
|
|
114
|
+
if (path === undefined || interfaceName === undefined)
|
|
115
|
+
throw new TypeError(`The DBus method ${member} of ${action.controller} has no interface: declare its controller with @DBusInterface`);
|
|
116
|
+
interfacesAt(path, interfaceName).methods.push(action);
|
|
117
|
+
}
|
|
118
|
+
return templates;
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* The signature of the result of a method: its returns option, or the schema of @Return
|
|
122
|
+
* @param action
|
|
123
|
+
*/
|
|
124
|
+
const resultSignature = (action) => {
|
|
125
|
+
if (action.address.returns !== undefined)
|
|
126
|
+
return action.address.returns;
|
|
127
|
+
return action.returnSchema ? (0, Signature_js_1.schemaSignature)(action.returnSchema) : undefined;
|
|
128
|
+
};
|
|
129
|
+
return {
|
|
130
|
+
channel: 'dbus',
|
|
131
|
+
definition: DBusChannel_js_1.DBusChannel,
|
|
132
|
+
name: options.name,
|
|
133
|
+
middlewares: options.middlewares,
|
|
134
|
+
start: async (runtime) => {
|
|
135
|
+
const templates = collect(runtime);
|
|
136
|
+
const manager = await runtime.getObject(DBusObjectManager_js_1.DBusObjectManager);
|
|
137
|
+
const localService = new dbus_sdk_1.LocalService(options.service);
|
|
138
|
+
service = localService;
|
|
139
|
+
/**
|
|
140
|
+
* Build the interface of an object
|
|
141
|
+
* @param path
|
|
142
|
+
* @param name
|
|
143
|
+
* @param served
|
|
144
|
+
* @param variables
|
|
145
|
+
* @param object
|
|
146
|
+
*/
|
|
147
|
+
const buildInterface = (path, name, served, variables, object) => {
|
|
148
|
+
const localInterface = new dbus_sdk_1.LocalInterface(name);
|
|
149
|
+
for (const action of served.methods) {
|
|
150
|
+
const returns = resultSignature(action);
|
|
151
|
+
const hasInput = action.dto !== dtos_1.FlexibleDTO;
|
|
152
|
+
localInterface.defineMethod({
|
|
153
|
+
name: action.address.member,
|
|
154
|
+
inputArgs: hasInput ? [{ name: 'input', type: 'a{sv}' }] : [],
|
|
155
|
+
outputArgs: returns ? [{ name: 'output', type: returns }] : [],
|
|
156
|
+
method: async (input) => {
|
|
157
|
+
const context = new DBusContext_js_1.DBusContext({ path: path, interface: name, member: action.address.member, data: input && typeof input === 'object' ? input : {} });
|
|
158
|
+
let result;
|
|
159
|
+
try {
|
|
160
|
+
result = await runtime.dispatchTo(action, context, { params: variables });
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
throw toMethodError(error);
|
|
164
|
+
}
|
|
165
|
+
if (!returns)
|
|
166
|
+
return undefined;
|
|
167
|
+
return (0, Signature_js_1.toEncodable)(returns === 'a{sv}' && (result === undefined || result === null) ? {} : result);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
for (const property of served.declaration?.properties ?? []) {
|
|
172
|
+
localInterface.defineProperty({
|
|
173
|
+
name: property.name,
|
|
174
|
+
type: property.type,
|
|
175
|
+
getter: () => (0, Signature_js_1.toEncodable)(manager.getPropertyValue(path, property)),
|
|
176
|
+
//A value written by a client is validated synchronously: its errors are given to the client
|
|
177
|
+
setter: property.writable ? (value) => {
|
|
178
|
+
let validated;
|
|
179
|
+
try {
|
|
180
|
+
validated = property.validate(value);
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
//The errors given to DBus are plain errors (the name of an exception is read only)
|
|
184
|
+
throw toMethodError(error);
|
|
185
|
+
}
|
|
186
|
+
manager[DBusObjectManager_js_1.STORE]({ path: path, interface: name, property: property, value: validated });
|
|
187
|
+
} : undefined,
|
|
188
|
+
emitPropertiesChanged: property.writable
|
|
189
|
+
});
|
|
190
|
+
object.properties.set(property, [...(object.properties.get(property) ?? []), name]);
|
|
191
|
+
}
|
|
192
|
+
for (const signal of served.declaration?.signals ?? []) {
|
|
193
|
+
const emitter = new node_events_1.default();
|
|
194
|
+
localInterface.defineSignal({ name: signal.name, args: [{ name: 'data', type: signal.type }], eventEmitter: emitter });
|
|
195
|
+
const signals = object.signals.get(signal.name) ?? [];
|
|
196
|
+
signals.push({ signal: signal, emitter: emitter });
|
|
197
|
+
object.signals.set(signal.name, signals);
|
|
198
|
+
}
|
|
199
|
+
return localInterface;
|
|
200
|
+
};
|
|
201
|
+
/**
|
|
202
|
+
* Export an object
|
|
203
|
+
* @param path
|
|
204
|
+
*/
|
|
205
|
+
const addObject = (path) => {
|
|
206
|
+
if (exported.has(path))
|
|
207
|
+
return true;
|
|
208
|
+
const object = { object: new dbus_sdk_1.LocalObject(path), signals: new Map(), properties: new Map() };
|
|
209
|
+
let served = false;
|
|
210
|
+
for (const { template, interfaces } of templates.values()) {
|
|
211
|
+
const variables = template.match(path);
|
|
212
|
+
if (!variables)
|
|
213
|
+
continue;
|
|
214
|
+
interfaces.forEach((interfaceServed, name) => object.object.addInterface(buildInterface(path, name, interfaceServed, variables, object)));
|
|
215
|
+
served = true;
|
|
216
|
+
}
|
|
217
|
+
if (!served)
|
|
218
|
+
return false;
|
|
219
|
+
exported.set(path, object);
|
|
220
|
+
localService.addObject(object.object);
|
|
221
|
+
return true;
|
|
222
|
+
};
|
|
223
|
+
//The objects of the paths without variables are exported at once, and kept until the adapter closes
|
|
224
|
+
const fixed = new Set();
|
|
225
|
+
for (const { template } of templates.values()) {
|
|
226
|
+
if (!template.static)
|
|
227
|
+
continue;
|
|
228
|
+
fixed.add(template.template);
|
|
229
|
+
addObject(template.template);
|
|
230
|
+
}
|
|
231
|
+
const connect = connectOptions(options.bus ?? 'session');
|
|
232
|
+
let flags = dbus_sdk_1.RequestNameFlags.DBUS_NAME_FLAG_DO_NOT_QUEUE;
|
|
233
|
+
if (options.replaceExisting)
|
|
234
|
+
flags |= dbus_sdk_1.RequestNameFlags.DBUS_NAME_FLAG_REPLACE_EXISTING;
|
|
235
|
+
if (options.allowReplacement)
|
|
236
|
+
flags |= dbus_sdk_1.RequestNameFlags.DBUS_NAME_FLAG_ALLOW_REPLACEMENT;
|
|
237
|
+
const result = await localService.run({ ...connect, flags: flags });
|
|
238
|
+
if (result !== dbus_sdk_1.RequestNameResultCode.DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER && result !== dbus_sdk_1.RequestNameResultCode.DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER) {
|
|
239
|
+
await localService.stop().catch(() => undefined);
|
|
240
|
+
throw new Error(`The DBus name ${options.service} is owned by another service`);
|
|
241
|
+
}
|
|
242
|
+
const sink = {
|
|
243
|
+
addObject: addObject,
|
|
244
|
+
removeObject: (path) => {
|
|
245
|
+
if (fixed.has(path) || !exported.delete(path))
|
|
246
|
+
return false;
|
|
247
|
+
return localService.removeObject(path);
|
|
248
|
+
},
|
|
249
|
+
isFixed: (path) => fixed.has(path),
|
|
250
|
+
emitSignal: (path, signal, data) => {
|
|
251
|
+
const emitters = exported.get(path)?.signals.get(signal.name)?.filter((candidate) => candidate.signal === signal);
|
|
252
|
+
if (!emitters?.length)
|
|
253
|
+
return false;
|
|
254
|
+
emitters.forEach(({ emitter }) => emitter.emit(signal.name, (0, Signature_js_1.toEncodable)(data)));
|
|
255
|
+
return true;
|
|
256
|
+
},
|
|
257
|
+
propertyChanged: (path, property) => {
|
|
258
|
+
const object = exported.get(path);
|
|
259
|
+
const interfaces = object?.properties.get(property);
|
|
260
|
+
if (!object || !interfaces)
|
|
261
|
+
return;
|
|
262
|
+
//The interfaces read the new value with their getters (the manager stored it), typed by the property
|
|
263
|
+
interfaces.forEach((name) => object.object.getInterface(name)?.emitPropertiesChanged(property.name));
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
detach = manager[DBusObjectManager_js_1.ATTACH](sink);
|
|
267
|
+
},
|
|
268
|
+
stop: async () => {
|
|
269
|
+
//The name is released: no new call reaches the service, the calls in progress end
|
|
270
|
+
detach?.();
|
|
271
|
+
detach = undefined;
|
|
272
|
+
await service?.dbus?.releaseName(options.service).catch(() => undefined);
|
|
273
|
+
},
|
|
274
|
+
close: async () => {
|
|
275
|
+
await service?.dbus?.disconnect().catch(() => undefined);
|
|
276
|
+
exported.clear();
|
|
277
|
+
service = undefined;
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type EntrypointAdapter } from '@lakutata/entrypoint';
|
|
2
|
+
import { type ChannelDefinition } from '@lakutata/entrypoint/channel';
|
|
3
|
+
import { DBusContext } from '../context/DBusContext.js';
|
|
4
|
+
declare module '@lakutata/entrypoint' {
|
|
5
|
+
interface EntrypointOptions {
|
|
6
|
+
/**
|
|
7
|
+
* The D-Bus adapters, built by `dbusEntrypoint()`: one, or several for several buses or service names.
|
|
8
|
+
* @default undefined (no D-Bus adapter)
|
|
9
|
+
*/
|
|
10
|
+
dbus?: EntrypointAdapter<DBusContext> | EntrypointAdapter<DBusContext>[];
|
|
11
|
+
}
|
|
12
|
+
interface PrefixOptions {
|
|
13
|
+
/**
|
|
14
|
+
* The object path (or path template) and the interface of a controller's D-Bus methods. `@DBusInterface` sets
|
|
15
|
+
* it; an application does not set it itself.
|
|
16
|
+
*/
|
|
17
|
+
dbus?: {
|
|
18
|
+
/**
|
|
19
|
+
* The object path, or path template, of the methods.
|
|
20
|
+
*/
|
|
21
|
+
path?: string;
|
|
22
|
+
/**
|
|
23
|
+
* The name of the methods' interface.
|
|
24
|
+
*/
|
|
25
|
+
interface?: string;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The definition of the D-Bus channel of the entrypoint, named `dbus`: its actions are the methods of D-Bus interfaces,
|
|
31
|
+
* addressed by `{member, interface, path}` (the method name from `@DBusMethod`, the interface and the path template from
|
|
32
|
+
* `@DBusInterface`). A call matches an action by its interface, its method and its object path; a call matching none
|
|
33
|
+
* fails with `ControllerActionNotFoundException`. `@DBusMethod` and {@link dbusEntrypoint} use it: an application only
|
|
34
|
+
* needs it to write an adapter of its own.
|
|
35
|
+
*/
|
|
36
|
+
export declare const DBusChannel: ChannelDefinition;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DBusChannel = void 0;
|
|
4
|
+
const entrypoint_1 = require("@lakutata/entrypoint");
|
|
5
|
+
const channel_1 = require("@lakutata/entrypoint/channel");
|
|
6
|
+
const DBusContext_js_1 = require("../context/DBusContext.js");
|
|
7
|
+
const Names_js_1 = require("../lib/Names.js");
|
|
8
|
+
/**
|
|
9
|
+
* The key of the address of a method
|
|
10
|
+
* @param interfaceName
|
|
11
|
+
* @param member
|
|
12
|
+
* @param path
|
|
13
|
+
*/
|
|
14
|
+
function addressKey(interfaceName, member, path) {
|
|
15
|
+
return `${interfaceName}.${member}@${path}`;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The definition of the D-Bus channel of the entrypoint, named `dbus`: its actions are the methods of D-Bus interfaces,
|
|
19
|
+
* addressed by `{member, interface, path}` (the method name from `@DBusMethod`, the interface and the path template from
|
|
20
|
+
* `@DBusInterface`). A call matches an action by its interface, its method and its object path; a call matching none
|
|
21
|
+
* fails with `ControllerActionNotFoundException`. `@DBusMethod` and {@link dbusEntrypoint} use it: an application only
|
|
22
|
+
* needs it to write an adapter of its own.
|
|
23
|
+
*/
|
|
24
|
+
exports.DBusChannel = (0, channel_1.hasChannel)('dbus') ? (0, channel_1.getChannel)('dbus') : (0, channel_1.defineChannel)({
|
|
25
|
+
name: 'dbus',
|
|
26
|
+
kind: 'request',
|
|
27
|
+
contextType: DBusContext_js_1.DBUS_CONTEXT_TYPE,
|
|
28
|
+
validate: (pattern) => {
|
|
29
|
+
(0, Names_js_1.checkMemberName)(pattern.member, 'method');
|
|
30
|
+
if (pattern.interface !== undefined)
|
|
31
|
+
(0, Names_js_1.checkInterfaceName)(pattern.interface);
|
|
32
|
+
if (pattern.path !== undefined)
|
|
33
|
+
(0, Names_js_1.checkPathTemplate)(pattern.path);
|
|
34
|
+
return pattern;
|
|
35
|
+
},
|
|
36
|
+
identify: (pattern) => addressKey(pattern.interface ?? '?', pattern.member, pattern.path ?? '?'),
|
|
37
|
+
describe: (pattern) => {
|
|
38
|
+
const { returns, ...address } = pattern;
|
|
39
|
+
return returns === undefined ? address : { ...address, returns: returns };
|
|
40
|
+
},
|
|
41
|
+
prefix: (prefix, pattern) => {
|
|
42
|
+
const dbus = prefix.dbus;
|
|
43
|
+
if (!dbus || (pattern.path !== undefined && pattern.interface !== undefined))
|
|
44
|
+
return undefined;
|
|
45
|
+
return { ...pattern, path: pattern.path ?? dbus.path, interface: pattern.interface ?? dbus.interface };
|
|
46
|
+
},
|
|
47
|
+
createMatcher: (entries) => {
|
|
48
|
+
const templates = entries
|
|
49
|
+
.filter((entry) => entry.details.pattern.path !== undefined)
|
|
50
|
+
.map((entry) => ({ entry: entry, template: (0, Names_js_1.compilePathTemplate)(entry.details.pattern.path) }));
|
|
51
|
+
return {
|
|
52
|
+
match: (context) => {
|
|
53
|
+
const { path, interface: interfaceName, member } = context;
|
|
54
|
+
for (const { entry, template } of templates) {
|
|
55
|
+
if (entry.details.pattern.interface !== interfaceName || entry.details.pattern.member !== member)
|
|
56
|
+
continue;
|
|
57
|
+
const params = template.match(path);
|
|
58
|
+
if (params)
|
|
59
|
+
return { entry: entry, params: params };
|
|
60
|
+
}
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
},
|
|
65
|
+
notFound: (context) => new entrypoint_1.ControllerActionNotFoundException('The DBus method {member} of the interface {interface} of {path} is not found', {
|
|
66
|
+
member: context.member,
|
|
67
|
+
interface: context.interface,
|
|
68
|
+
path: context.path
|
|
69
|
+
})
|
|
70
|
+
});
|