diff --git a/nodecg-io-dbus/extension/dbusClient.ts b/nodecg-io-dbus/extension/dbusClient.ts new file mode 100644 index 000000000..240c2528e --- /dev/null +++ b/nodecg-io-dbus/extension/dbusClient.ts @@ -0,0 +1,55 @@ +import { DBusConfig } from "./index"; +import * as dbus from "dbus-next"; +import { MessageBus, ProxyObject, ClientInterface, Variant } from "dbus-next"; + +export class DBusClient { + public readonly session: MessageBus; + public readonly system: MessageBus; + + constructor(config: DBusConfig) { + this.session = dbus.sessionBus(config); + this.system = dbus.systemBus(); + } + + public async proxy(config: DBusProxyConfig): Promise { + const proxy = await (config.system ? this.system : this.session).getProxyObject(config.iface, config.path); + return config.create(this, proxy); + } + + static createClient(config: DBusConfig): DBusClient { + return new DBusClient(config); + } +} + +// Required, so we don't have circular imports. +export interface DBusProxyConfig { + iface: string; + path: string; + system: boolean; + create(client: DBusClient, proxy: ProxyObject): T; +} + +export class DBusObject { + protected readonly client: DBusClient; + protected readonly proxy: ProxyObject; + private readonly properties: RatBagPropertyInterface; + + protected constructor(client: DBusClient, proxy: ProxyObject) { + this.client = client; + this.proxy = proxy; + this.properties = proxy.getInterface("org.freedesktop.DBus.Properties") as RatBagPropertyInterface; + } + + async getProperty(iface: string, name: string): Promise { + return await this.properties.Get(iface, name); + } + + async setProperty(iface: string, name: string, value: Variant): Promise { + return await this.properties.Set(iface, name, value); + } +} + +type RatBagPropertyInterface = ClientInterface & { + Get(iface: string, path: string): Promise; + Set(iface: string, path: string, value: Variant): Promise; +}; diff --git a/nodecg-io-dbus/extension/index.ts b/nodecg-io-dbus/extension/index.ts new file mode 100644 index 000000000..70a25e0c0 --- /dev/null +++ b/nodecg-io-dbus/extension/index.ts @@ -0,0 +1,38 @@ +import { NodeCG } from "nodecg-types/types/server"; +import { Result, emptySuccess, success, ServiceBundle } from "nodecg-io-core"; +import { DBusClient } from "./dbusClient"; +import * as dbus from "dbus-next"; + +export interface DBusConfig { + busAddress?: string; +} + +export * from "./dbusClient"; + +module.exports = (nodecg: NodeCG) => { + new DBusService(nodecg, "dbus", __dirname, "../schema.json").register(); +}; + +class DBusService extends ServiceBundle { + async validateConfig(config: DBusConfig): Promise> { + dbus.sessionBus(config); + return emptySuccess(); + } + + async createClient(config: DBusConfig): Promise> { + const client = DBusClient.createClient(config); + this.nodecg.log.info("Successfully created dbus client."); + return success(client); + } + + stopClient(client: DBusClient): void { + client.session.disconnect(); + client.system.disconnect(); + this.nodecg.log.info("Successfully stopped dbus client."); + } + + removeHandlers(client: DBusClient): void { + client.session.removeAllListeners(); + client.system.removeAllListeners(); + } +} diff --git a/nodecg-io-dbus/extension/ratbag.ts b/nodecg-io-dbus/extension/ratbag.ts new file mode 100644 index 000000000..8f591ba51 --- /dev/null +++ b/nodecg-io-dbus/extension/ratbag.ts @@ -0,0 +1,746 @@ +import { DBusClient, DBusProxyConfig, DBusObject } from "./dbusClient"; +import { ProxyObject, ClientInterface, Variant } from "dbus-next"; + +/** + * Access to ratbagd. + */ +export class RatBagManager extends DBusObject { + static readonly PROXY: DBusProxyConfig = { + iface: "org.freedesktop.ratbag1", + path: "/org/freedesktop/ratbag1", + system: true, + create(client: DBusClient, proxy: ProxyObject): RatBagManager { + return new RatBagManager(client, proxy); + }, + }; + + constructor(client: DBusClient, proxy: ProxyObject) { + super(client, proxy); + } + + /** + * Gets the API version of ratbagd. This is built for API 1. Everything else might not work as intended. + */ + public async api(): Promise { + return (await this.getProperty("org.freedesktop.ratbag1.Manager", "APIVersion")).value; + } + + /** + * Gets a list of all currently connected devices. + */ + public async devices(): Promise { + const variant = await this.getProperty("org.freedesktop.ratbag1.Manager", "Devices"); + const paths: string[] = variant.value; + const devices: RatBagDevice[] = []; + for (const path of paths) { + const proxy = await this.proxy.bus.getProxyObject("org.freedesktop.ratbag1", path); + devices.push(new RatBagDevice(this.client, proxy)); + } + return devices; + } +} + +/** + * A device, ratbagd can control. + */ +export class RatBagDevice extends DBusObject { + private readonly device: RatBagDeviceInterface; + + constructor(client: DBusClient, proxy: ProxyObject) { + super(client, proxy); + this.device = proxy.getInterface("org.freedesktop.ratbag1.Device") as RatBagDeviceInterface; + } + + /** + * Gets the device name. + */ + public async name(): Promise { + return (await this.getProperty("org.freedesktop.ratbag1.Device", "Name")).value; + } + + /** + * Gets the device model + */ + public async model(): Promise { + let modelString: string = (await this.getProperty("org.freedesktop.ratbag1.Device", "Model")).value; + try { + const busType: string = modelString.substring(0, modelString.indexOf(":")); + modelString = modelString.substring(modelString.indexOf(":") + 1); + if (busType !== "usb" && busType !== "bluetooth") { + // We don't know about that bus type. + return { busType: "unknown" }; + } + const vendorHex = modelString.substring(0, modelString.indexOf(":")); + modelString = modelString.substring(modelString.indexOf(":") + 1); + const productHex = modelString.substring(0, modelString.indexOf(":")); + modelString = modelString.substring(modelString.indexOf(":") + 1); + const vendorId = parseInt(vendorHex, 16); + const productId = parseInt(productHex, 16); + const version = parseInt(modelString); + if (isNaN(vendorId) || isNaN(productId) || isNaN(version)) { + return { busType: "unknown" }; + } + return { + busType: busType, + vendorHex: vendorHex, + vendorId: vendorId, + productHex: productHex, + productId: productId, + version: version, + }; + } catch (err) { + return { busType: "unknown" }; + } + } + + /** + * Gets a list of profiles for that device. If a device does not support multiple profiles, + * there'll be just one profile in the list that can be used. + */ + public async profiles(): Promise { + const variant = await this.getProperty("org.freedesktop.ratbag1.Device", "Profiles"); + const paths: string[] = variant.value; + const profiles: RatBagProfile[] = []; + for (const path of paths) { + const proxy = await this.proxy.bus.getProxyObject("org.freedesktop.ratbag1", path); + profiles.push(new RatBagProfile(this.client, proxy)); + } + return profiles; + } + + /** + * Writes all changes that were made to the device. + */ + public async commit(): Promise { + await this.device.Commit(); + } + + /** + * Adds a listener for an event, when committing to the device fails. + */ + public on(event: "Resync", handler: () => void): void { + this.device.on(event, handler); + } + + public once(event: "Resync", handler: () => void): void { + this.device.once(event, handler); + } + + public off(event: "Resync", handler: () => void): void { + this.device.off(event, handler); + } +} + +/** + * A profile for a ratbagd device. + */ +export class RatBagProfile extends DBusObject { + private readonly profile: RatBagProfileInterface; + + constructor(client: DBusClient, proxy: ProxyObject) { + super(client, proxy); + this.profile = proxy.getInterface("org.freedesktop.ratbag1.Profile") as RatBagProfileInterface; + } + + /** + * Gets the index of the profile. + */ + public async index(): Promise { + return (await this.getProperty("org.freedesktop.ratbag1.Profile", "Index")).value; + } + + /** + * Gets the name of the profile, if the device supports profile naming. + */ + public async name(): Promise { + const name = (await this.getProperty("org.freedesktop.ratbag1.Profile", "Name")).value; + return name === "" ? undefined : name; + } + + /** + * Sets the name of a profile. This must not be called if the device does not support profile naming. + * Use {@link name()} first, to find out whether you can use this. + */ + public async setName(name: string): Promise { + await this.setProperty("org.freedesktop.ratbag1.Profile", "Name", new Variant("s", name)); + } + + /** + * Gets whether the profile is enabled. A disabled profile may have invalid values set, so you should + * check these values before enabling a profile. + */ + public async enabled(): Promise { + return (await this.getProperty("org.freedesktop.ratbag1.Profile", "Enabled")).value; + } + + /** + * Enables this profile. + */ + public async enable(): Promise { + await this.setProperty("org.freedesktop.ratbag1.Profile", "Enabled", new Variant("b", true)); + } + + /** + * Disables this profile. + */ + public async disable(): Promise { + await this.setProperty("org.freedesktop.ratbag1.Profile", "Enabled", new Variant("b", false)); + } + + /** + * Gets whether this profile is currently active. There is always only one active profile. + */ + public async active(): Promise { + return (await this.getProperty("org.freedesktop.ratbag1.Profile", "IsActive")).value; + } + + /** + * Activates this profile. The currently active profile will be deactivated. + */ + public async activate(): Promise { + return await this.profile.SetActive(); + } + + /** + * Gets a list of display resolutions, that can be switched through. + */ + public async resolutions(): Promise { + const variant = await this.getProperty("org.freedesktop.ratbag1.Profile", "Resolutions"); + const paths: string[] = variant.value; + const resolutions: RatBagResolution[] = []; + for (const path of paths) { + const proxy = await this.proxy.bus.getProxyObject("org.freedesktop.ratbag1", path); + resolutions.push(new RatBagResolution(this.client, proxy)); + } + return resolutions; + } + + /** + * Gets a list of buttons on the device for this profile. + */ + public async buttons(): Promise { + const variant = await this.getProperty("org.freedesktop.ratbag1.Profile", "Buttons"); + const paths: string[] = variant.value; + const buttons: RatBagButton[] = []; + for (const path of paths) { + const proxy = await this.proxy.bus.getProxyObject("org.freedesktop.ratbag1", path); + buttons.push(new RatBagButton(this.client, proxy)); + } + return buttons; + } + + /** + * Gets a list of leds on the device for this profile. + */ + public async leds(): Promise { + const variant = await this.getProperty("org.freedesktop.ratbag1.Profile", "Leds"); + const paths: string[] = variant.value; + const leds: RatBagLed[] = []; + for (const path of paths) { + const proxy = await this.proxy.bus.getProxyObject("org.freedesktop.ratbag1", path); + leds.push(new RatBagLed(this.client, proxy)); + } + return leds; + } +} + +/** + * A resolution profile for a device profile. + */ +export class RatBagResolution extends DBusObject { + private readonly resolution: RatBagResolutionInterface; + + constructor(client: DBusClient, proxy: ProxyObject) { + super(client, proxy); + this.resolution = proxy.getInterface("org.freedesktop.ratbag1.Resolution") as RatBagResolutionInterface; + } + + /** + * Gets the index of this resolution profile. + */ + public async index(): Promise { + return (await this.getProperty("org.freedesktop.ratbag1.Resolution", "Index")).value; + } + + /** + * Gets whether this resolution profile is the currently active resolution. + */ + public async active(): Promise { + return (await this.getProperty("org.freedesktop.ratbag1.Resolution", "IsActive")).value; + } + + /** + * Gets whether this resolution profile is the default. + */ + public async default(): Promise { + return (await this.getProperty("org.freedesktop.ratbag1.Resolution", "IsDefault")).value; + } + + /** + * Sets this resolution profile as the currently active resolution. + */ + public async activate(): Promise { + await this.resolution.SetActive(); + } + + /** + * Sets this resolution profile as default. + */ + public async setDefault(): Promise { + await this.resolution.SetDefault(); + } + + /** + * Gets the dpi values for this profile. + */ + public async dpi(): Promise { + const dpi: number | [number, number] = ( + await this.getProperty("org.freedesktop.ratbag1.Resolution", "Resolution") + ).value; + if (typeof dpi === "number") { + return dpi; + } else { + return { + x: dpi[0], + y: dpi[1], + }; + } + } + + /** + * Sets the dpi for this profile. If {@link dpi()} returns a single value, this must also be set to a single value. + * If {@link dpi()} returns separate x and y values, this must be set to separate x and y values. + */ + public async setDpi(dpi: RatBagDpi): Promise { + const variant = + typeof dpi === "number" + ? new Variant("u", dpi) + : new Variant<[number, number]>("(uu)", [dpi.x, dpi.y]); + await this.setProperty("org.freedesktop.ratbag1.Resolution", "Resolution", variant); + } + + /** + * Gets a list of numbers that can be used as dpi values. + */ + public async allowedDpiValues(): Promise { + return (await this.getProperty("org.freedesktop.ratbag1.Resolution", "Resolutions")).value; + } +} + +/** + * A button on a device for a specific profile + */ +export class RatBagButton extends DBusObject { + private static readonly SPECIAL_ACTION_MAP: Record = { + unknown: 0x40000000, + doubleclick: 0x40000001, + "wheel left": 0x40000002, + "wheel right": 0x40000003, + "wheel up": 0x40000004, + "wheel down": 0x40000005, + "ratched mode switch": 0x40000006, + "resolution cycle up": 0x40000007, + "resolution cycle down": 0x40000008, + "resolution up": 0x40000009, + "resolution down": 0x4000000a, + "resolution alternate": 0x4000000b, + "resolution default": 0x4000000c, + "profile cycle up": 0x4000000d, + "profile cycle down": 0x4000000e, + "profile up": 0x4000000f, + "profile down": 0x40000010, + "second mode": 0x40000011, + "battery level": 0x40000012, + }; + + constructor(client: DBusClient, proxy: ProxyObject) { + super(client, proxy); + } + + /** + * Gets the index of this button. + */ + public async index(): Promise { + return (await this.getProperty("org.freedesktop.ratbag1.Button", "Index")).value; + } + + /** + * Gets the action currently bound to this button. + */ + public async mapping(): Promise { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const raw: [number, Variant] = (await this.getProperty("org.freedesktop.ratbag1.Button", "Mapping")).value; + if (raw[0] === 0) { + return { + type: "none", + }; + } else if (raw[0] === 1) { + return { + type: "button", + button: raw[1].value, + }; + } else if (raw[0] === 2) { + const id = Object.keys(RatBagButton.SPECIAL_ACTION_MAP).find( + (key) => RatBagButton.SPECIAL_ACTION_MAP[key as RatBagSpecialAction] === raw[1].value, + ) as RatBagSpecialAction | undefined; + return { + type: "special", + action: id === undefined ? "unknown" : id, + }; + } else if (raw[0] === 3) { + const macro: RatBagMacroAction[] = []; + for (const entry of raw[1].value as [number, number][]) { + macro.push({ + type: entry[0] === 0 ? "release" : "press", + keyCode: entry[1], + }); + } + return { + type: "macro", + macro: macro, + }; + } else { + return { + type: "unknown", + }; + } + } + + /** + * Binds this button to the given action. + */ + public async setMapping(mapping: RatBagMapping): Promise { + let id = 1000; + let variant: Variant = new Variant("u", 0); + if (mapping.type === "none") { + id = 1000; + variant = new Variant("u", 0); + } else if (mapping.type === "button") { + id = 1; + variant = new Variant("u", mapping.button); + } else if (mapping.type === "special") { + id = 2; + const func = RatBagButton.SPECIAL_ACTION_MAP[mapping.action]; + variant = new Variant("u", func === undefined ? 0x40000000 : func); + } else if (mapping.type === "macro") { + id = 3; + const actions: [number, number][] = []; + for (const action of mapping.macro) { + actions.push([action.type === "press" ? 1 : 0, action.keyCode]); + } + variant = new Variant<[number, number][]>("a(uu)", actions); + } + await this.setProperty("org.freedesktop.ratbag1.Button", "Mapping", new Variant("(uv)", [id, variant])); + } +} + +/** + * A led on a device for a specific profile + */ +export class RatBagLed extends DBusObject { + constructor(client: DBusClient, proxy: ProxyObject) { + super(client, proxy); + } + + /** + * Gets the index for this led. + */ + public async index(): Promise { + return (await this.getProperty("org.freedesktop.ratbag1.Led", "Index")).value; + } + + /** + * Gets the current mode of the led. + */ + public async mode(): Promise { + const modeId: number = (await this.getProperty("org.freedesktop.ratbag1.Led", "Mode")).value; + switch (modeId) { + case 1: + return "on"; + case 2: + return "cycle"; + case 3: + return "breath"; + default: + return "off"; + } + } + + /** + * Sets the mode of the led. + */ + public async setMode(mode: LedMode): Promise { + let modeId = 0; + if (mode === "on") { + modeId = 1; + } else if (mode === "cycle") { + modeId = 2; + } else if (mode === "breath") { + modeId = 3; + } + await this.setProperty("org.freedesktop.ratbag1.Led", "Mode", new Variant("u", modeId)); + } + + /** + * Gets a list of supported led modes. + */ + public async supportedModes(): Promise { + const modeIds: number[] = (await this.getProperty("org.freedesktop.ratbag1.Led", "Mode")).value; + const modes: LedMode[] = []; + for (const modeId of modeIds) { + switch (modeId) { + case 0: + modes.push("off"); + break; + case 1: + modes.push("on"); + break; + case 2: + modes.push("cycle"); + break; + case 3: + modes.push("breath"); + break; + } + } + return modes; + } + + /** + * Gets the color, the led is currently in. + */ + public async color(): Promise { + const color: [number, number, number] = (await this.getProperty("org.freedesktop.ratbag1.Led", "Color")).value; + return { + color: ((color[0] & 0xff) << 16) | ((color[1] & 0xff) << 8) | (color[2] & 0xff), + red: color[0] & 0xff, + green: color[1] & 0xff, + blue: color[2] & 0xff, + }; + } + + /** + * Sets the color for the led. + */ + public async setColor(color: RatBagColorObj | RatBagColorValue): Promise { + let value: [number, number, number]; + if ("color" in color) { + value = [(color.color >> 16) & 0xff, (color.color >> 8) & 0xff, color.color & 0xff]; + } else { + value = [color.red, color.green, color.blue]; + } + await this.setProperty( + "org.freedesktop.ratbag1.Led", + "Color", + new Variant<[number, number, number]>("(uuu)", value), + ); + } + + /** + * Gets the current effect duration in milliseconds. What exactly this means depends on the led mode. + */ + public async effectDuration(): Promise { + return (await this.getProperty("org.freedesktop.ratbag1.Led", "EffectDuration")).value; + } + + /** + * Sets the current effect duration in milliseconds. + */ + public async setEffectDuration(millis: number): Promise { + await this.setProperty("org.freedesktop.ratbag1.Led", "EffectDuration", new Variant("u", millis)); + } + + /** + * Gets the current led brightness [0;255] + */ + public async brightness(): Promise { + return (await this.getProperty("org.freedesktop.ratbag1.Led", "Brightness")).value & 0xff; + } + + /** + * Sets the current led brightness [0;255] + */ + public async setBrightness(brightness: number): Promise { + await this.setProperty( + "org.freedesktop.ratbag1.Led", + "Brightness", + new Variant("u", brightness & 0xff), + ); + } +} + +/** + * A model of a ratbagd device. + */ +export type RatBagModel = RatBagModelUnknown | RatBagModelCommon; + +/** + * An unknown device model. + */ +export type RatBagModelUnknown = { + busType: "unknown"; +}; + +/** + * A known device model. + */ +export type RatBagModelCommon = { + /** + * How the device id connected. + */ + busType: "usb" | "bluetooth"; + + /** + * The vendor id of the device as a hex string. + */ + vendorHex: string; + + /** + * The vendor id of the device as a number. + */ + vendorId: number; + + /** + * The product id of the device as a hex string. + */ + productHex: string; + + /** + * The product id of the device as a number. + */ + productId: number; + + /** + * The version of the device. This number is only used internally to distinguish multiple + * devices of the same type. + */ + version: number; +}; + +/** + * A resolution in DPI. This can either be a single value or separate values for x and y depending on the device. + * When setting a DPI value, it must be exactly the kind of value, the device supports. + */ +export type RatBagDpi = number | { x: number; y: number }; + +/** + * A mapping for a button. + */ +export type RatBagMapping = + | RatBagMappingNone + | RatBagMappingUnknown + | RatBagMappingButton + | RatBagMappingSpecial + | RatBagMappingMacro; + +/** + * A button mapping that does nothing. + */ +export type RatBagMappingNone = { + type: "none"; +}; + +/** + * An unknown button mapping. + */ +export type RatBagMappingUnknown = { + type: "unknown"; +}; + +/** + * A button mapping that maps a physical button to a logical button. + */ +export type RatBagMappingButton = { + type: "button"; + + /** + * The logical mouse button to map to. + */ + button: number; +}; + +/** + * A mapping that triggers a special action. + */ +export type RatBagMappingSpecial = { + type: "special"; + + /** + * The action to trigger. + */ + action: RatBagSpecialAction; +}; + +/** + * A mapping that triggers a macro. + */ +export type RatBagMappingMacro = { + type: "macro"; + macro: RatBagMacroAction[]; +}; + +/** + * An action in a macro. + */ +export type RatBagMacroAction = { + type: "press" | "release"; + keyCode: number; +}; + +/** + * A color represented by red, green and blue values in range [0;255] + */ +export type RatBagColorObj = { + red: number; + green: number; + blue: number; +}; + +/** + * A color represented as 0xRRGGBB + */ +export type RatBagColorValue = { + color: number; +}; + +/** + * A special button action. + */ +export type RatBagSpecialAction = + | "unknown" + | "doubleclick" + | "wheel left" + | "wheel right" + | "wheel up" + | "wheel down" + | "ratched mode switch" + | "resolution cycle up" + | "resolution cycle down" + | "resolution up" + | "resolution down" + | "resolution alternate" + | "resolution default" + | "profile cycle up" + | "profile cycle down" + | "profile up" + | "profile down" + | "second mode" + | "battery level"; + +/** + * A mode for a led. + */ +export type LedMode = "off" | "on" | "cycle" | "breath"; + +type RatBagDeviceInterface = ClientInterface & { + Commit(): Promise; +}; + +type RatBagProfileInterface = ClientInterface & { + SetActive(): Promise; +}; + +type RatBagResolutionInterface = ClientInterface & { + SetDefault(): Promise; + SetActive(): Promise; +}; diff --git a/nodecg-io-dbus/package.json b/nodecg-io-dbus/package.json new file mode 100644 index 000000000..94d40cbfc --- /dev/null +++ b/nodecg-io-dbus/package.json @@ -0,0 +1,47 @@ +{ + "name": "nodecg-io-dbus", + "version": "0.2.0", + "description": "Allows to interface with DBus", + "homepage": "https://nodecg.io/RELEASE/samples/dbus", + "author": { + "name": "noeppi_noeppi", + "url": "https://github.com/noeppi-noeppi" + }, + "repository": { + "type": "git", + "url": "https://github.com/codeoverflow-org/nodecg-io.git", + "directory": "nodecg-io-dbus" + }, + "files": [ + "**/*.js", + "**/*.js.map", + "**/*.d.ts", + "*.json" + ], + "main": "extension/index", + "scripts": { + "build": "tsc -b", + "watch": "tsc -b -w", + "clean": "tsc -b --clean" + }, + "keywords": [ + "nodecg-io", + "nodecg-bundle" + ], + "nodecg": { + "compatibleRange": "^1.1.1", + "bundleDependencies": { + "nodecg-io-core": "^0.2.0" + } + }, + "license": "MIT", + "devDependencies": { + "@types/node": "^15.0.2", + "nodecg-types": "^1.8.2", + "typescript": "^4.2.4" + }, + "dependencies": { + "nodecg-io-core": "^0.2.0", + "dbus-next": "^0.10.2" + } +} diff --git a/nodecg-io-dbus/schema.json b/nodecg-io-dbus/schema.json new file mode 100644 index 000000000..6dd02a254 --- /dev/null +++ b/nodecg-io-dbus/schema.json @@ -0,0 +1,12 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "additionalProperties": false, + "properties": { + "busAddress": { + "type": "string", + "description": "The bus address for the session bus to use" + } + }, + "required": [] +} diff --git a/nodecg-io-dbus/tsconfig.json b/nodecg-io-dbus/tsconfig.json new file mode 100644 index 000000000..1c8405620 --- /dev/null +++ b/nodecg-io-dbus/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../tsconfig.common.json" +} diff --git a/package-lock.json b/package-lock.json index 26da7c7e8..7279e319f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "ajv": "^8.2.0", "clean-webpack-plugin": "^3.0.0", "crypto-js": "^4.0.0", + "dbus-next": "^0.10.2", "discord.js": "^12.5.3", "easymidi": "^2.0.4", "elgato-stream-deck": "^4.0.1", @@ -3442,6 +3443,14 @@ "node": ">= 8" } }, + "node_modules/@nornagon/put": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@nornagon/put/-/put-0.0.8.tgz", + "integrity": "sha512-ugvXJjwF5ldtUpa7D95kruNJ41yFQDEKyF5CW4TgKJnh+W/zmlBzXXeKTyqIgwMFrkePN2JqOBqcF0M0oOunow==", + "engines": { + "node": ">=0.3.0" + } + }, "node_modules/@octokit/auth-token": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", @@ -4755,7 +4764,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true + "devOptional": true }, "node_modules/abort-controller": { "version": "3.0.0", @@ -7077,6 +7086,23 @@ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz", "integrity": "sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig==" }, + "node_modules/dbus-next": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/dbus-next/-/dbus-next-0.10.2.tgz", + "integrity": "sha512-kLNQoadPstLgKKGIXKrnRsMgtAK/o+ix3ZmcfTfvBHzghiO9yHXpoKImGnB50EXwnfSFaSAullW/7UrSkAISSQ==", + "dependencies": { + "@nornagon/put": "0.0.8", + "event-stream": "3.3.4", + "hexy": "^0.2.10", + "jsbi": "^2.0.5", + "long": "^4.0.0", + "safe-buffer": "^5.1.1", + "xml2js": "^0.4.17" + }, + "optionalDependencies": { + "usocket": "^0.3.0" + } + }, "node_modules/debug": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", @@ -7467,8 +7493,7 @@ "node_modules/duplexer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" }, "node_modules/duplexer3": { "version": "0.1.4", @@ -7711,7 +7736,7 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, + "devOptional": true, "engines": { "node": ">=6" } @@ -8196,6 +8221,31 @@ "node": ">= 0.6" } }, + "node_modules/event-stream": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", + "dependencies": { + "duplexer": "~0.1.1", + "from": "~0", + "map-stream": "~0.1.0", + "pause-stream": "0.0.11", + "split": "0.3", + "stream-combiner": "~0.0.4", + "through": "~2.3.1" + } + }, + "node_modules/event-stream/node_modules/split": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", + "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", + "dependencies": { + "through": "2" + }, + "engines": { + "node": "*" + } + }, "node_modules/event-target-shim": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", @@ -8984,6 +9034,11 @@ "node": ">= 0.6" } }, + "node_modules/from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=" + }, "node_modules/from2": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", @@ -10477,6 +10532,14 @@ "node": ">=8" } }, + "node_modules/hexy": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/hexy/-/hexy-0.2.11.tgz", + "integrity": "sha512-ciq6hFsSG/Bpt2DmrZJtv+56zpPdnq+NQ4ijEFrveKN0ZG1mhl/LdT1NQZ9se6ty1fACcI4d4vYqC9v8EYpH2A==", + "bin": { + "hexy": "bin/hexy_cmd.js" + } + }, "node_modules/hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -12848,6 +12911,11 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsbi": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/jsbi/-/jsbi-2.0.5.tgz", + "integrity": "sha512-TzO/62Hxeb26QMb4IGlI/5X+QLr9Uqp1FPkwp2+KOICW+Q+vSuFj61c8pkT6wAns4WcK56X7CmSHhJeDGWOqxQ==" + }, "node_modules/jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", @@ -13420,6 +13488,11 @@ "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", "dev": true }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, "node_modules/loud-rejection": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", @@ -13537,6 +13610,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/map-stream": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", + "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=" + }, "node_modules/map-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", @@ -15434,6 +15512,14 @@ "node": ">=8" } }, + "node_modules/pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", + "dependencies": { + "through": "~2.3" + } + }, "node_modules/performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -16742,6 +16828,11 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, "node_modules/saxes": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", @@ -17770,6 +17861,14 @@ "node": ">=0.10.0" } }, + "node_modules/stream-combiner": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", + "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", + "dependencies": { + "duplexer": "~0.1.1" + } + }, "node_modules/stream-each": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", @@ -18346,8 +18445,7 @@ "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, "node_modules/through2": { "version": "3.0.2", @@ -19105,6 +19203,138 @@ "node": ">=0.10.0" } }, + "node_modules/usocket": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/usocket/-/usocket-0.3.0.tgz", + "integrity": "sha512-V/H02RNiaOCJZuPoKont/y12VJaImC6C5xW7OzPFjYu9qnig0yv9hyp9E7Wqjm6d8yZuZouH3NAfDATVMgh2SQ==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.14.2", + "node-gyp": "^7.1.2" + } + }, + "node_modules/usocket/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "optional": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/usocket/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/usocket/node_modules/minipass": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.5.tgz", + "integrity": "sha512-+8NzxD82XQoNKNrl1d/FSi+X8wAEWR+sbYAfIvub4Nz0d22plFG72CEVVaufV8PNf4qSslFTD8VMOxNVhHCjTw==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/usocket/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/usocket/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "optional": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/usocket/node_modules/node-gyp": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz", + "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==", + "optional": true, + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.3", + "nopt": "^5.0.0", + "npmlog": "^4.1.2", + "request": "^2.88.2", + "rimraf": "^3.0.2", + "semver": "^7.3.2", + "tar": "^6.0.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": ">= 10.12.0" + } + }, + "node_modules/usocket/node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "optional": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/usocket/node_modules/tar": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "optional": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/usocket/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -19867,6 +20097,26 @@ "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" }, + "node_modules/xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "engines": { + "node": ">=4.0" + } + }, "node_modules/xmlchars": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", @@ -22730,6 +22980,11 @@ "fastq": "^1.6.0" } }, + "@nornagon/put": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@nornagon/put/-/put-0.0.8.tgz", + "integrity": "sha512-ugvXJjwF5ldtUpa7D95kruNJ41yFQDEKyF5CW4TgKJnh+W/zmlBzXXeKTyqIgwMFrkePN2JqOBqcF0M0oOunow==" + }, "@octokit/auth-token": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", @@ -23870,7 +24125,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true + "devOptional": true }, "abort-controller": { "version": "3.0.0", @@ -25725,6 +25980,21 @@ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz", "integrity": "sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig==" }, + "dbus-next": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/dbus-next/-/dbus-next-0.10.2.tgz", + "integrity": "sha512-kLNQoadPstLgKKGIXKrnRsMgtAK/o+ix3ZmcfTfvBHzghiO9yHXpoKImGnB50EXwnfSFaSAullW/7UrSkAISSQ==", + "requires": { + "@nornagon/put": "0.0.8", + "event-stream": "3.3.4", + "hexy": "^0.2.10", + "jsbi": "^2.0.5", + "long": "^4.0.0", + "safe-buffer": "^5.1.1", + "usocket": "^0.3.0", + "xml2js": "^0.4.17" + } + }, "debug": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", @@ -26026,8 +26296,7 @@ "duplexer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" }, "duplexer3": { "version": "0.1.4", @@ -26241,7 +26510,7 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true + "devOptional": true }, "envinfo": { "version": "7.8.1", @@ -26606,6 +26875,30 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, + "event-stream": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", + "requires": { + "duplexer": "~0.1.1", + "from": "~0", + "map-stream": "~0.1.0", + "pause-stream": "0.0.11", + "split": "0.3", + "stream-combiner": "~0.0.4", + "through": "~2.3.1" + }, + "dependencies": { + "split": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", + "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", + "requires": { + "through": "2" + } + } + } + }, "event-target-shim": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", @@ -27241,6 +27534,11 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, + "from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=" + }, "from2": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", @@ -28430,6 +28728,11 @@ "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", "dev": true }, + "hexy": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/hexy/-/hexy-0.2.11.tgz", + "integrity": "sha512-ciq6hFsSG/Bpt2DmrZJtv+56zpPdnq+NQ4ijEFrveKN0ZG1mhl/LdT1NQZ9se6ty1fACcI4d4vYqC9v8EYpH2A==" + }, "hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -30216,6 +30519,11 @@ "esprima": "^4.0.0" } }, + "jsbi": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/jsbi/-/jsbi-2.0.5.tgz", + "integrity": "sha512-TzO/62Hxeb26QMb4IGlI/5X+QLr9Uqp1FPkwp2+KOICW+Q+vSuFj61c8pkT6wAns4WcK56X7CmSHhJeDGWOqxQ==" + }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", @@ -30667,6 +30975,11 @@ "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", "dev": true }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, "loud-rejection": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", @@ -30759,6 +31072,11 @@ "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", "dev": true }, + "map-stream": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", + "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=" + }, "map-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", @@ -32300,6 +32618,14 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, + "pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", + "requires": { + "through": "~2.3" + } + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -33264,6 +33590,11 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, "saxes": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", @@ -34098,6 +34429,14 @@ "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" }, + "stream-combiner": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", + "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", + "requires": { + "duplexer": "~0.1.1" + } + }, "stream-each": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", @@ -34531,8 +34870,7 @@ "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, "through2": { "version": "3.0.2", @@ -35111,6 +35449,106 @@ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "dev": true }, + "usocket": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/usocket/-/usocket-0.3.0.tgz", + "integrity": "sha512-V/H02RNiaOCJZuPoKont/y12VJaImC6C5xW7OzPFjYu9qnig0yv9hyp9E7Wqjm6d8yZuZouH3NAfDATVMgh2SQ==", + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.14.2", + "node-gyp": "^7.1.2" + }, + "dependencies": { + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "optional": true + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "optional": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.5.tgz", + "integrity": "sha512-+8NzxD82XQoNKNrl1d/FSi+X8wAEWR+sbYAfIvub4Nz0d22plFG72CEVVaufV8PNf4qSslFTD8VMOxNVhHCjTw==", + "optional": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "optional": true, + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "optional": true + }, + "node-gyp": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz", + "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==", + "optional": true, + "requires": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.3", + "nopt": "^5.0.0", + "npmlog": "^4.1.2", + "request": "^2.88.2", + "rimraf": "^3.0.2", + "semver": "^7.3.2", + "tar": "^6.0.2", + "which": "^2.0.2" + } + }, + "nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "optional": true, + "requires": { + "abbrev": "1" + } + }, + "tar": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "optional": true, + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + } + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -35684,6 +36122,20 @@ "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" }, + "xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" + }, "xmlchars": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", diff --git a/samples/dbus-ratbagd/extension/index.ts b/samples/dbus-ratbagd/extension/index.ts new file mode 100644 index 000000000..6c0c91294 --- /dev/null +++ b/samples/dbus-ratbagd/extension/index.ts @@ -0,0 +1,24 @@ +import { NodeCG } from "nodecg-types/types/server"; +import { DBusClient } from "nodecg-io-dbus"; +import { RatBagManager } from "nodecg-io-dbus/extension/ratbag"; +import { requireService } from "nodecg-io-core"; + +module.exports = function (nodecg: NodeCG) { + nodecg.log.info("Sample bundle for Dbus started."); + + const dbus = requireService(nodecg, "dbus"); + + dbus?.onAvailable(async (client) => { + nodecg.log.info("DBus service available."); + const ratbag = await client.proxy(RatBagManager.PROXY); + const devices = await ratbag.devices(); + nodecg.log.info("ratbagd devices:"); + for (const device of devices) { + nodecg.log.info(" - " + (await device.name())); + } + }); + + dbus?.onUnavailable(() => { + nodecg.log.info("DBus service unavailable."); + }); +}; diff --git a/samples/dbus-ratbagd/package.json b/samples/dbus-ratbagd/package.json new file mode 100644 index 000000000..00c52492c --- /dev/null +++ b/samples/dbus-ratbagd/package.json @@ -0,0 +1,24 @@ +{ + "name": "dbus-ratbagd", + "version": "0.2.0", + "private": true, + "nodecg": { + "compatibleRange": "^1.1.1", + "bundleDependencies": { + "nodecg-io-dbus": "0.2.0" + } + }, + "scripts": { + "build": "tsc -b", + "watch": "tsc -b -w", + "clean": "tsc -b --clean" + }, + "license": "MIT", + "dependencies": { + "@types/node": "^15.0.2", + "nodecg-types": "^1.8.2", + "nodecg-io-core": "^0.2.0", + "typescript": "^4.2.4", + "nodecg-io-dbus": "0.2.0" + } +} diff --git a/samples/dbus-ratbagd/tsconfig.json b/samples/dbus-ratbagd/tsconfig.json new file mode 100644 index 000000000..c8bb01bee --- /dev/null +++ b/samples/dbus-ratbagd/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig.common.json" +}