diff options
author | Profpatsch <mail@profpatsch.de> | 2024-12-10T02·16+0100 |
---|---|---|
committer | Profpatsch <mail@profpatsch.de> | 2024-12-10T15·34+0000 |
commit | c12fdeb8e003685fc7fe9f3c579afefac30a054b (patch) | |
tree | 4dd72e032f6f972c1eff2fbf8df2fefd1df72844 /users/Profpatsch | |
parent | 4eeac3cb1dcf933482d00169140a09a7c01f3a3f (diff) |
refactor(users/Profpatsch): simple wrapper around the dbus lib r/8999
This makes defining the interface a little less verbose & more typesafe (checks are done by the dbus library). Change-Id: I16df987fd152cabf76ed9878ed1a372a0f7003fb Reviewed-on: https://cl.tvl.fyi/c/depot/+/12886 Reviewed-by: Profpatsch <mail@profpatsch.de> Tested-by: BuildkiteCI
Diffstat (limited to 'users/Profpatsch')
-rw-r--r-- | users/Profpatsch/alacritty-change-color-scheme/alacritty-change-color-scheme.js | 246 |
1 files changed, 159 insertions, 87 deletions
diff --git a/users/Profpatsch/alacritty-change-color-scheme/alacritty-change-color-scheme.js b/users/Profpatsch/alacritty-change-color-scheme/alacritty-change-color-scheme.js index ca2e86a2b798..728463e407da 100644 --- a/users/Profpatsch/alacritty-change-color-scheme/alacritty-change-color-scheme.js +++ b/users/Profpatsch/alacritty-change-color-scheme/alacritty-change-color-scheme.js @@ -35,9 +35,113 @@ const lightTheme = getThemePathSync(lightThemeName); console.log(`Dark theme: ${darkTheme}`); console.log(`Light theme: ${lightTheme}`); +class Bus { + /** + * @param {'session' | 'system'} type + * @param {string} name + */ + constructor(name, type) { + this._name = name; + this._type = type; + switch (type) { + case 'session': + this._bus = dbus.sessionBus(); + break; + case 'system': + this._bus = dbus.systemBus(); + break; + } + this._bus.connection.once('error', err => { + console.error(`${this._type} bus ${this._name} error: ${err}`); + throw new Error(`${this._type} bus ${this._name} error: ${err}`); + }); + this._bus.connection.once('end', () => { + console.error(`${this._type} bus ${this._name} connection ended unexpectedly`); + throw new Error(`${this._type} bus ${this._name} connection ended unexpectedly`); + }); + } + + _busErrorMessages(what) { + return `Error getting ${what} from ${this._type} bus ${this._name}`; + } + + /** + * + * @param {string} name + * @param {number} flags + * @returns {Promise<number>} + */ + requestName(name, flags) { + return promisifyMethodAnnotate( + this._bus, + // @ts-ignore + this._bus.requestName, + this._busErrorMessages(`requesting name ${name}`), + name, + flags, + ); + } + + /** + * @param {{ [key: string]: unknown }} iface + * @param {string} path + * @param {{ name: string; methods: { [key: string]: unknown }; }} opts + */ + exportInterface(iface, path, opts) { + // @ts-ignore + return this._bus.exportInterface(iface, path, opts); + } + + /** + /** Get object from bus, with the given interface (not checked!) + * @template {{[key: string]: (...args: any[]) => Promise<unknown>}} Interface + * @param {string} serviceName + * @param {string} interfaceName + * @param {string} objectName object name + * @returns {Promise<Interface & EventEmitter >} + */ + async getObject(serviceName, interfaceName, objectName) { + //@ts-ignore + const s = this._bus.getService(serviceName); + + /** @type {{[key: string]: Function}} */ + // @ts-ignore + const iface = await promisifyMethodAnnotate( + s, + s.getInterface, + this._busErrorMessages(`interface ${interfaceName}`), + objectName, + interfaceName, + ); + + if (!iface) { + throw new Error( + `Interface ${interfaceName} not found on object ${objectName} of service ${serviceName}`, + ); + } + + // We need to promisify all methods on the interface + const methodNames = Object.keys(iface.$methods ?? {}); + const methods = {}; + /** @type {Record<string, Function>} */ + for (const methodName of methodNames) { + methods[methodName] = iface[methodName]; + iface[methodName] = (...args) => + promisifyMethodAnnotate( + iface, + methods[methodName], + this._busErrorMessages(`method ${methodName}`), + ...args, + ); + } + + // @ts-ignore + return iface; + } +} + // Connect to the user session bus -/** @type any */ -const bus = dbus.sessionBus(); +const bus = new Bus('color-scheme', 'session'); opentelemetry.diag.setLogger({ ...console, verbose: console.log }); @@ -167,17 +271,6 @@ function setupActiveSpan(tracer, spanData) { ); } -// tracer.startActiveSpan('222', span => { -// span.setAttribute('blabla', 'alacritty-change-color-scheme'); -// tracer.startActiveSpan('333', span => { -// span.setAttribute('foo', 'bar'); -// span.end(); -// }); -// // span.setAttribute('service.name', 'alacritty-change-color-scheme'); -// // span.setAttribute('service.version', '0.0.1'); -// span.end(); -// }); - // set XDG_CONFIG_HOME if it's not set if (!process.env.XDG_CONFIG_HOME) { process.env.XDG_CONFIG_HOME = process.env.HOME + '/.config'; @@ -196,7 +289,8 @@ function getThemePathSync(theme) { */ function writeAlacrittyColorConfig(cs) { const theme = cs === 'prefer-dark' ? darkTheme : lightTheme; - console.log(`Writing color scheme ${cs} with theme ${theme}`); + console.log(` + Writing color scheme ${cs} with theme ${theme}`); fs.writeFileSync( process.env.XDG_CONFIG_HOME + '/alacritty/alacritty-colors-autogen.toml', `# !! THIS FILE IS GENERATED BY ${programName} @@ -205,27 +299,35 @@ general.import = ["${theme}"]`, ); } +/** Typescript type that returns the inner value type T from a Promise<T> + * type PromiseVal<T> = T extends Promise<infer U> ? U : T; + * @template T + * @typedef {T extends Promise<infer U> ? U : T } PromiseVal + */ + +/** + * @template {{[key: string]: (...args: any[]) => Promise<unknown>}} T + * @typedef {typeof Bus.prototype.getObject<T>} GetObject<T> + */ + +/** + * @template {{[key: string]: (...args: any[]) => Promise<unknown>}} T + * @typedef {PromiseVal<ReturnType<GetObject<T>>>} IfaceReturn<T> */ + /** get the current value of the color scheme from dbus * * @returns {Promise<'prefer-dark' | 'prefer-light'>} */ async function getColorScheme() { - let service = bus.getService('org.freedesktop.portal.Desktop'); - let iface = await promisifyMethodAnnotate( - service, - service.getInterface, - 'Error getting interface', - '/org/freedesktop/portal/desktop', + /** @typedef {{ReadOne: (interface: string, settingName: string) => Promise<[unknown, ['prefer-dark' | 'prefer-light']]>}} ColorScheme */ + /** @type {IfaceReturn<ColorScheme>} */ + let iface = await bus.getObject( + 'org.freedesktop.portal.Desktop', 'org.freedesktop.portal.Settings', + '/org/freedesktop/portal/desktop', ); - const [_, [value]] = await promisifyMethodAnnotate( - iface, - iface.ReadOne, - 'Error reading color scheme', - 'org.gnome.desktop.interface', - 'color-scheme', - ); + const [_, [value]] = await iface.ReadOne('org.gnome.desktop.interface', 'color-scheme'); assert(value === 'prefer-dark' || value === 'prefer-light'); return value; } @@ -260,14 +362,11 @@ function writeAlacrittyColorConfigIfDifferent(cs) { /** Listen on the freedesktop SettingChanged dbus interface for the color-scheme setting to change. */ async function listenForColorschemeChange() { - const service = bus.getService('org.freedesktop.portal.Desktop'); - - const iface = await promisifyMethodAnnotate( - service, - service.getInterface, - 'Error getting interface', - '/org/freedesktop/portal/desktop', + /** @type {PromiseVal<ReturnType<typeof bus.getObject<{}>>>} */ + const iface = await bus.getObject( + 'org.freedesktop.portal.Desktop', 'org.freedesktop.portal.Settings', + '/org/freedesktop/portal/desktop', ); // Listen for SettingChanged signals @@ -299,18 +398,12 @@ async function exportColorSchemeDbusInterface() { }; try { - const retCode = await promisifyMethodAnnotate( - bus, - bus.requestName, - 'Error requesting name for interface de.profpatsch.alacritty.ColorScheme', - ifaceName, - 0, - ); + bus; + const retCode = await bus.requestName(ifaceName, 0); console.log( `Request name returned ${retCode} for interface de.profpatsch.alacritty.ColorScheme`, ); bus.exportInterface(ifaceImpl, '/de/profpatsch/alacritty/ColorScheme', iface); - bus.exportInterface(ifaceImpl, '/de/profpatsch/alacritty/ColorScheme2', iface); console.log('Exported interface de.profpatsch.alacritty.ColorScheme'); } catch (err) { console.log('Error exporting interface de.profpatsch.alacritty.ColorScheme'); @@ -330,20 +423,12 @@ function annotateErr(msg) { }; } -/** @type any */ -const bus2 = dbus.sessionBus(); +const bus2 = new Bus('otel', 'session'); async function exportOtelInterface() { console.log('Exporting OpenTelemetry interface'); try { - const retCode = await promisifyMethodAnnotate( - bus2, - bus2.requestName, - 'Error requesting name for interface de.profpatsch.otel.Tracer', - - 'de.profpatsch.otel.Tracer', - 0, - ); + const retCode = bus2.requestName('de.profpatsch.otel.Tracer', 0); console.log( `Request name returned ${retCode} for interface de.profpatsch.otel.Tracer`, ); @@ -442,49 +527,38 @@ async function getParentCallsite() { async function setupTracer(tracerName) { const parentCallsite = await getParentCallsite(); console.log(`Setting up tracer ${tracerName} from ${parentCallsite?.getFileName()}`); - const service = bus2.getService('de.profpatsch.otel.Tracer'); - const iface = await promisifyMethodAnnotate( - service, - service.getInterface, - 'Error getting interface', - '/de/profpatsch/otel/TracerFactory', + + /** @typedef {{CreateTracer: (name: string) => Promise<string>}} TracerFactory */ + /** @type {IfaceReturn<TracerFactory>} */ + const iface = await bus2.getObject( + 'de.profpatsch.otel.Tracer', 'de.profpatsch.otel.TracerFactory', + '/de/profpatsch/otel/TracerFactory', ); - const path = await promisifyMethodAnnotate( - iface, - iface.CreateTracer, - 'Error creating tracer', - tracerName, - ); - const tracerIface = await promisifyMethodAnnotate( - service, - service.getInterface, - 'Error getting interface', - path, + const path = await iface.CreateTracer(tracerName); + + /** + * @typedef {{ + * StartSpan: (spanData: string) => Promise<void>, + * EndSpan: (spanData: string) => Promise<void> + * BatchSpans: ([bool, string]) => Promise<void> + * }} Tracer + * @type {IfaceReturn<Tracer>} + * */ + const tracerIface = await bus2.getObject( + 'de.profpatsch.otel.Tracer', 'de.profpatsch.otel.Tracer', + path, ); function StartSpan(spanData) { - return promisifyMethodAnnotate( - tracerIface, - tracerIface.StartSpan, - 'Error starting span', - JSON.stringify(spanData), - ); + return tracerIface.StartSpan(JSON.stringify(spanData)); } function EndSpan(spanData) { - return promisifyMethodAnnotate( - tracerIface, - tracerIface.EndSpan, - 'Error ending span', - JSON.stringify(spanData), - ); + return tracerIface.EndSpan(JSON.stringify(spanData)); } function BatchSpans(spans) { - return promisifyMethodAnnotate( - tracerIface, - tracerIface.BatchSpans, - 'Error batching spans', + return tracerIface.BatchSpans( spans.map(([isStartSpan, span]) => [isStartSpan, JSON.stringify(span)]), ); } @@ -548,8 +622,6 @@ async function main() { [false, { spanId: 'batchy', endTime: t + 1000 }], ]); - // TODO: proper error handling, through proper callback promises for dbus function. - await exportColorSchemeDbusInterface(); // get the current color scheme |