@lakutata/dbus 2.3.0 → 3.0.0-beta.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.
- 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 -145
- 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,164 @@
|
|
|
1
|
+
import { Component } from '@lakutata/core';
|
|
2
|
+
import type { DBusPropertyDefinition, DBusSignalDefinition } from '../lib/Declarations.js';
|
|
3
|
+
/**
|
|
4
|
+
* What a DBus adapter does for the object manager while it runs
|
|
5
|
+
*/
|
|
6
|
+
export type DBusObjectSink = {
|
|
7
|
+
/**
|
|
8
|
+
* Export an object, false when no interface of the adapter serves its path
|
|
9
|
+
*/
|
|
10
|
+
addObject(path: string): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Stop exporting an object added by the object manager, false when it does not export it or exports it as a fixed
|
|
13
|
+
* object (the path of a template without variables), which it keeps
|
|
14
|
+
*/
|
|
15
|
+
removeObject(path: string): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Whether it exports the object as a fixed object
|
|
18
|
+
*/
|
|
19
|
+
isFixed(path: string): boolean;
|
|
20
|
+
emitSignal(path: string, signal: DBusSignalDefinition<any>, data: unknown): boolean;
|
|
21
|
+
propertyChanged(path: string, property: DBusPropertyDefinition<any>, value: unknown): void;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* A property value written by a D-Bus client, the argument of the `propertyWritten` event of
|
|
25
|
+
* {@link DBusObjectManager}. The value is already validated and kept when the event is emitted.
|
|
26
|
+
*/
|
|
27
|
+
export type DBusPropertyWrite = {
|
|
28
|
+
/**
|
|
29
|
+
* The object path of the property (`'/com/example/Devices/A1'`).
|
|
30
|
+
*/
|
|
31
|
+
readonly path: string;
|
|
32
|
+
/**
|
|
33
|
+
* The name of the interface the client wrote it through (`'com.example.Device'`).
|
|
34
|
+
*/
|
|
35
|
+
readonly interface: string;
|
|
36
|
+
/**
|
|
37
|
+
* The property's definition, to compare with the one built by `defineDBusProperty`.
|
|
38
|
+
*/
|
|
39
|
+
readonly property: DBusPropertyDefinition<any>;
|
|
40
|
+
/**
|
|
41
|
+
* The value written, validated by the property's schema.
|
|
42
|
+
*/
|
|
43
|
+
readonly value: unknown;
|
|
44
|
+
};
|
|
45
|
+
export declare const ATTACH: unique symbol;
|
|
46
|
+
export declare const STORE: unique symbol;
|
|
47
|
+
/**
|
|
48
|
+
* The application's D-Bus objects: it adds and removes the objects of the path templates of `@DBusInterface`
|
|
49
|
+
* (`/com/example/Devices/{sn}`), keeps the values of their properties, and emits their signals. Inject it
|
|
50
|
+
* (`@Inject(DBusObjectManager)`) or get it (`getObject(DBusObjectManager)`) from any object: it is autoloaded, a
|
|
51
|
+
* singleton of the application, and needs no registration.
|
|
52
|
+
*
|
|
53
|
+
* Its state lives in the application, not on the bus: the objects added before a {@link dbusEntrypoint} starts are
|
|
54
|
+
* exported when it starts, and every running D-Bus adapter whose interfaces match a path exports the object. The
|
|
55
|
+
* clients are told of the objects added and removed by the `org.freedesktop.DBus.ObjectManager` interface of the root
|
|
56
|
+
* object (`InterfacesAdded`, `InterfacesRemoved`).
|
|
57
|
+
*
|
|
58
|
+
* It emits `propertyWritten` (a {@link DBusPropertyWrite}) when a client writes a writable property.
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* import {Component} from 'lakutata'
|
|
62
|
+
* import {Inject} from 'lakutata/decorator/di'
|
|
63
|
+
* import {DBusObjectManager, defineDBusProperty, defineDBusSignal, type DBusPropertyWrite} from '@lakutata/dbus'
|
|
64
|
+
*
|
|
65
|
+
* export const DeviceState = defineDBusProperty<string>('State', 's', {initial: 'idle'})
|
|
66
|
+
* export const DeviceLevel = defineDBusProperty<number>('Level', 'i', {writable: true, initial: 1})
|
|
67
|
+
* export const DeviceRemoved = defineDBusSignal<string>('Removed', 's')
|
|
68
|
+
*
|
|
69
|
+
* //Declared in the components of the application, with the controllers of the interfaces at /com/example/Devices/{sn}
|
|
70
|
+
* export class Devices extends Component {
|
|
71
|
+
* @Inject(DBusObjectManager)
|
|
72
|
+
* protected readonly manager: DBusObjectManager
|
|
73
|
+
*
|
|
74
|
+
* protected async init(): Promise<void> {
|
|
75
|
+
* this.manager.on('propertyWritten', (write: DBusPropertyWrite): void => {
|
|
76
|
+
* if (write.property === DeviceLevel) console.log(`${write.path}: level ${write.value}`)
|
|
77
|
+
* })
|
|
78
|
+
* }
|
|
79
|
+
*
|
|
80
|
+
* public plug(sn: string): void {
|
|
81
|
+
* const path: string = `/com/example/Devices/${sn}`
|
|
82
|
+
* this.manager.addObject(path)
|
|
83
|
+
* this.manager.setPropertyValue(path, DeviceState, 'running')
|
|
84
|
+
* }
|
|
85
|
+
*
|
|
86
|
+
* public unplug(sn: string): void {
|
|
87
|
+
* const path: string = `/com/example/Devices/${sn}`
|
|
88
|
+
* this.manager.emitSignal(path, DeviceRemoved, sn)
|
|
89
|
+
* this.manager.removeObject(path)
|
|
90
|
+
* }
|
|
91
|
+
* }
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
export declare class DBusObjectManager extends Component {
|
|
95
|
+
#private;
|
|
96
|
+
/**
|
|
97
|
+
* Send the changes to an adapter until the returned function is called; the objects already added are exported by it
|
|
98
|
+
* @param sink
|
|
99
|
+
*/
|
|
100
|
+
[ATTACH](sink: DBusObjectSink): () => void;
|
|
101
|
+
/**
|
|
102
|
+
* Keep a value written by a client
|
|
103
|
+
* @param write
|
|
104
|
+
*/
|
|
105
|
+
[STORE](write: DBusPropertyWrite): void;
|
|
106
|
+
/**
|
|
107
|
+
* Add an object: every running D-Bus adapter whose interfaces have a path template matching it (or the same path)
|
|
108
|
+
* exports it, with those interfaces, and the adapters started later export it when they start. The variables of the
|
|
109
|
+
* matching templates are given to the methods called on it. An object whose path matches no template is kept, but
|
|
110
|
+
* not exported.
|
|
111
|
+
* @param path The object path (`'/com/example/Devices/A1'`), not a template.
|
|
112
|
+
* @returns `false` when the object was already added, `true` otherwise.
|
|
113
|
+
* @throws {TypeError} When the path is invalid, or is a template (it contains braces).
|
|
114
|
+
*/
|
|
115
|
+
addObject(path: string): boolean;
|
|
116
|
+
/**
|
|
117
|
+
* Remove an object added with {@link addObject}: the adapters stop exporting it, and its property values are
|
|
118
|
+
* forgotten (added again, it starts from the initial values). A fixed object (the path of a template without
|
|
119
|
+
* variables, exported by the adapters themselves) stays exported, with its property values, when it was also
|
|
120
|
+
* added: only its entry in {@link objects} is removed.
|
|
121
|
+
* @param path The object path given to {@link addObject}.
|
|
122
|
+
* @returns `false` when the object was not added, `true` otherwise.
|
|
123
|
+
*/
|
|
124
|
+
removeObject(path: string): boolean;
|
|
125
|
+
/**
|
|
126
|
+
* Tell whether an object was added with {@link addObject} and not removed since.
|
|
127
|
+
* @param path The object path.
|
|
128
|
+
* @returns `true` when the object is added.
|
|
129
|
+
*/
|
|
130
|
+
hasObject(path: string): boolean;
|
|
131
|
+
/**
|
|
132
|
+
* List the objects added with {@link addObject}, in the order they were added; the objects of the paths without
|
|
133
|
+
* variables, exported by the adapters themselves, are not listed.
|
|
134
|
+
* @returns The object paths.
|
|
135
|
+
*/
|
|
136
|
+
objects(): string[];
|
|
137
|
+
/**
|
|
138
|
+
* Set the value of a property on an object, validated by the property's schema: the clients read it from then on,
|
|
139
|
+
* and the running adapters exporting the object announce it (`PropertiesChanged`). The value is kept even when no
|
|
140
|
+
* adapter exports the object yet.
|
|
141
|
+
* @param path The object path (`'/com/example/Devices/A1'`).
|
|
142
|
+
* @param property The property's definition, listed in the `properties` of the object's interface.
|
|
143
|
+
* @param value The new value.
|
|
144
|
+
* @throws {InvalidValueException} When the value does not match the property's schema; nothing is changed.
|
|
145
|
+
*/
|
|
146
|
+
setPropertyValue<T>(path: string, property: DBusPropertyDefinition<T>, value: T): void;
|
|
147
|
+
/**
|
|
148
|
+
* Get the value of a property on an object: the last value set by the application or written by a client.
|
|
149
|
+
* @param path The object path.
|
|
150
|
+
* @param property The property's definition.
|
|
151
|
+
* @returns The value, or the property's `initial` value until one is set.
|
|
152
|
+
*/
|
|
153
|
+
getPropertyValue<T>(path: string, property: DBusPropertyDefinition<T>): T | undefined;
|
|
154
|
+
/**
|
|
155
|
+
* Emit a signal from an object, through every running adapter exporting the object with an interface listing the
|
|
156
|
+
* signal. The data is validated by the signal's DTO first.
|
|
157
|
+
* @param path The object path (`'/com/example/Devices/A1'`).
|
|
158
|
+
* @param signal The signal's definition, listed in the `signals` of the object's interface.
|
|
159
|
+
* @param data The data of the signal.
|
|
160
|
+
* @returns `false` when no running adapter exports the object with this signal (nothing is sent), `true` otherwise.
|
|
161
|
+
* @throws {InvalidValueException} When the data does not match the signal's DTO.
|
|
162
|
+
*/
|
|
163
|
+
emitSignal<T>(path: string, signal: DBusSignalDefinition<T>, data: T): boolean;
|
|
164
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { BaseContext } from '@lakutata/entrypoint';
|
|
2
|
+
import { type DBusContextParams } from '../types/DBusContextParams.js';
|
|
3
|
+
/**
|
|
4
|
+
* The `type` of every {@link DBusContext}: `'DBUS'`. A middleware or an access rule shared by several transports tells
|
|
5
|
+
* the D-Bus calls apart with it.
|
|
6
|
+
*/
|
|
7
|
+
export declare const DBUS_CONTEXT_TYPE: string;
|
|
8
|
+
/**
|
|
9
|
+
* The context of a D-Bus method call: `this.context` of a controller action declared with `@DBusMethod` when a client
|
|
10
|
+
* calls it through {@link dbusEntrypoint}. The adapter creates one per call; its `data` is the call's input (the entries
|
|
11
|
+
* of its `a{sv}` dictionary). The variables of the object path template are not in the context: they are merged into
|
|
12
|
+
* the action's input, as the route parameters of HTTP.
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import {Controller} from 'lakutata/com/entrypoint'
|
|
16
|
+
* import {DBusContext, DBusInterface, DBusMethod} from '@lakutata/dbus'
|
|
17
|
+
*
|
|
18
|
+
* @DBusInterface('com.example.Manager', {path: '/com/example/Manager'})
|
|
19
|
+
* class ManagerController extends Controller {
|
|
20
|
+
* //Returns "com.example.Manager.Ping at /com/example/Manager"
|
|
21
|
+
* @DBusMethod('Ping', {returns: 's'})
|
|
22
|
+
* public async ping(): Promise<string> {
|
|
23
|
+
* const context: DBusContext = this.context as DBusContext
|
|
24
|
+
* return `${context.interface}.${context.member} at ${context.path}`
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare class DBusContext<T extends Record<string, any> = {}> extends BaseContext<T> {
|
|
30
|
+
/**
|
|
31
|
+
* Always {@link DBUS_CONTEXT_TYPE} (`'DBUS'`).
|
|
32
|
+
*/
|
|
33
|
+
readonly type: string;
|
|
34
|
+
/**
|
|
35
|
+
* The object path the client called (`'/com/example/Devices/A1'`).
|
|
36
|
+
*/
|
|
37
|
+
readonly path: string;
|
|
38
|
+
/**
|
|
39
|
+
* The name of the interface the client called (`'com.example.Device'`).
|
|
40
|
+
*/
|
|
41
|
+
readonly interface: string;
|
|
42
|
+
/**
|
|
43
|
+
* The name of the method the client called (`'Status'`).
|
|
44
|
+
*/
|
|
45
|
+
readonly member: string;
|
|
46
|
+
/**
|
|
47
|
+
* Create the context of a method call, validating its properties.
|
|
48
|
+
* @param params The object path, the interface, the method and the input of the call.
|
|
49
|
+
* @throws {InvalidValueException} When a property is missing or invalid.
|
|
50
|
+
*/
|
|
51
|
+
constructor(params: DBusContextParams);
|
|
52
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { Controller } from '@lakutata/entrypoint';
|
|
2
|
+
import { type DBusPropertyDefinition, type DBusSignalDefinition } from '../lib/Declarations.js';
|
|
3
|
+
/**
|
|
4
|
+
* The options of {@link DBusInterface}: where the interface is served, and its signals and properties.
|
|
5
|
+
*/
|
|
6
|
+
export type DBusInterfaceOptions = {
|
|
7
|
+
/**
|
|
8
|
+
* The object path of the interface. A path without variables (`'/com/example/Manager'`) is one object, exported
|
|
9
|
+
* while the adapter runs ({@link DBusObjectManager.removeObject} does not remove it). A template (`'/com/example/Devices/{sn}'`) serves the objects added with
|
|
10
|
+
* {@link DBusObjectManager.addObject} whose path matches it; its variables are merged into the input of the methods,
|
|
11
|
+
* as route parameters (they take precedence over the client's input). Its elements are letters, digits and `_`, or
|
|
12
|
+
* variables in braces; a variable matches one element.
|
|
13
|
+
*/
|
|
14
|
+
path: string;
|
|
15
|
+
/**
|
|
16
|
+
* The signals of the interface, declared with {@link defineDBusSignal} and emitted with
|
|
17
|
+
* {@link DBusObjectManager.emitSignal}.
|
|
18
|
+
* @default []
|
|
19
|
+
*/
|
|
20
|
+
signals?: DBusSignalDefinition<any>[];
|
|
21
|
+
/**
|
|
22
|
+
* The properties of the interface, declared with {@link defineDBusProperty} and set with
|
|
23
|
+
* {@link DBusObjectManager.setPropertyValue}.
|
|
24
|
+
* @default []
|
|
25
|
+
*/
|
|
26
|
+
properties?: DBusPropertyDefinition<any>[];
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Serve a controller as a D-Bus interface: its `@DBusMethod` actions are the interface's methods, and the signals and
|
|
30
|
+
* properties of the options are its other members, on the objects at `options.path`. The controllers declaring the same
|
|
31
|
+
* path are served by the same objects, each one interface; a subclass inherits the declaration of its parent class.
|
|
32
|
+
* The objects also implement `org.freedesktop.DBus.Properties`, `Introspectable` and `Peer`, and the root object `/`
|
|
33
|
+
* implements `ObjectManager`. Nothing is served until a {@link dbusEntrypoint} runs.
|
|
34
|
+
* @param name The name of the interface (`'com.example.Device'`): two or more elements separated by dots, made of
|
|
35
|
+
* letters, digits and `_`, not starting with a digit; 255 characters at most.
|
|
36
|
+
* @param options The object path (or template) of the interface, its signals and its properties.
|
|
37
|
+
* @returns The class decorator.
|
|
38
|
+
* @throws {TypeError} When the class is declared, if the name of the interface or the path is invalid.
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* import {DTO} from 'lakutata'
|
|
42
|
+
* import {Controller} from 'lakutata/com/entrypoint'
|
|
43
|
+
* import {Expect, Return} from 'lakutata/decorator/dto'
|
|
44
|
+
* import {DBusInterface, DBusMethod, defineDBusProperty, defineDBusSignal} from '@lakutata/dbus'
|
|
45
|
+
*
|
|
46
|
+
* class DeviceSnDTO extends DTO {
|
|
47
|
+
* @Expect(DTO.String().required())
|
|
48
|
+
* public sn: string
|
|
49
|
+
* }
|
|
50
|
+
*
|
|
51
|
+
* class StatusDTO extends DTO {
|
|
52
|
+
* @Expect(DTO.String().required())
|
|
53
|
+
* public sn: string
|
|
54
|
+
*
|
|
55
|
+
* @Expect(DTO.Boolean().required())
|
|
56
|
+
* public online: boolean
|
|
57
|
+
* }
|
|
58
|
+
*
|
|
59
|
+
* export const DeviceChanged = defineDBusSignal('Changed', StatusDTO)
|
|
60
|
+
* export const DeviceState = defineDBusProperty<string>('State', 's', {initial: 'idle'})
|
|
61
|
+
*
|
|
62
|
+
* //Served by the objects /com/example/Devices/A1, /com/example/Devices/B2… added with DBusObjectManager
|
|
63
|
+
* @DBusInterface('com.example.Device', {path: '/com/example/Devices/{sn}', signals: [DeviceChanged], properties: [DeviceState]})
|
|
64
|
+
* export class DeviceController extends Controller {
|
|
65
|
+
* //The sn of the input is the one of the object path
|
|
66
|
+
* @DBusMethod('Status', DeviceSnDTO)
|
|
67
|
+
* @Return(StatusDTO)
|
|
68
|
+
* public async status(input: DeviceSnDTO): Promise<StatusDTO> {
|
|
69
|
+
* return {sn: input.sn, online: true} as StatusDTO
|
|
70
|
+
* }
|
|
71
|
+
* }
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export declare function DBusInterface<ClassConstructor extends typeof Controller>(name: string, options: DBusInterfaceOptions): (target: ClassConstructor) => void;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type { DTO, MethodDecorator } from '@lakutata/core';
|
|
2
|
+
import type { Controller } from '@lakutata/entrypoint';
|
|
3
|
+
import { ActionOptions } from '@lakutata/entrypoint/channel';
|
|
4
|
+
import type { DBusContext } from '../context/DBusContext.js';
|
|
5
|
+
/**
|
|
6
|
+
* The options of {@link DBusMethod}: the options of a controller action (`name`, `description`, `acl`, `rule`,
|
|
7
|
+
* `groups`, `middlewares`), with the D-Bus type of the method's result.
|
|
8
|
+
*/
|
|
9
|
+
export type DBusMethodOptions = ActionOptions<DBusContext> & {
|
|
10
|
+
/**
|
|
11
|
+
* The type of the method's result: a DTO (a dictionary of variants, `a{sv}`) or a D-Bus signature (`'s'`, `'b'`,
|
|
12
|
+
* `'x'`, `'v'`…). Without it, the type comes from the method's `@Return` schema: an object is `a{sv}`, a string
|
|
13
|
+
* `s`, a boolean `b`, an integer or a bigint `x`, another number `d`, an array `av`, any other value a variant `v`.
|
|
14
|
+
* @default the type of the `@Return` schema; without `@Return`, the method has no result
|
|
15
|
+
*/
|
|
16
|
+
returns?: typeof DTO | string;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Serve a controller action as a method of the D-Bus interface its controller declares with `@DBusInterface`. A method
|
|
20
|
+
* with a DTO takes one argument, a dictionary of variants (`a{sv}`) holding the DTO's properties; a method without one
|
|
21
|
+
* takes no argument. The input goes through the entrypoint's middlewares, the DTO validation and the access control,
|
|
22
|
+
* as in the other channels, and the variables of the object path template are merged into it.
|
|
23
|
+
*
|
|
24
|
+
* The result is encoded with the type of `returns` or of `@Return` (the dates as ISO strings, the `null` and
|
|
25
|
+
* `undefined` values left out, since a variant has no null); a method with neither returns nothing. An error thrown by
|
|
26
|
+
* the action is answered as a D-Bus error named after its `errno` (or its name), prefixed by the service name
|
|
27
|
+
* (`com.example.DeviceService.E_OFFLINE`), with its message; an `errno` already containing dots is used as it is.
|
|
28
|
+
* The same method may also carry the decorators of the other channels (`@ServiceAction`, `@GET`…).
|
|
29
|
+
* @param name The name of the method (`'Reboot'`): letters, digits and `_`, not starting with a digit; 255 characters at
|
|
30
|
+
* most. Unique in its interface.
|
|
31
|
+
* @returns The method decorator.
|
|
32
|
+
* @throws {TypeError} When the method is declared, if its name is invalid; when the adapter starts, if its controller
|
|
33
|
+
* has no `@DBusInterface`.
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* import {DTO} from 'lakutata'
|
|
37
|
+
* import {Controller} from 'lakutata/com/entrypoint'
|
|
38
|
+
* import {Expect, Return} from 'lakutata/decorator/dto'
|
|
39
|
+
* import {DBusInterface, DBusMethod} from '@lakutata/dbus'
|
|
40
|
+
*
|
|
41
|
+
* class ConfigureDTO extends DTO {
|
|
42
|
+
* @Expect(DTO.String().required())
|
|
43
|
+
* public sn: string
|
|
44
|
+
*
|
|
45
|
+
* @Expect(DTO.Number().integer().min(0).optional())
|
|
46
|
+
* public retries?: number
|
|
47
|
+
* }
|
|
48
|
+
*
|
|
49
|
+
* @DBusInterface('com.example.Manager', {path: '/com/example/Manager'})
|
|
50
|
+
* export class ManagerController extends Controller {
|
|
51
|
+
* //No argument, returns a string (s)
|
|
52
|
+
* @DBusMethod('Ping', {returns: 's'})
|
|
53
|
+
* public async ping(): Promise<string> {
|
|
54
|
+
* return 'pong'
|
|
55
|
+
* }
|
|
56
|
+
*
|
|
57
|
+
* //One argument a{sv}, returns a dictionary a{sv} (the type of @Return)
|
|
58
|
+
* @DBusMethod('Configure', ConfigureDTO, {description: 'Configure a device'})
|
|
59
|
+
* @Return(ConfigureDTO)
|
|
60
|
+
* public async configure(input: ConfigureDTO): Promise<ConfigureDTO> {
|
|
61
|
+
* return input
|
|
62
|
+
* }
|
|
63
|
+
*
|
|
64
|
+
* //No result
|
|
65
|
+
* @DBusMethod('Reset')
|
|
66
|
+
* public async reset(): Promise<void> {
|
|
67
|
+
* }
|
|
68
|
+
* }
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export declare function DBusMethod<ClassPrototype extends Controller, Method>(name: string): MethodDecorator<ClassPrototype, Method, any>;
|
|
72
|
+
/**
|
|
73
|
+
* Serve a controller action as a method of the D-Bus interface its controller declares with `@DBusInterface`: its input
|
|
74
|
+
* is the DTO, given by the client as one dictionary of variants (`a{sv}`); its result has the type of `@Return`.
|
|
75
|
+
* The input goes through the entrypoint's middlewares, the DTO validation and the access control, and the variables
|
|
76
|
+
* of the object path template are merged into it. An error thrown by the action is answered as a D-Bus error named
|
|
77
|
+
* after its `errno`, prefixed by the service name (`com.example.DeviceService.E_OFFLINE`).
|
|
78
|
+
* @param name The name of the method (`'Reboot'`): letters, digits and `_`, not starting with a digit; 255 characters at
|
|
79
|
+
* most. Unique in its interface.
|
|
80
|
+
* @param dtoConstructor The DTO of the method's input, given by the client as an `a{sv}` dictionary.
|
|
81
|
+
* @returns The method decorator.
|
|
82
|
+
* @throws {TypeError} When the method is declared, if its name is invalid; when the adapter starts, if its controller
|
|
83
|
+
* has no `@DBusInterface`.
|
|
84
|
+
*/
|
|
85
|
+
export declare function DBusMethod<ClassPrototype extends Controller, Method, DTOConstructor extends typeof DTO = typeof DTO>(name: string, dtoConstructor: DTOConstructor): MethodDecorator<ClassPrototype, Method, any>;
|
|
86
|
+
/**
|
|
87
|
+
* Serve a controller action as a method of the D-Bus interface its controller declares with `@DBusInterface`, with
|
|
88
|
+
* action options: it takes no argument; its result has the type of `returns` or of `@Return`.
|
|
89
|
+
* The input goes through the entrypoint's middlewares, the DTO validation and the access control, and the variables
|
|
90
|
+
* of the object path template are merged into it. An error thrown by the action is answered as a D-Bus error named
|
|
91
|
+
* after its `errno`, prefixed by the service name (`com.example.DeviceService.E_OFFLINE`).
|
|
92
|
+
* @param name The name of the method (`'Reboot'`): letters, digits and `_`, not starting with a digit; 255 characters at
|
|
93
|
+
* most. Unique in its interface.
|
|
94
|
+
* @param options The options of the action, and the type of its result (`returns`).
|
|
95
|
+
* @returns The method decorator.
|
|
96
|
+
* @throws {TypeError} When the method is declared, if its name is invalid; when the adapter starts, if its controller
|
|
97
|
+
* has no `@DBusInterface`.
|
|
98
|
+
*/
|
|
99
|
+
export declare function DBusMethod<ClassPrototype extends Controller, Method>(name: string, options: DBusMethodOptions): MethodDecorator<ClassPrototype, Method, any>;
|
|
100
|
+
/**
|
|
101
|
+
* Serve a controller action as a method of the D-Bus interface its controller declares with `@DBusInterface`, with
|
|
102
|
+
* action options: its input is the DTO, given by the client as one dictionary of variants (`a{sv}`); its result has the
|
|
103
|
+
* type of `returns` or of `@Return`.
|
|
104
|
+
* The input goes through the entrypoint's middlewares, the DTO validation and the access control, and the variables
|
|
105
|
+
* of the object path template are merged into it. An error thrown by the action is answered as a D-Bus error named
|
|
106
|
+
* after its `errno`, prefixed by the service name (`com.example.DeviceService.E_OFFLINE`).
|
|
107
|
+
* @param name The name of the method (`'Reboot'`): letters, digits and `_`, not starting with a digit; 255 characters at
|
|
108
|
+
* most. Unique in its interface.
|
|
109
|
+
* @param dtoConstructor The DTO of the method's input, given by the client as an `a{sv}` dictionary.
|
|
110
|
+
* @param options The options of the action, and the type of its result (`returns`).
|
|
111
|
+
* @returns The method decorator.
|
|
112
|
+
* @throws {TypeError} When the method is declared, if its name is invalid; when the adapter starts, if its controller
|
|
113
|
+
* has no `@DBusInterface`.
|
|
114
|
+
*/
|
|
115
|
+
export declare function DBusMethod<ClassPrototype extends Controller, Method, DTOConstructor extends typeof DTO = typeof DTO>(name: string, dtoConstructor: DTOConstructor, options: DBusMethodOptions): MethodDecorator<ClassPrototype, Method, any>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { DBusChannel } from '../channel/DBusChannel.js';
|
|
2
|
+
export { DBusContext, DBUS_CONTEXT_TYPE } from '../context/DBusContext.js';
|
|
3
|
+
export { type DBusContextParams } from '../types/DBusContextParams.js';
|
|
4
|
+
export { DBusInterface, type DBusInterfaceOptions } from '../decorators/DBusInterface.js';
|
|
5
|
+
export { DBusMethod, type DBusMethodOptions } from '../decorators/DBusMethod.js';
|
|
6
|
+
export { defineDBusSignal, defineDBusProperty, type DBusSignalDefinition, type DBusPropertyDefinition, type DBusPropertyOptions, type DBusInterfaceDeclaration } from '../lib/Declarations.js';
|
|
7
|
+
export { dbusEntrypoint, type DBusEntrypointOptions } from '../adapters/DBusEntrypoint.js';
|
|
8
|
+
export { DBusObjectManager, type DBusPropertyWrite } from '../components/DBusObjectManager.js';
|
|
9
|
+
export { DBusClientComponent, buildDBusClientOptions } from '../components/DBusClientComponent.js';
|
|
10
|
+
export type { DBusClientOptions } from '../lib/DBusClientOptions.js';
|
|
11
|
+
export { DBus, DBusInterface as DBusRemoteInterface, DBusObject, DBusService, LocalInterface, LocalObject, LocalService, createDBusError, DBusSignedValue, DBusSignalEmitter, Signature, RequestNameFlags, RequestNameResultCode, type BusNameBasicInfo, type ConnectOpts, type DecodeOpts, type InvokeOpts } from 'dbus-sdk';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { DecodeOpts } from 'dbus-sdk';
|
|
2
|
+
/**
|
|
3
|
+
* The options of {@link buildDBusClientOptions}: the bus a {@link DBusClientComponent} connects to, and how it decodes
|
|
4
|
+
* the replies.
|
|
5
|
+
*/
|
|
6
|
+
export interface DBusClientOptions {
|
|
7
|
+
/**
|
|
8
|
+
* The address of the bus: `'unix:path=/var/run/dbus/system_bus_socket'` (the system bus),
|
|
9
|
+
* `'unix:path=/run/user/1000/bus'`, `'tcp:host=127.0.0.1,port=5555'`; the value of `DBUS_SESSION_BUS_ADDRESS` for
|
|
10
|
+
* the session bus.
|
|
11
|
+
*/
|
|
12
|
+
busAddress: string;
|
|
13
|
+
/**
|
|
14
|
+
* How long the connection to the bus may take, in milliseconds (a positive integer).
|
|
15
|
+
* @default 20000
|
|
16
|
+
*/
|
|
17
|
+
timeout?: number;
|
|
18
|
+
/**
|
|
19
|
+
* How long a call may wait for its reply, in milliseconds (a positive integer); a call's own `timeout` overrides it.
|
|
20
|
+
* @default dbus-sdk's default
|
|
21
|
+
*/
|
|
22
|
+
callTimeout?: number;
|
|
23
|
+
/**
|
|
24
|
+
* How the replies and the signals are decoded (`DecodeOpts` of `dbus-sdk`): `types` (`'none'`, `'variants'`,
|
|
25
|
+
* `'all'`: where the values keep their D-Bus types as typed values), `dictionaries` (`'object'` or `'map'`),
|
|
26
|
+
* `int64` (`'number'` or `'bigint'`).
|
|
27
|
+
* @default {int64: 'number'} (the 64-bit integers as numbers when they are safe integers, else bigints)
|
|
28
|
+
*/
|
|
29
|
+
decode?: DecodeOpts;
|
|
30
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { DTO, type Schema } from '@lakutata/core';
|
|
2
|
+
/**
|
|
3
|
+
* A D-Bus signal, built by {@link defineDBusSignal}: list it in the `signals` of `@DBusInterface`, and emit it with
|
|
4
|
+
* {@link DBusObjectManager.emitSignal}. The definition itself identifies the signal: two definitions with the same
|
|
5
|
+
* name are two signals.
|
|
6
|
+
* @typeParam T The data the signal carries.
|
|
7
|
+
*/
|
|
8
|
+
export type DBusSignalDefinition<T = unknown> = {
|
|
9
|
+
/**
|
|
10
|
+
* Always `'signal'`.
|
|
11
|
+
*/
|
|
12
|
+
readonly kind: 'signal';
|
|
13
|
+
/**
|
|
14
|
+
* The member name of the signal (`'Changed'`).
|
|
15
|
+
*/
|
|
16
|
+
readonly name: string;
|
|
17
|
+
/**
|
|
18
|
+
* The D-Bus signature of the signal's one argument: `a{sv}` for a DTO, or the signature given.
|
|
19
|
+
*/
|
|
20
|
+
readonly type: string;
|
|
21
|
+
/**
|
|
22
|
+
* Validate the data of an emission: with the DTO when the signal has one, returning the validated data; as it is
|
|
23
|
+
* otherwise.
|
|
24
|
+
* @param data The data to emit.
|
|
25
|
+
* @returns The data validated.
|
|
26
|
+
* @throws {InvalidValueException} When the data does not match the signal's DTO.
|
|
27
|
+
*/
|
|
28
|
+
readonly validate: (data: T) => T;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* A D-Bus property, built by {@link defineDBusProperty}: list it in the `properties` of `@DBusInterface`. Its values
|
|
32
|
+
* are kept by {@link DBusObjectManager}, one per object path: the application sets them with
|
|
33
|
+
* {@link DBusObjectManager.setPropertyValue}, the clients read them, and write them when the property is writable. The
|
|
34
|
+
* definition itself identifies the property.
|
|
35
|
+
* @typeParam T The values of the property.
|
|
36
|
+
*/
|
|
37
|
+
export type DBusPropertyDefinition<T = unknown> = {
|
|
38
|
+
/**
|
|
39
|
+
* Always `'property'`.
|
|
40
|
+
*/
|
|
41
|
+
readonly kind: 'property';
|
|
42
|
+
/**
|
|
43
|
+
* The member name of the property (`'State'`).
|
|
44
|
+
*/
|
|
45
|
+
readonly name: string;
|
|
46
|
+
/**
|
|
47
|
+
* The D-Bus signature of the property's values (`'s'`, `'i'`, `'a{sv}'`…).
|
|
48
|
+
*/
|
|
49
|
+
readonly type: string;
|
|
50
|
+
/**
|
|
51
|
+
* Whether the clients may write the property (`org.freedesktop.DBus.Properties.Set`); a read-only property refuses
|
|
52
|
+
* their writes with a D-Bus error.
|
|
53
|
+
*/
|
|
54
|
+
readonly writable: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* The value of the property on every object until it is set.
|
|
57
|
+
*/
|
|
58
|
+
readonly initial?: T;
|
|
59
|
+
/**
|
|
60
|
+
* Validate a value of the property, synchronously, with its `schema` (the value as it is without a schema).
|
|
61
|
+
* @param value The value set by the application or written by a client.
|
|
62
|
+
* @returns The value validated.
|
|
63
|
+
* @throws {InvalidValueException} When the value does not match the schema; a client writing it gets a D-Bus error.
|
|
64
|
+
*/
|
|
65
|
+
readonly validate: (value: T) => T;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* The options of {@link defineDBusProperty}.
|
|
69
|
+
* @typeParam T The values of the property.
|
|
70
|
+
*/
|
|
71
|
+
export type DBusPropertyOptions<T> = {
|
|
72
|
+
/**
|
|
73
|
+
* Whether the clients may write the property. A value written is validated with `schema`, kept, and announced by
|
|
74
|
+
* `DBusObjectManager` with a `propertyWritten` event and to the clients with `PropertiesChanged`.
|
|
75
|
+
* @default false
|
|
76
|
+
*/
|
|
77
|
+
writable?: boolean;
|
|
78
|
+
/**
|
|
79
|
+
* The value of the property on every object until it is set; it is not validated.
|
|
80
|
+
* @default undefined
|
|
81
|
+
*/
|
|
82
|
+
initial?: T;
|
|
83
|
+
/**
|
|
84
|
+
* The schema validating the values of the property (`DTO.Number().integer().min(0)`), the ones set by the
|
|
85
|
+
* application and the ones written by the clients.
|
|
86
|
+
* @default none: every value is accepted
|
|
87
|
+
*/
|
|
88
|
+
schema?: Schema;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* The declaration of a D-Bus interface served by a controller, as `@DBusInterface` records it.
|
|
92
|
+
*/
|
|
93
|
+
export type DBusInterfaceDeclaration = {
|
|
94
|
+
/**
|
|
95
|
+
* The name of the interface (`'com.example.Device'`).
|
|
96
|
+
*/
|
|
97
|
+
readonly interface: string;
|
|
98
|
+
/**
|
|
99
|
+
* The object path, or path template, of the interface (`'/com/example/Devices/{sn}'`).
|
|
100
|
+
*/
|
|
101
|
+
readonly path: string;
|
|
102
|
+
/**
|
|
103
|
+
* The signals of the interface.
|
|
104
|
+
*/
|
|
105
|
+
readonly signals: DBusSignalDefinition<any>[];
|
|
106
|
+
/**
|
|
107
|
+
* The properties of the interface.
|
|
108
|
+
*/
|
|
109
|
+
readonly properties: DBusPropertyDefinition<any>[];
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* Declare a D-Bus signal, to list in the `signals` of one or more `@DBusInterface`. The signal has one argument: a
|
|
113
|
+
* dictionary of variants (`a{sv}`) holding a DTO, or a value of the signature given. Its data is validated by its DTO
|
|
114
|
+
* when it is emitted.
|
|
115
|
+
* @typeParam T The data the signal carries.
|
|
116
|
+
* @param name The member name of the signal (`'Changed'`): letters, digits and `_`, not starting with a digit; 255
|
|
117
|
+
* characters at most.
|
|
118
|
+
* @param data The DTO of the signal's data, or the D-Bus signature of its argument (`'s'`, `'a{sv}'`…); with a
|
|
119
|
+
* signature, the data is not validated. `'a{sv}'` by default.
|
|
120
|
+
* @returns The signal's definition.
|
|
121
|
+
* @throws {TypeError} When the name is invalid.
|
|
122
|
+
* @example
|
|
123
|
+
* ```typescript
|
|
124
|
+
* import {DTO} from 'lakutata'
|
|
125
|
+
* import {Expect} from 'lakutata/decorator/dto'
|
|
126
|
+
* import {defineDBusSignal, type DBusObjectManager} from '@lakutata/dbus'
|
|
127
|
+
*
|
|
128
|
+
* class StatusDTO extends DTO {
|
|
129
|
+
* @Expect(DTO.String().required())
|
|
130
|
+
* public sn: string
|
|
131
|
+
*
|
|
132
|
+
* @Expect(DTO.Boolean().required())
|
|
133
|
+
* public online: boolean
|
|
134
|
+
* }
|
|
135
|
+
*
|
|
136
|
+
* //A dictionary of variants a{sv}, validated by StatusDTO
|
|
137
|
+
* export const DeviceChanged = defineDBusSignal<StatusDTO>('Changed', StatusDTO)
|
|
138
|
+
* //A string s
|
|
139
|
+
* export const DeviceMessage = defineDBusSignal<string>('Message', 's')
|
|
140
|
+
*
|
|
141
|
+
* declare const manager: DBusObjectManager
|
|
142
|
+
* manager.emitSignal('/com/example/Devices/A1', DeviceChanged, {sn: 'A1', online: true} as StatusDTO)
|
|
143
|
+
* manager.emitSignal('/com/example/Devices/A1', DeviceMessage, 'Rebooted')
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
export declare function defineDBusSignal<T = Record<string, unknown>>(name: string, data?: typeof DTO | string): DBusSignalDefinition<T>;
|
|
147
|
+
/**
|
|
148
|
+
* Declare a D-Bus property, to list in the `properties` of one or more `@DBusInterface`. Its values are kept by
|
|
149
|
+
* `DBusObjectManager`, one per object: the application sets them, the clients read them (`Get`, `GetAll`) and are told
|
|
150
|
+
* of their changes (`PropertiesChanged`), and write them when the property is writable.
|
|
151
|
+
* @typeParam T The values of the property.
|
|
152
|
+
* @param name The member name of the property (`'State'`): letters, digits and `_`, not starting with a digit; 255
|
|
153
|
+
* characters at most.
|
|
154
|
+
* @param type The D-Bus signature of its values (`'s'`, `'i'`, `'b'`, `'a{sv}'`…); it is not checked against `schema`.
|
|
155
|
+
* @param options Whether the clients may write it, its initial value and the schema of its values; none by default
|
|
156
|
+
* (read-only, no initial value, every value accepted).
|
|
157
|
+
* @returns The property's definition.
|
|
158
|
+
* @throws {TypeError} When the name is invalid.
|
|
159
|
+
* @example
|
|
160
|
+
* ```typescript
|
|
161
|
+
* import {DTO} from 'lakutata'
|
|
162
|
+
* import {defineDBusProperty, type DBusObjectManager, type DBusPropertyWrite} from '@lakutata/dbus'
|
|
163
|
+
*
|
|
164
|
+
* //Read-only, "idle" until it is set
|
|
165
|
+
* export const DeviceState = defineDBusProperty<string>('State', 's', {initial: 'idle'})
|
|
166
|
+
* //Written by the clients, from 0 to 10
|
|
167
|
+
* export const DeviceLevel = defineDBusProperty<number>('Level', 'i', {writable: true, initial: 1, schema: DTO.Number().integer().min(0).max(10)})
|
|
168
|
+
*
|
|
169
|
+
* declare const manager: DBusObjectManager
|
|
170
|
+
* manager.setPropertyValue('/com/example/Devices/A1', DeviceState, 'running')
|
|
171
|
+
* manager.on('propertyWritten', (write: DBusPropertyWrite): void => {
|
|
172
|
+
* if (write.property === DeviceLevel) console.log(`${write.path}: level ${write.value}`)
|
|
173
|
+
* })
|
|
174
|
+
* ```
|
|
175
|
+
*/
|
|
176
|
+
export declare function defineDBusProperty<T = unknown>(name: string, type: string, options?: DBusPropertyOptions<T>): DBusPropertyDefinition<T>;
|
|
177
|
+
/**
|
|
178
|
+
* Keep the declaration of the interface of a controller
|
|
179
|
+
* @param controller
|
|
180
|
+
* @param declaration
|
|
181
|
+
*/
|
|
182
|
+
export declare function setDBusInterfaceDeclaration(controller: Function, declaration: DBusInterfaceDeclaration): void;
|
|
183
|
+
/**
|
|
184
|
+
* The declaration of the interface of a controller, or of its nearest parent class declaring one
|
|
185
|
+
* @param controller
|
|
186
|
+
*/
|
|
187
|
+
export declare function getDBusInterfaceDeclaration(controller: Function): DBusInterfaceDeclaration | undefined;
|