@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.
Files changed (81) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +253 -25
  3. package/dist/cjs/adapters/DBusEntrypoint.d.ts +89 -0
  4. package/dist/cjs/adapters/DBusEntrypoint.js +280 -0
  5. package/dist/cjs/channel/DBusChannel.d.ts +36 -0
  6. package/dist/cjs/channel/DBusChannel.js +70 -0
  7. package/dist/cjs/components/DBusClientComponent.d.ts +494 -0
  8. package/dist/cjs/components/DBusClientComponent.js +272 -0
  9. package/dist/cjs/components/DBusObjectManager.d.ts +164 -0
  10. package/dist/cjs/components/DBusObjectManager.js +200 -0
  11. package/dist/cjs/context/DBusContext.d.ts +52 -0
  12. package/dist/cjs/context/DBusContext.js +68 -0
  13. package/dist/cjs/decorators/DBusInterface.d.ts +74 -0
  14. package/dist/cjs/decorators/DBusInterface.js +63 -0
  15. package/dist/cjs/decorators/DBusMethod.d.ts +115 -0
  16. package/dist/cjs/decorators/DBusMethod.js +20 -0
  17. package/dist/cjs/exports/DBus.d.ts +11 -0
  18. package/dist/cjs/exports/DBus.js +42 -0
  19. package/dist/cjs/lib/DBusClientOptions.d.ts +30 -0
  20. package/dist/cjs/lib/Declarations.d.ts +187 -0
  21. package/dist/cjs/lib/Declarations.js +113 -0
  22. package/dist/cjs/lib/Names.d.ts +35 -0
  23. package/dist/cjs/lib/Names.js +80 -0
  24. package/dist/cjs/lib/Signature.d.ts +14 -0
  25. package/dist/cjs/lib/Signature.js +53 -0
  26. package/dist/cjs/package.json +1 -0
  27. package/dist/cjs/types/DBusContextParams.d.ts +22 -0
  28. package/dist/cjs/types/DBusContextParams.js +2 -0
  29. package/dist/esm/adapters/DBusEntrypoint.js +274 -0
  30. package/dist/esm/channel/DBusChannel.js +67 -0
  31. package/dist/esm/components/DBusClientComponent.js +267 -0
  32. package/dist/esm/components/DBusObjectManager.js +197 -0
  33. package/dist/esm/context/DBusContext.js +64 -0
  34. package/dist/esm/decorators/DBusInterface.js +60 -0
  35. package/dist/esm/decorators/DBusMethod.js +17 -0
  36. package/dist/esm/exports/DBus.js +12 -0
  37. package/dist/esm/lib/DBusClientOptions.js +1 -0
  38. package/dist/esm/lib/Declarations.js +107 -0
  39. package/dist/esm/lib/Names.js +73 -0
  40. package/dist/esm/lib/Signature.js +49 -0
  41. package/dist/esm/types/DBusContextParams.js +1 -0
  42. package/dist/types/adapters/DBusEntrypoint.d.ts +89 -0
  43. package/dist/types/channel/DBusChannel.d.ts +36 -0
  44. package/dist/types/components/DBusClientComponent.d.ts +494 -0
  45. package/dist/types/components/DBusObjectManager.d.ts +164 -0
  46. package/dist/types/context/DBusContext.d.ts +52 -0
  47. package/dist/types/decorators/DBusInterface.d.ts +74 -0
  48. package/dist/types/decorators/DBusMethod.d.ts +115 -0
  49. package/dist/types/exports/DBus.d.ts +11 -0
  50. package/dist/types/lib/DBusClientOptions.d.ts +30 -0
  51. package/dist/types/lib/Declarations.d.ts +187 -0
  52. package/dist/types/lib/Names.d.ts +35 -0
  53. package/dist/types/lib/Signature.d.ts +14 -0
  54. package/dist/types/types/DBusContextParams.d.ts +22 -0
  55. package/package.json +38 -39
  56. package/CHANGELOG.md +0 -153
  57. package/dist/CommonExports.d.ts +0 -2
  58. package/dist/CommonExports.d.ts.map +0 -1
  59. package/dist/CommonExports.js +0 -44
  60. package/dist/ComponentExports.d.ts +0 -2
  61. package/dist/ComponentExports.d.ts.map +0 -1
  62. package/dist/ComponentExports.js +0 -5
  63. package/dist/ProviderExports.d.ts +0 -2
  64. package/dist/ProviderExports.d.ts.map +0 -1
  65. package/dist/ProviderExports.js +0 -5
  66. package/dist/components/DBusClientComponent.d.ts +0 -75
  67. package/dist/components/DBusClientComponent.d.ts.map +0 -1
  68. package/dist/components/DBusClientComponent.js +0 -125
  69. package/dist/interfaces/DBusClientOptions.d.ts +0 -7
  70. package/dist/interfaces/DBusClientOptions.d.ts.map +0 -1
  71. package/dist/providers/DBusClientProvider.d.ts +0 -75
  72. package/dist/providers/DBusClientProvider.d.ts.map +0 -1
  73. package/dist/providers/DBusClientProvider.js +0 -125
  74. package/dist/tests/DBusTest.spec.d.ts +0 -2
  75. package/dist/tests/DBusTest.spec.d.ts.map +0 -1
  76. package/dist/tests/DBusTest.spec.js +0 -26
  77. package/dist/tests/Test.d.ts +0 -9
  78. package/dist/tests/Test.d.ts.map +0 -1
  79. package/dist/tests/Test.js +0 -80
  80. package/tsconfig.json +0 -7
  81. /package/dist/{interfaces → cjs/lib}/DBusClientOptions.js +0 -0
package/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023-present Lakutata
4
+
5
+ All rights reserved
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
package/README.md CHANGED
@@ -1,38 +1,266 @@
1
- <div align="center">
1
+ # @lakutata/dbus
2
2
 
3
- ![lakutata](https://socialify.git.ci/lakutata/lakutata/image?description=1&descriptionEditable=An%20IoC-based%20universal%20application%20framework&font=Source%20Code%20Pro&forks=1&language=1&logo=https%3A%2F%2Fraw.githubusercontent.com%2Flakutata%2Flakutata%2Fmain%2Fassets%2Flogo.svg&name=1&pattern=Circuit%20Board&stargazers=1&theme=Auto)
3
+ The D-Bus channel of the [lakutata](https://github.com/lakutata/lakutata) framework: the application owns a service
4
+ name on a bus (the system bus, the session bus or a private bus) and serves its controllers as the interfaces of D-Bus
5
+ objects: their methods, properties and signals. It also has a D-Bus client component, to call the other services of a
6
+ bus, read their properties and listen to their signals. The protocol is implemented by
7
+ [dbus-sdk](https://github.com/myq1991/node-dbus-sdk), whose classes this package re-exports. The umbrella package
8
+ `lakutata` does not re-export it: import it from `@lakutata/dbus`.
4
9
 
5
- </div>
10
+ ## Installation
6
11
 
7
- <div align="center">
12
+ ```shell
13
+ npm install lakutata @lakutata/dbus
14
+ ```
8
15
 
9
- ![node-lts](https://img.shields.io/node/v-lts/lakutata?style=for-the-badge&logo=nodedotjs&color=rgb(128%2C189%2C65))
10
- ![npm](https://img.shields.io/npm/v/lakutata?style=for-the-badge&logo=npm&color=rgb(128%2C189%2C65))
11
- ![npm](https://img.shields.io/npm/dm/lakutata?style=for-the-badge&logo=npm&color=rgb(128%2C189%2C65))
12
- ![NPM](https://img.shields.io/npm/l/lakutata?style=for-the-badge&logo=github&color=rgb(128%2C189%2C65))
13
- ![Codacy grade](https://img.shields.io/codacy/grade/0f16d1c355494415ad7733f8f22f7d36?style=for-the-badge&logo=codacy)
16
+ - It needs a D-Bus daemon, as on Linux: the system bus (`/var/run/dbus/system_bus_socket`), the session bus of a
17
+ desktop session (`DBUS_SESSION_BUS_ADDRESS`), or a private `dbus-daemon`. Owning a name on the system bus needs a bus
18
+ policy allowing it (a file of `/etc/dbus-1/system.d/`).
19
+ - Node.js 22 or later; its peer dependencies `@lakutata/core` and `@lakutata/entrypoint` come with `lakutata`.
14
20
 
15
- </div>
21
+ ## Usage
16
22
 
17
- ## 💫 Description
23
+ ### A D-Bus service
18
24
 
19
- Lakutata is a generic development framework written in TypeScript and designed with IoC principles. Its main objective
20
- is to provide a universal, efficient, and stable development framework. The design goals of Lakutata are not limited to
21
- web application development; it aims to serve as a foundational framework for desktop applications, embedded systems
22
- applications, and web applications. The framework primarily adopts an OOP (Object-Oriented Programming) approach and
23
- encapsulates functionalities such as subprocesses, threads, permission management, and database ORM, enabling the
24
- framework to be used out of the box.
25
+ `dbusEntrypoint` is the `dbus` adapter of the entrypoint. A controller declared with `@DBusInterface` serves an
26
+ interface at an object path; its `@DBusMethod` actions are the interface's methods.
25
27
 
26
- In addition, Lakutata also supports the integration of third-party libraries into the application, allowing developers
27
- to freely encapsulate and call third-party modules using Lakutata's dependency injection.
28
+ ```typescript
29
+ import {Application, DTO} from 'lakutata'
30
+ import {buildEntrypoints, Controller} from 'lakutata/com/entrypoint'
31
+ import {Expect, Return} from 'lakutata/decorator/dto'
32
+ import {dbusEntrypoint, DBusInterface, DBusMethod} from '@lakutata/dbus'
28
33
 
29
- ## ✨ Getting started
34
+ class ConfigureDTO extends DTO {
35
+ @Expect(DTO.String().required())
36
+ public sn: string
30
37
 
31
- - Install lakutata DBus SDK
32
- ```shell
33
- npm install @lakutata/dbus
38
+ @Expect(DTO.Number().integer().min(0).optional())
39
+ public retries?: number
40
+ }
41
+
42
+ @DBusInterface('com.example.Manager', {path: '/com/example/Manager'})
43
+ class ManagerController extends Controller {
44
+ //No argument, returns a string (s)
45
+ @DBusMethod('Ping', {returns: 's'})
46
+ public async ping(): Promise<string> {
47
+ return 'pong'
48
+ }
49
+
50
+ //One argument a{sv}, returns a dictionary a{sv} (the type of @Return)
51
+ @DBusMethod('Configure', ConfigureDTO)
52
+ @Return(ConfigureDTO)
53
+ public async configure(input: ConfigureDTO): Promise<ConfigureDTO> {
54
+ return input
55
+ }
56
+ }
57
+
58
+ //busctl --user call com.example.DeviceService /com/example/Manager com.example.Manager Ping
59
+ Application.run(() => ({
60
+ id: 'devices.app',
61
+ name: 'Devices',
62
+ components: {
63
+ entrypoint: buildEntrypoints({
64
+ controllers: [ManagerController],
65
+ dbus: dbusEntrypoint({bus: 'session', service: 'com.example.DeviceService'})
66
+ })
67
+ },
68
+ bootstrap: ['entrypoint']
69
+ }))
70
+ ```
71
+
72
+ - **The input** of a method with a DTO is one argument, a dictionary of variants (`a{sv}`) holding the DTO's
73
+ properties; a method without a DTO takes no argument. The input goes through the middlewares, the validation and the
74
+ access control of the entrypoint, as in the other channels.
75
+ - **The result** has the type of the `returns` option (a DTO is `a{sv}`, or a signature such as `'s'`), or else the type
76
+ of the `@Return` schema: an object is `a{sv}`, a string `s`, a boolean `b`, an integer `x`, another number `d`, an
77
+ array `av`, the other values a variant `v`. Without them, the method has no result. The dates are sent as ISO
78
+ strings, the `null` and `undefined` values are left out (a variant has no null).
79
+ - **The errors** reach the callers as D-Bus errors named after their `errno`, prefixed by the service name
80
+ (`com.example.DeviceService.E_OFFLINE`), with their message.
81
+ - **The context** of the methods is a `DBusContext`: `context.path`, `context.interface` and `context.member`.
82
+ - **Several controllers** at the same path are the interfaces of the same objects. The objects implement
83
+ `org.freedesktop.DBus.Properties`, `Introspectable` and `Peer`, and the root object `/` implements `ObjectManager`.
84
+ - A method may also carry the decorators of the other channels (`@ServiceAction`, `@GET`…).
85
+
86
+ ### The adapter
87
+
88
+ ```text
89
+ dbus: dbusEntrypoint({bus: 'system', service: 'com.example.DeviceService', replaceExisting: true})
90
+ ```
91
+
92
+ - `bus`: `'session'` (default, the address in `DBUS_SESSION_BUS_ADDRESS`), `'system'` (`DBUS_SYSTEM_BUS_ADDRESS`, else
93
+ `unix:path=/var/run/dbus/system_bus_socket`), the address of a bus (`unix:path=…`, `tcp:host=…,port=…`), or the path
94
+ of the socket of a private bus.
95
+ - `service`: the well-known name of the service. The adapter fails to start when another connection owns it
96
+ (`replaceExisting` takes it when its owner allows it, `allowReplacement` lets another service take it).
97
+ - `name` and `middlewares`: the adapter's name, and the middlewares of its calls (after the global ones).
98
+ - It stops gracefully with the entrypoint: the name is released, the calls in progress end, then the connection
99
+ closes.
100
+
101
+ ### Objects, properties and signals
102
+
103
+ The path of an interface is either a path (`/com/example/Manager`), whose object is exported when the adapter starts
104
+ and stays exported while it runs (`DBusObjectManager.removeObject()` does not remove it), or a template
105
+ (`/com/example/Devices/{sn}`), whose objects are added and removed with `DBusObjectManager`. The
106
+ variables of the path are merged into the input of the methods, as the route parameters (they take precedence over the
107
+ client's input).
108
+
109
+ A property is a value of an object, kept by `DBusObjectManager`: the application sets it, the clients read it and are
110
+ notified of its changes (`PropertiesChanged`); until it is set, its value is its `initial` value. A `writable`
111
+ property is also written by the clients: the value is validated by the property's `schema` (the errors are given to the
112
+ client), kept, and `DBusObjectManager` emits `propertyWritten`. A write which must reach a device, or may fail after
113
+ the validation, is better a method: its errors are given to the caller. A signal's data is validated by its DTO when it
114
+ is emitted.
115
+
116
+ ```typescript
117
+ import {Component, DTO} from 'lakutata'
118
+ import {Controller} from 'lakutata/com/entrypoint'
119
+ import {Expect, Return} from 'lakutata/decorator/dto'
120
+ import {Inject} from 'lakutata/decorator/di'
121
+ import {
122
+ DBusInterface,
123
+ DBusMethod,
124
+ DBusObjectManager,
125
+ defineDBusProperty,
126
+ defineDBusSignal,
127
+ type DBusPropertyWrite
128
+ } from '@lakutata/dbus'
129
+
130
+ class DeviceSnDTO extends DTO {
131
+ @Expect(DTO.String().required())
132
+ public sn: string
133
+ }
134
+
135
+ class StatusDTO extends DTO {
136
+ @Expect(DTO.String().required())
137
+ public sn: string
138
+
139
+ @Expect(DTO.Boolean().required())
140
+ public online: boolean
141
+ }
142
+
143
+ export const DeviceChanged = defineDBusSignal<StatusDTO>('Changed', StatusDTO)
144
+ export const DeviceState = defineDBusProperty<string>('State', 's', {initial: 'idle'})
145
+ export const DeviceLevel = defineDBusProperty<number>('Level', 'i', {writable: true, initial: 1, schema: DTO.Number().integer().min(0).max(10)})
146
+
147
+ @DBusInterface('com.example.Device', {path: '/com/example/Devices/{sn}', signals: [DeviceChanged], properties: [DeviceState, DeviceLevel]})
148
+ export class DeviceController extends Controller {
149
+ //The sn of the input is the one of the object path
150
+ @DBusMethod('Status', DeviceSnDTO)
151
+ @Return(StatusDTO)
152
+ public async status(input: DeviceSnDTO): Promise<StatusDTO> {
153
+ return {sn: input.sn, online: true} as StatusDTO
154
+ }
155
+ }
156
+
157
+ //Registered in the components of the application
158
+ export class Devices extends Component {
159
+ @Inject(DBusObjectManager)
160
+ protected readonly manager: DBusObjectManager
161
+
162
+ protected async init(): Promise<void> {
163
+ this.manager.on('propertyWritten', (write: DBusPropertyWrite): void => {
164
+ if (write.property === DeviceLevel) console.log(`${write.path}: level ${write.value}`)
165
+ })
166
+ }
167
+
168
+ public plug(sn: string): void {
169
+ const path: string = `/com/example/Devices/${sn}`
170
+ //Exported by the interfaces of the matching templates
171
+ this.manager.addObject(path)
172
+ this.manager.setPropertyValue(path, DeviceState, 'running')
173
+ this.manager.emitSignal(path, DeviceChanged, {sn: sn, online: true} as StatusDTO)
174
+ }
175
+
176
+ public unplug(sn: string): void {
177
+ this.manager.removeObject(`/com/example/Devices/${sn}`)
178
+ }
179
+ }
34
180
  ```
35
181
 
36
- ## 🌎 License
182
+ `DBusObjectManager` is autoloaded, one per application: inject it in any object (`@Inject(DBusObjectManager)`) or get
183
+ it (`getObject(DBusObjectManager)`). The objects added before the adapter starts are exported when it starts. The
184
+ clients are told of the objects added and removed by the `ObjectManager` of the service (`InterfacesAdded`,
185
+ `InterfacesRemoved`).
186
+
187
+ ### The client
188
+
189
+ `DBusClientComponent` connects to a bus when it is created, to call the services, read their objects and properties,
190
+ and listen to their signals; it disconnects when the application stops.
191
+
192
+ ```typescript
193
+ import {Application} from 'lakutata'
194
+ import {DBusClientComponent, type DBusRemoteInterface} from '@lakutata/dbus'
195
+
196
+ Application
197
+ .run(() => ({
198
+ id: 'client.app',
199
+ name: 'Client',
200
+ components: {
201
+ dbus: {class: DBusClientComponent, busAddress: 'unix:path=/var/run/dbus/system_bus_socket', timeout: 5000}
202
+ }
203
+ }))
204
+ .onLaunched(async (app: Application): Promise<void> => {
205
+ const dbus: DBusClientComponent = await app.getObject('dbus')
206
+ //A method call with an explicit signature: the output arguments, as an array
207
+ const [status] = await dbus.invoke({
208
+ service: 'com.example.DeviceService',
209
+ objectPath: '/com/example/Devices/A1',
210
+ interface: 'com.example.Device',
211
+ method: 'Status',
212
+ signature: 'a{sv}',
213
+ args: [{sn: 'A1'}]
214
+ })
215
+ console.log(status)
216
+ //An interface built from the introspection of its object
217
+ const device: DBusRemoteInterface = await dbus.interface('com.example.DeviceService', '/com/example/Devices/A1', 'com.example.Device')
218
+ console.log(await device.property.State.get())
219
+ device.signal.on('Changed', (data: unknown): void => console.log(data))
220
+ //The events of the connection
221
+ dbus.on('nameOwnerChanged', (name: string, oldOwner: string, newOwner: string): void => console.log(name, oldOwner, newOwner))
222
+ })
223
+ ```
224
+
225
+ `buildDBusClientOptions(options)` builds the same declaration from typed options:
226
+ `dbus: buildDBusClientOptions({busAddress: 'unix:path=/var/run/dbus/system_bus_socket'})`.
227
+
228
+ ## API
229
+
230
+ | Export | What it is |
231
+ |---|---|
232
+ | `dbusEntrypoint`, `DBusEntrypointOptions` | The adapter of the entrypoint (its `dbus` option): the bus, the service name |
233
+ | `DBusInterface`, `DBusInterfaceOptions` | Class decorator: a controller served as a D-Bus interface at an object path or path template |
234
+ | `DBusMethod`, `DBusMethodOptions` | Method decorator: an action served as a method of the interface, the type of its result |
235
+ | `defineDBusSignal`, `DBusSignalDefinition` | Declares a signal, its DTO or signature |
236
+ | `defineDBusProperty`, `DBusPropertyDefinition`, `DBusPropertyOptions` | Declares a property: its signature, `writable`, `initial`, `schema` |
237
+ | `DBusInterfaceDeclaration` | The declaration `@DBusInterface` records |
238
+ | `DBusObjectManager` | The objects of the templates, the property values and the signals: `addObject`, `removeObject`, `hasObject`, `objects`, `setPropertyValue`, `getPropertyValue`, `emitSignal`; the `propertyWritten` event |
239
+ | `DBusPropertyWrite` | A property written by a client, the argument of `propertyWritten` |
240
+ | `DBusContext`, `DBusContextParams`, `DBUS_CONTEXT_TYPE` | The context of the method calls: `path`, `interface`, `member` |
241
+ | `DBusChannel` | The definition of the `dbus` channel, for the custom adapters |
242
+ | `DBusClientComponent` | The client: `invoke`, `interface`, `interfaceSignal`, `object`, `service`, `services`, `listNames`, `listServices`, `nameHasOwner`, `getNameOwner`, `addMatch`, the connection events |
243
+ | `buildDBusClientOptions`, `DBusClientOptions` | The client's declaration and options: `busAddress`, `timeout`, `callTimeout`, `decode` (`DecodeOpts` of `dbus-sdk`; the 64-bit integers are numbers by default) |
244
+ | `DBus`, `DBusRemoteInterface`, `DBusObject`, `DBusService`, `LocalService`, `LocalObject`, `LocalInterface`, `DBusSignedValue`, `DBusSignalEmitter`, `Signature`, `createDBusError`, `RequestNameFlags`, `RequestNameResultCode`, `BusNameBasicInfo`, `ConnectOpts`, `DecodeOpts`, `InvokeOpts` | Re-exported from dbus-sdk 2 (`DBusRemoteInterface` is its `DBusInterface`; see its MIGRATION.md for the changes from 1.x) |
245
+
246
+ The typings document each declaration with examples.
247
+
248
+ ## Errors
249
+
250
+ | Error | When |
251
+ |---|---|
252
+ | `TypeError` | An invalid interface, member or service name, or object path, when the class is declared or `dbusEntrypoint()` is called; `DBusObjectManager.addObject()` with a template; the start of the adapter, when a `@DBusMethod` belongs to a controller without `@DBusInterface` |
253
+ | `Error` (`The DBus name … is owned by another service`) | The adapter's start, when another connection owns the service name; the entrypoint fails to start |
254
+ | The errors of dbus-sdk (`UnknownBusAddressError`, a connection error…) | The adapter's start or the client's creation, when the bus cannot be reached; the client's calls, when a method answers a D-Bus error |
255
+ | `InvalidValueException` (from `lakutata`) | `setPropertyValue()` or `emitSignal()` with a value its schema or DTO refuses; the client's options when it is created |
256
+
257
+ The errors thrown by the actions are given to the callers as D-Bus errors named after their `errno`
258
+ (`com.example.DeviceService.E_OFFLINE`), with their message; a client writing an invalid property value gets a D-Bus
259
+ error too.
260
+
261
+ ## See also
37
262
 
38
- Lakutata is [MIT licensed](LICENSE).
263
+ - `@lakutata/entrypoint` (`lakutata/com/entrypoint`): the entrypoint, the controllers, the middlewares and the access
264
+ control (`doc/en/ActionPattern.md` of the package `lakutata`, Chinese in `doc/zh`).
265
+ - [dbus-sdk](https://github.com/myq1991/node-dbus-sdk): the D-Bus protocol, its client classes and its local services.
266
+ - `@lakutata/core` (`lakutata`): the components, `Application` and the dependency injection.
@@ -0,0 +1,89 @@
1
+ import type { EntrypointAdapter, MiddlewareDefinition } from '@lakutata/entrypoint';
2
+ import { DBusContext } from '../context/DBusContext.js';
3
+ /**
4
+ * The options of {@link dbusEntrypoint}: the bus to connect to, and the service name to own on it.
5
+ */
6
+ export type DBusEntrypointOptions = {
7
+ /**
8
+ * The adapter's name, which tells it apart from the entrypoint's other adapters.
9
+ * @default undefined
10
+ */
11
+ name?: string;
12
+ /**
13
+ * The bus to connect to: `'session'` (the address in `DBUS_SESSION_BUS_ADDRESS`), `'system'` (the address in
14
+ * `DBUS_SYSTEM_BUS_ADDRESS`, else `unix:path=/var/run/dbus/system_bus_socket`), the address of a bus
15
+ * (`'unix:path=/run/my-bus.sock'`, `'tcp:host=127.0.0.1,port=5555'`), or the path of the socket of a private bus.
16
+ * The adapter fails to start when the bus cannot be reached (for `'session'`, also when `DBUS_SESSION_BUS_ADDRESS`
17
+ * is not set).
18
+ * @default 'session'
19
+ */
20
+ bus?: 'session' | 'system' | string;
21
+ /**
22
+ * The well-known name the service owns on the bus (`'com.example.DeviceService'`): two or more elements separated by
23
+ * dots. The clients address the service by it, and it prefixes the names of the D-Bus errors. On the system bus,
24
+ * the bus policy (`/etc/dbus-1/system.d/`) must allow the process to own it.
25
+ */
26
+ service: string;
27
+ /**
28
+ * Take the name from its current owner when that owner allowed it to be replaced (`allowReplacement`). Without it,
29
+ * the adapter fails to start when another connection owns the name; the request is never queued.
30
+ * @default false
31
+ */
32
+ replaceExisting?: boolean;
33
+ /**
34
+ * Let another connection take the name with `replaceExisting`. The adapter is not stopped when the name is taken:
35
+ * the clients reach the new owner.
36
+ * @default false
37
+ */
38
+ allowReplacement?: boolean;
39
+ /**
40
+ * The middlewares of this adapter's method calls, run after the entrypoint's global middlewares.
41
+ * @default []
42
+ */
43
+ middlewares?: MiddlewareDefinition[];
44
+ };
45
+ /**
46
+ * Build the D-Bus adapter of the entrypoint (its `dbus` option): the application owns a service name on a bus and
47
+ * serves the controllers declared with `@DBusInterface` as the interfaces of its objects, their `@DBusMethod` actions
48
+ * as the methods. The objects of the paths without variables are exported when the adapter starts, until it stops
49
+ * ({@link DBusObjectManager.removeObject} does not remove them); the objects of the path templates are exported when
50
+ * they are added with {@link DBusObjectManager.addObject}, before or after the start.
51
+ *
52
+ * Starting connects to the bus and requests the name. The adapter stops gracefully with the entrypoint: it releases the
53
+ * name (no new call reaches it), the calls in progress end, then the connection closes. It needs a D-Bus daemon, as on
54
+ * Linux: the system bus, a session bus, or a private `dbus-daemon`.
55
+ * @param options The bus, the service name and how it is owned, the adapter's middlewares.
56
+ * @returns The adapter, to give to the `dbus` option of `buildEntrypoints()`.
57
+ * @throws {TypeError} At once, when the service name is invalid; when the adapter starts, when an action declared with
58
+ * `@DBusMethod` belongs to a controller without `@DBusInterface`.
59
+ * @throws {Error} When the adapter starts, if the bus cannot be reached, or if another connection owns the name
60
+ * (`The DBus name … is owned by another service`): the entrypoint fails to start.
61
+ * @example
62
+ * ```typescript
63
+ * import {Application} from 'lakutata'
64
+ * import {buildEntrypoints, Controller} from 'lakutata/com/entrypoint'
65
+ * import {dbusEntrypoint, DBusInterface, DBusMethod} from '@lakutata/dbus'
66
+ *
67
+ * @DBusInterface('com.example.Manager', {path: '/com/example/Manager'})
68
+ * class ManagerController extends Controller {
69
+ * @DBusMethod('Ping', {returns: 's'})
70
+ * public async ping(): Promise<string> {
71
+ * return 'pong'
72
+ * }
73
+ * }
74
+ *
75
+ * //busctl --system call com.example.DeviceService /com/example/Manager com.example.Manager Ping
76
+ * Application.run(() => ({
77
+ * id: 'devices.app',
78
+ * name: 'Devices',
79
+ * components: {
80
+ * entrypoint: buildEntrypoints({
81
+ * controllers: [ManagerController],
82
+ * dbus: dbusEntrypoint({bus: 'system', service: 'com.example.DeviceService'})
83
+ * })
84
+ * },
85
+ * bootstrap: ['entrypoint']
86
+ * }))
87
+ * ```
88
+ */
89
+ export declare function dbusEntrypoint(options: DBusEntrypointOptions): EntrypointAdapter<DBusContext>;