productivity-nkh/electron/dbus.ts

174 lines
4.7 KiB
TypeScript

'use strict';
import { IPC } from './shared-with-frontend/ipc-events.const';
import { error, log } from 'electron-log';
const errorHandler = require('./error-handler-with-frontend-inform');
const mainWinMod = require('./main-window');
// only optionally require dbus
let isDBusError = false;
let dbus;
try {
dbus = require('dbus-native');
} catch (e) {
log('NOTE: Continuing without DBUS');
error(e);
isDBusError = true;
}
const CONFIG = require('./CONFIG');
const serviceName = CONFIG.D_BUS_ID;
const interfaceName = serviceName;
const objectPath = '/' + serviceName.replace(/\./g, '/');
let sessionBus;
let ifaceDesc;
let iface;
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
function init(params): void {
sessionBus = dbus.sessionBus();
// Check the connection was successful
if (!sessionBus) {
isDBusError = true;
errorHandler(`DBus: Could not connect to the DBus session bus.`);
}
sessionBus.requestName(serviceName, 0x4, (e, retCode) => {
// If there was an error, warn user and fail
if (e) {
isDBusError = true;
errorHandler(
`DBus: Could not request service name ${serviceName}, the error was: ${e}.`,
);
}
// Return code 0x1 means we successfully had the name
if (retCode === 1) {
log(`Successfully requested service name '${serviceName}'!`);
proceed();
/* Other return codes means various errors, check here
(https://dbus.freedesktop.org/doc/api/html/group__DBusShared.html#ga37a9bc7c6eb11d212bf8d5e5ff3b50f9) for more
information
*/
} else {
isDBusError = true;
errorHandler(
`DBus: Failed to request service name '${serviceName}'.Check what return code '${retCode}' means.`,
);
}
});
// Function called when we have successfully got the service name we wanted
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
function proceed(): void {
// First, we need to create our interface description (here we will only expose method calls)
ifaceDesc = {
name: interfaceName,
methods: {
// Simple types
markAsDone: [],
startTask: [],
pauseTask: [],
showApp: [],
quitApp: [],
},
properties: {},
signals: {
taskChanged: ['ss', 'task_id', 'task_text'],
pomodoroUpdate: ['bxx', 'is_on_break', 'session_time_left', 'session_total_time'],
},
};
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
function checkMainWin(): void {
const mainWin = mainWinMod.getWin();
if (!mainWin) {
errorHandler('DBus: mainWin not ready');
}
}
// Then we need to create the interface implementation (with actual functions)
iface = {
markAsDone: () => {
checkMainWin();
const mainWin = mainWinMod.getWin();
mainWin.webContents.send(IPC.TASK_MARK_AS_DONE);
},
startTask: () => {
checkMainWin();
const mainWin = mainWinMod.getWin();
mainWin.webContents.send(IPC.TASK_START);
},
pauseTask: () => {
checkMainWin();
const mainWin = mainWinMod.getWin();
mainWin.webContents.send(IPC.TASK_PAUSE);
},
showApp: () => {
params.showApp();
},
quitApp: () => {
params.quitApp();
},
emit: () => {
// no nothing, as usual
},
};
// Now we need to actually export our interface on our object
sessionBus.exportInterface(iface, objectPath, ifaceDesc);
// Say our service is ready to receive function calls (you can use `gdbus call` to make function calls)
log('Interface exposed to DBus, ready to receive function calls!');
}
}
let isErrorShownOnce = false;
if (!isDBusError) {
module.exports = {
init,
setTask: (taskId, taskText) => {
// fail silently to prevent hundreds of error messages
if (isDBusError || isErrorShownOnce) {
return;
}
if (iface) {
errorHandler('DBus: interface not ready yet');
isErrorShownOnce = true;
} else {
iface.emit('taskChanged', taskId + '', taskText + '');
}
},
updatePomodoro: (isOnBreak, currentSessionTime, currentSessionInitialTime) => {
// fail silently to prevent hundreds of error messages
if (isDBusError || isErrorShownOnce) {
return;
}
if (iface) {
iface.emit(
'pomodoroUpdate',
isOnBreak ? 1 : 0,
currentSessionTime,
currentSessionInitialTime,
);
} else {
errorHandler('DBus: interface not ready yet');
isErrorShownOnce = true;
}
},
};
} else {
module.exports = {
init: () => {},
setTask: () => {},
updatePomodoro: () => {},
};
}