UNPKG

dbus-sdk

Version:

A Node.js SDK for interacting with DBus, enabling seamless service calling and exposure with TypeScript support

212 lines (211 loc) 10.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DBusInterface = void 0; const DBusPropertyAccess_1 = require("./lib/enums/DBusPropertyAccess"); const Errors_1 = require("./lib/Errors"); const DBusSignedValue_1 = require("./lib/DBusSignedValue"); class DBusInterface { #signalEmitter; /** * Constructor for DBusInterface. * Initializes the DBus interface with the provided options and sets up references to the DBus connection, * service, object, and introspection data. * @param opts - Configuration options for the DBus interface. */ constructor(opts) { this.opts = opts; this.name = this.opts.iface; this.dbus = this.opts.dbus; this.service = this.opts.dbusService; this.object = this.opts.dbusObject; this.introspectInterface = this.opts.introspectInterface; } /** * Converts a parameter object to an array of arguments based on introspection data. * Extracts input parameters from the provided parameter object, mapping them to the expected order of arguments * for a given method as defined in the introspection metadata. If a required parameter is missing, an error is thrown. * @param methodInfo - The introspection metadata of the method, containing argument definitions. * @param inputParameterObject - The parameter object containing named arguments to be mapped. * @returns An array of arguments extracted from the parameter object, ordered according to the method's signature. * @throws {NotEnoughParamsError} If a required parameter is missing from the input object. */ objectifiedParameterToArguments(methodInfo, inputParameterObject) { const inputParameters = methodInfo.arg .filter((arg) => arg.direction === 'in') .map((arg, index) => ({ ...arg, name: arg.name ? arg.name : `param${index}` })); const args = []; for (const inputParameter of inputParameters) { const name = inputParameter.name; const arg = inputParameterObject[name]; if (arg === undefined) throw new Errors_1.NotEnoughParamsError(`Parameter "${name}" is required`); args.push(arg); } return args; } /** * Getter for methods with reply mode. * Dynamically creates an object containing methods that expect a reply from the DBus invocation. * Each method handles input arguments with type signatures and returns the result of the invocation. * @returns A record of method names mapped to their callable implementations with reply mode. */ get method() { const methods = {}; this.listMethods().forEach((methodInfo) => { methods[methodInfo.name] = async (...args) => { const types = methodInfo.arg .filter((arg) => arg.direction === 'in') .map((arg) => arg.type); const signature = types.length ? types.join('') : undefined; const inputArguments = signature ? args.length ? DBusSignedValue_1.DBusSignedValue.parse(signature, args.length > 1 ? args : args[0]) : [] : []; const result = await this.dbus.invoke({ service: this.service.name, objectPath: this.object.name, interface: this.name, method: methodInfo.name, signature: signature, args: inputArguments }); if (result.length > 1) return result; return result[0]; }; }); return methods; } /** * Getter for methods with reply mode using parameter object pattern. * Dynamically creates an object containing methods that expect a reply from the DBus invocation. * Each method accepts a single parameter object containing named arguments, which are mapped to the expected input parameters * based on the introspection data. This approach enhances readability and avoids errors due to parameter order. * @returns A record of method names mapped to their callable implementations with reply mode, accepting a parameter object. */ get parameterObjectifyMethod() { const methods = {}; this.listMethods().forEach((methodInfo) => { methods[methodInfo.name] = async (parameterObject) => { const args = this.objectifiedParameterToArguments(methodInfo, parameterObject ? parameterObject : {}); return await this.method[methodInfo.name](...args); }; }); return methods; } /** * Getter for methods with no-reply mode. * Dynamically creates an object containing methods that do not expect a reply from the DBus invocation. * These methods are used for fire-and-forget calls. * @returns A record of method names mapped to their callable implementations with no-reply mode. */ get noReplyMethod() { const noReplyMethods = {}; this.listMethods().forEach((methodInfo) => { noReplyMethods[methodInfo.name] = (...args) => { const types = methodInfo.arg .filter((arg) => arg.direction === 'in') .map((arg) => arg.type); this.dbus.invoke({ service: this.service.name, objectPath: this.object.name, interface: this.name, method: methodInfo.name, signature: types.length ? types.join('') : undefined, args: args }, true); }; }); return noReplyMethods; } /** * Getter for methods with no-reply mode using parameter object pattern. * Dynamically creates an object containing methods that do not expect a reply from the DBus invocation. * Each method accepts a single parameter object containing named arguments, which are mapped to the expected input parameters * based on the introspection data. This approach enhances readability and avoids errors due to parameter order. * These methods are used for fire-and-forget calls. * @returns A record of method names mapped to their callable implementations with no-reply mode, accepting a parameter object. */ get parameterObjectifyNoReplyMethod() { const noReplyMethods = {}; this.listMethods().forEach((methodInfo) => { noReplyMethods[methodInfo.name] = (parameterObject) => { const args = this.objectifiedParameterToArguments(methodInfo, parameterObject ? parameterObject : {}); return this.noReplyMethod[methodInfo.name](...args); }; }); return noReplyMethods; } /** * Getter for properties of the DBus interface. * Dynamically creates an object containing property operations (get/set) for each property defined in the introspection data. * Access control is enforced based on property access mode (read/write/readwrite). * @returns A record of property names mapped to their get/set operations. */ get property() { const properties = {}; this.listProperties().forEach((propertyInfo) => { properties[propertyInfo.name] = { set: async (value) => { if (![DBusPropertyAccess_1.DBusPropertyAccess.WRITE, DBusPropertyAccess_1.DBusPropertyAccess.READWRITE].includes(propertyInfo.access)) throw new Errors_1.AccessPropertyForbiddenError(`Access to attribute ${propertyInfo.name} is prohibited, and its access mode is ${propertyInfo.access}`); return this.dbus.setProperty({ service: this.service.name, objectPath: this.object.name, interface: this.name, property: propertyInfo.name, value: value }); }, get: async () => { if (![DBusPropertyAccess_1.DBusPropertyAccess.READ, DBusPropertyAccess_1.DBusPropertyAccess.READWRITE].includes(propertyInfo.access)) throw new Errors_1.AccessPropertyForbiddenError(`Access to attribute ${propertyInfo.name} is prohibited, and its access mode is ${propertyInfo.access}`); return this.dbus.getProperty({ service: this.service.name, objectPath: this.object.name, interface: this.name, property: propertyInfo.name }); } }; }); return properties; } /** * Getter for the DBus signal emitter. * Lazily initializes and returns a signal emitter for emitting signals associated with this interface. * @returns A DBusSignalEmitter instance for handling signal emissions. */ get signal() { if (!this.#signalEmitter) this.#signalEmitter = this.dbus.createSignalEmitter({ service: this.service.name, uniqueName: this.service.uniqueName, objectPath: this.object.name, interface: this.name }); return this.#signalEmitter; } /** * Lists all methods defined in the introspection data for this interface. * @returns An array of IntrospectMethod objects representing the methods of this interface. */ listMethods() { return this.introspectInterface.method; } /** * Lists all properties defined in the introspection data for this interface. * @returns An array of IntrospectProperty objects representing the properties of this interface. */ listProperties() { return this.introspectInterface.property; } /** * Lists all signals defined in the introspection data for this interface. * @returns An array of IntrospectSignal objects representing the signals of this interface. */ listSignals() { return this.introspectInterface.signal; } } exports.DBusInterface = DBusInterface;