Files
linux-sys-telemetry/org.sensord/gnome-sensor-tray/src/sensorClient.js

156 lines
4.8 KiB
JavaScript

import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
const BUS_NAME = 'org.sensord';
const OBJECT_PATH = '/org/sensord';
const IFACE_PREFIX = 'org.sensord.';
export default class SensorClient {
constructor() {
this._conn = null;
this._signalIds = [];
this._readings = new Map();
this._meta = new Map();
this._onChanged = null;
this._available = false;
this._nameWatchId = 0;
}
start(onChanged) {
this._onChanged = onChanged;
try {
this._conn = Gio.bus_get_sync(Gio.BusType.SYSTEM, null);
} catch (e) {
console.error('sensortray: cannot connect to system bus:', e.message);
return;
}
this._nameWatchId = Gio.bus_watch_name_on_connection(
this._conn,
BUS_NAME,
Gio.BusNameWatcherFlags.NONE,
() => this._onNameAppeared(),
() => this._onNameVanished(),
);
}
_onNameAppeared() {
this._available = true;
this._discover();
}
_onNameVanished() {
this._available = false;
this._unsubscribeAll();
this._readings.clear();
this._meta.clear();
if (this._onChanged)
this._onChanged(null, null);
}
_discover() {
this._unsubscribeAll();
this._readings.clear();
this._meta.clear();
let introXml;
try {
let result = this._conn.call_sync(
BUS_NAME, OBJECT_PATH,
'org.freedesktop.DBus.Introspectable', 'Introspect',
null, GLib.VariantType.new('(s)'),
Gio.DBusCallFlags.NONE, 3000, null,
);
[introXml] = result.deep_unpack();
} catch (e) {
console.error('sensortray: introspect failed:', e.message);
return;
}
let ifaces = [];
let re = /interface\s+name="(org\.sensord\.[^"]+)"/g;
let m;
while ((m = re.exec(introXml)) !== null)
ifaces.push(m[1]);
for (let iface of ifaces) {
let category = iface.slice(IFACE_PREFIX.length);
let sid = this._conn.signal_subscribe(
BUS_NAME, iface, 'Changed', OBJECT_PATH,
null, Gio.DBusSignalFlags.NONE,
(_conn, _sender, _path, _iface, _signal, params) => {
let [readings] = params.deep_unpack();
this._readings.set(category, readings);
if (this._onChanged)
this._onChanged(category, readings);
},
);
this._signalIds.push(sid);
this._conn.call(
BUS_NAME, OBJECT_PATH, iface, 'GetMeta',
null, GLib.VariantType.new('(a{sv})'),
Gio.DBusCallFlags.NONE, 3000, null,
(conn, res) => {
try {
let result = conn.call_finish(res);
let [meta] = result.deep_unpack();
let parsed = {};
if (meta['icon'])
parsed.icon = meta['icon'].deep_unpack();
if (meta['units'])
parsed.units = meta['units'].deep_unpack();
this._meta.set(category, parsed);
} catch (e) {
console.debug(`sensortray: GetMeta(${iface}) unavailable:`, e.message);
}
},
);
this._conn.call(
BUS_NAME, OBJECT_PATH, iface, 'GetReadings',
null, GLib.VariantType.new('(a{sd})'),
Gio.DBusCallFlags.NONE, 3000, null,
(conn, res) => {
try {
let result = conn.call_finish(res);
let [readings] = result.deep_unpack();
this._readings.set(category, readings);
if (this._onChanged)
this._onChanged(category, readings);
} catch (e) {
console.error(`sensortray: GetReadings(${iface}) failed:`, e.message);
}
},
);
}
}
_unsubscribeAll() {
if (!this._conn)
return;
for (let sid of this._signalIds)
this._conn.signal_unsubscribe(sid);
this._signalIds = [];
}
get available() { return this._available; }
get readings() { return this._readings; }
get meta() { return this._meta; }
destroy() {
this._unsubscribeAll();
if (this._nameWatchId) {
Gio.bus_unwatch_name(this._nameWatchId);
this._nameWatchId = 0;
}
this._conn = null;
this._onChanged = null;
this._readings.clear();
this._meta.clear();
}
}