vrem
Version:
An open-source automatic time-tracker
155 lines (154 loc) • 6.91 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const http_1 = require("http");
const tracker_types_1 = require("./tracker_types");
const ipc_1 = require("../ipc");
const constants_1 = __importDefault(require("../constants"));
const ipc_2 = require("../ipc");
const fs_1 = __importDefault(require("fs"));
const tracker_utils_1 = require("./tracker_utils");
const { getActiveProgram, getIdleTime } = require('../../dist_native/vrem_windows.node');
const PORT = 3211;
function startHttpServer() {
const server = (0, http_1.createServer)(async (req, res) => {
try {
if (req.url === '/' && req.method === 'POST' && req.headers["content-type"] === 'application/json') {
const chunks = [];
for await (const chunk of req)
chunks.push(chunk);
if (!req.complete)
return;
const string = Buffer.concat(chunks).toString('utf8');
const data = JSON.parse(string);
main(data);
}
res.writeHead(200).end();
}
catch (e) {
try {
res.writeHead(500).end();
}
catch (e) { }
tracker_utils_1.dev && console.error(e);
}
});
server.listen(PORT, () => {
console.info("Vrem's tracking process is listening on port ", PORT);
});
}
let subscriber = null;
function startIpcServer() {
const server = new ipc_2.IpcServer();
// server.command('subprogram', payload => {
// main(payload);
// return true;
// });
server.command('subscribe', (payload, socket) => {
subscriber = (0, ipc_1.createSequentialSocket)(socket);
void subscriber.send(lastProgram);
socket.on('close', () => {
subscriber = null;
});
socket.on('error', () => { }); // ignore errors
});
server.listen(constants_1.default.autoTrackerSocketPath, () => {
console.info("Vrem's tracking process is listening on socket ", constants_1.default.autoTrackerSocketPath);
});
}
// Set onExit callbacks to add the last entry to the log file
{
const exit = () => process.exit();
process.on('SIGINT', exit);
process.on('SIGTERM', exit);
const exceptionHandler = e => {
tracker_utils_1.dev && console.error(e);
fs_1.default.appendFileSync(constants_1.default.appFolder + '/tracker_errors.log', `\n${new Date()}\n${e.stack}\n`, 'utf8');
process.exit(1);
};
process.on('uncaughtException', exceptionHandler);
process.on('unhandledRejection', exceptionHandler);
startIpcServer();
startHttpServer();
(0, tracker_utils_1.saveCurrentProgramToLogs)();
(0, tracker_utils_1.addToLogs)({ begin: true, timestamp: Date.now() });
process.on('exit', () => {
(0, tracker_utils_1.addToLogs)({ end: true, timestamp: Date.now() });
tracker_utils_1.dev && console.log('Exit');
});
}
let lastProgram = null;
let lastSubprogramTimestamp = null;
// deferredProgram can be only a browser. If the user switches to another program,
// the tracker forgets the subprogram at once. deferredProgram makes sense when the extension is disabled,
// but the browser remains in focus.
let deferredProgram = null;
let isIdle = false;
const IDLE_THRESHOLD = 90000;
const SUBPROGRAM_TIMEOUT = 2000;
const MAIN_INTERVAL = 1000;
function main(subprogramData = null) {
const idleTime = getIdleTime();
tracker_utils_1.dev && console.log('Idle time = ', getIdleTime());
if (idleTime > IDLE_THRESHOLD) {
if (!isIdle) {
(0, tracker_utils_1.addToLogs)({ idle: true, timestamp: Date.now() });
isIdle = true;
lastProgram = null;
}
return;
}
else if (isIdle) {
isIdle = false;
}
const activeProgram = getActiveProgram();
if (!activeProgram || activeProgram.error)
return;
activeProgram.timestamp = Date.now();
function processProgram(program) {
if (!lastProgram || lastProgram.path !== program.path || (0, tracker_types_1.isSubprogram)(lastProgram) !== (0, tracker_types_1.isSubprogram)(program)) {
(0, tracker_utils_1.addToLogs)(program);
lastProgram = program;
subscriber && subscriber.send(lastProgram);
}
else if (program.timestamp - (lastProgram.lastActiveTimestamp || lastProgram.timestamp) > 9999) {
lastProgram.lastActiveTimestamp = program.timestamp;
(0, tracker_utils_1.updateCurrentProgramLastActiveTimestamp)(lastProgram.lastActiveTimestamp);
}
}
if (subprogramData) { // when request came from the browser extension
const subprogram = { ...subprogramData, description: '', parent: activeProgram };
lastSubprogramTimestamp = subprogramData.timestamp;
if (!subprogram.path // extension send the last message with null values, when there is no focused website.
// When subprogram changed parent.path it can be that there are two browsers,
// but also that the user has switch to another program. We assume the latter here.
|| ((0, tracker_types_1.isSubprogram)(lastProgram) && lastProgram.path === subprogram.path && lastProgram.parent.path !== subprogram.parent.path)) {
tracker_utils_1.dev && console.log('Turn off subprogram mode', subprogram);
lastSubprogramTimestamp = null;
}
else {
if (activeProgram.timestamp - subprogram.timestamp < 100) {
//dev && console.log('timestamp diff', activeProgram.timestamp - subprogram.timestamp);
processProgram(subprogram);
deferredProgram = null;
}
return;
}
}
if ((0, tracker_types_1.isSubprogram)(lastProgram) && lastSubprogramTimestamp) { // usual iteration
if ((Date.now() - lastSubprogramTimestamp > SUBPROGRAM_TIMEOUT) || lastProgram.parent.path !== activeProgram.path) {
tracker_utils_1.dev && console.log(`Switch to usual mode ${Date.now() - lastSubprogramTimestamp > SUBPROGRAM_TIMEOUT
? ' due to timeout' : 'due to program change.'}` + 'The deferred: ', deferredProgram);
deferredProgram && processProgram(deferredProgram);
deferredProgram = null;
}
else {
deferredProgram = deferredProgram || activeProgram; // we should preserve the oldest timestamp
return;
}
}
processProgram(activeProgram);
}
setInterval(main, MAIN_INTERVAL);