dbusjs / node-dbus-next

🚌 The next great dbus library for node
https://www.npmjs.com/package/dbus-next
156 stars 52 forks source link

Improved Interface Generator #52

Closed Niels-Be closed 4 years ago

Niels-Be commented 4 years ago

This will add an interface generator for client interfaces. It is similar to the existing generator but with several improvements.

  1. It lets you generate an interface directly from a dbus object
  2. Has more Handlebar functions
  3. Customizable templates
  4. Example templates for:
    • A client interface wrapper (TS and JS)
    • Typescript client interface definitions
    • Service class stub (JS only, like in original generator)

Let me know if you want this in this project, otherwise I would create an separate project for this generator.

Usage:

Usage: generate-client-interfaces [options] <destination> <objectPath>

Generate an interface from a DBus object

Options:
  -V, --version          output the version number
  --system               Use the system bus
  --session              Use the session bus
  -t, --template [path]  Template to use for interface generation
  --full                 Do not exclude DBus standard interfaces
  -p, --prefix           Prefix class names with full interface path
  -o, --output [path]    The output file path (default: stdout)
  -h, --help             output usage information

Example: Generate a Typescript class that wraps all DBus calls into a high level interface.

./generate-client-interfaces.js --system -t ../templates/typescript-class.hbs org.bluez /org/bluez/hci0

import * as DBus from 'dbus-next';
import { EventEmitter } from 'events';

/*
 * Generated by dbus-next interface generator
 */

/**
 * org.bluez.Adapter1
 */
export class Adapter1 extends EventEmitter {

    public readonly dbusInterfaceName = 'org.bluez.Adapter1';
    public dbusObject: DBus.ProxyObject;
    public propertiesDBusInterface: DBus.ClientInterface;
    public thisDBusInterface: DBus.ClientInterface;

    constructor(dbusObject: DBus.ProxyObject) {
        super();
        this.dbusObject = dbusObject;
        this.thisDBusInterface = dbusObject.getInterface('org.bluez.Adapter1');
        this.propertiesDBusInterface = dbusObject.getInterface('org.freedesktop.DBus.Properties');

        // forward property change events
        this.propertiesDBusInterface.on('PropertiesChanged', (iface: string, changed: any, invalidated: any) => {
            if(iface === this.dbusInterfaceName) {
                this.emit('PropertiesChanged', iface, changed, invalidated);
            }
        });
        // forward all signals
        this.on("newListener", this.thisDBusInterface.on.bind(this.thisDBusInterface));
        this.on("removeListener", this.thisDBusInterface.removeListener.bind(this.thisDBusInterface));
    }

    /***** Properties *****/

    public getProperties(): Promise<{[name: string]: DBus.Variant}> {
        return this.propertiesDBusInterface.GetAll(this.dbusInterfaceName);
    }

    public getProperty(name: string): Promise<DBus.Variant> {
        return this.propertiesDBusInterface.Get(this.dbusInterfaceName, name);
    }

    public setProperty(name: string, value: DBus.Variant): Promise<void> {
        return this.propertiesDBusInterface.Set(this.dbusInterfaceName, name, value);
    }

    //@property({ name: 'Address', signature: 's', access: ACCESS_READ })
    public Address(): Promise<string> {
        return this.propertiesDBusInterface.Get(this.dbusInterfaceName, 'Address');
    }

    //@property({ name: 'AddressType', signature: 's', access: ACCESS_READ })
    public AddressType(): Promise<string> {
        return this.propertiesDBusInterface.Get(this.dbusInterfaceName, 'AddressType');
    }

    //@property({ name: 'Name', signature: 's', access: ACCESS_READ })
    public Name(): Promise<string> {
        return this.propertiesDBusInterface.Get(this.dbusInterfaceName, 'Name');
    }

    //@property({ name: 'Alias', signature: 's', access: ACCESS_READWRITE })
    public Alias(): Promise<string>;
    public Alias(value: string): Promise<void>;
    public Alias(value?: string): Promise<any> {
        if(value !== undefined) {
            return this.propertiesDBusInterface.Set(this.dbusInterfaceName, 'Alias', value);
        } else {
            return this.propertiesDBusInterface.Get(this.dbusInterfaceName, 'Alias');
        }
    }

    //@property({ name: 'Class', signature: 'u', access: ACCESS_READ })
    public Class(): Promise<number> {
        return this.propertiesDBusInterface.Get(this.dbusInterfaceName, 'Class');
    }

    //@property({ name: 'Powered', signature: 'b', access: ACCESS_READWRITE })
    public Powered(): Promise<boolean>;
    public Powered(value: boolean): Promise<void>;
    public Powered(value?: boolean): Promise<any> {
        if(value !== undefined) {
            return this.propertiesDBusInterface.Set(this.dbusInterfaceName, 'Powered', value);
        } else {
            return this.propertiesDBusInterface.Get(this.dbusInterfaceName, 'Powered');
        }
    }

    //@property({ name: 'Discoverable', signature: 'b', access: ACCESS_READWRITE })
    public Discoverable(): Promise<boolean>;
    public Discoverable(value: boolean): Promise<void>;
    public Discoverable(value?: boolean): Promise<any> {
        if(value !== undefined) {
            return this.propertiesDBusInterface.Set(this.dbusInterfaceName, 'Discoverable', value);
        } else {
            return this.propertiesDBusInterface.Get(this.dbusInterfaceName, 'Discoverable');
        }
    }

    //@property({ name: 'DiscoverableTimeout', signature: 'u', access: ACCESS_READWRITE })
    public DiscoverableTimeout(): Promise<number>;
    public DiscoverableTimeout(value: number): Promise<void>;
    public DiscoverableTimeout(value?: number): Promise<any> {
        if(value !== undefined) {
            return this.propertiesDBusInterface.Set(this.dbusInterfaceName, 'DiscoverableTimeout', value);
        } else {
            return this.propertiesDBusInterface.Get(this.dbusInterfaceName, 'DiscoverableTimeout');
        }
    }

    //@property({ name: 'Pairable', signature: 'b', access: ACCESS_READWRITE })
    public Pairable(): Promise<boolean>;
    public Pairable(value: boolean): Promise<void>;
    public Pairable(value?: boolean): Promise<any> {
        if(value !== undefined) {
            return this.propertiesDBusInterface.Set(this.dbusInterfaceName, 'Pairable', value);
        } else {
            return this.propertiesDBusInterface.Get(this.dbusInterfaceName, 'Pairable');
        }
    }

    //@property({ name: 'PairableTimeout', signature: 'u', access: ACCESS_READWRITE })
    public PairableTimeout(): Promise<number>;
    public PairableTimeout(value: number): Promise<void>;
    public PairableTimeout(value?: number): Promise<any> {
        if(value !== undefined) {
            return this.propertiesDBusInterface.Set(this.dbusInterfaceName, 'PairableTimeout', value);
        } else {
            return this.propertiesDBusInterface.Get(this.dbusInterfaceName, 'PairableTimeout');
        }
    }

    //@property({ name: 'Discovering', signature: 'b', access: ACCESS_READ })
    public Discovering(): Promise<boolean> {
        return this.propertiesDBusInterface.Get(this.dbusInterfaceName, 'Discovering');
    }

    //@property({ name: 'UUIDs', signature: 'as', access: ACCESS_READ })
    public UUIDs(): Promise<Array<string>> {
        return this.propertiesDBusInterface.Get(this.dbusInterfaceName, 'UUIDs');
    }

    //@property({ name: 'Modalias', signature: 's', access: ACCESS_READ })
    public Modalias(): Promise<string> {
        return this.propertiesDBusInterface.Get(this.dbusInterfaceName, 'Modalias');
    }

    /***** Methods *****/

    //@method({ name: 'StartDiscovery', inSignature: '', outSignature: '' })
    public StartDiscovery(): Promise<void> {
        return this.thisDBusInterface.StartDiscovery();
    }

    //@method({ name: 'SetDiscoveryFilter', inSignature: 'a{sv}', outSignature: '' })
    public SetDiscoveryFilter(properties: {[key: string]: DBus.Variant}): Promise<void> {
        return this.thisDBusInterface.SetDiscoveryFilter(properties);
    }

    //@method({ name: 'StopDiscovery', inSignature: '', outSignature: '' })
    public StopDiscovery(): Promise<void> {
        return this.thisDBusInterface.StopDiscovery();
    }

    //@method({ name: 'RemoveDevice', inSignature: 'o', outSignature: '' })
    public RemoveDevice(device: DBus.ObjectPath): Promise<void> {
        return this.thisDBusInterface.RemoveDevice(device);
    }

    //@method({ name: 'GetDiscoveryFilters', inSignature: '', outSignature: 'as' })
    public GetDiscoveryFilters(): Promise<Array<string>> {
        return this.thisDBusInterface.GetDiscoveryFilters();
    }

}

/* [....] */
acrisci commented 4 years ago

The JavaScript version makes a service interface and the TypeScript version makes a client interface. That should be explicit somewhere, probably in the name of the template.

Niels-Be commented 4 years ago

The JavaScript version makes a service interface and the TypeScript version makes a client interface. That should be explicit somewhere, probably in the name of the template.

Right it should only generate client interfaces. Is there any use case for generating interfaces for a service?

acrisci commented 4 years ago

Is there any use case for generating interfaces for a service?

Yeah, this was written to generate the boilerplate for mpris-service. It's more useful for clients, but it can easily do both because they use the same kinds of abstractions.

Niels-Be commented 4 years ago

I did some updates and also added a recursive option to generate classes for an entire service at once. Each interface will be generated into its own file.

See node-dbus-network-manager for an example of a fully generated project.

acrisci commented 4 years ago

:+1: