deepwork-node-watchdog 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +140 -0
- package/dist/helpers/blacklist.helper.d.ts +7 -0
- package/dist/helpers/blacklist.helper.js +64 -0
- package/dist/helpers/command.helper.d.ts +5 -0
- package/dist/helpers/command.helper.js +95 -0
- package/dist/helpers/config.helper.d.ts +8 -0
- package/dist/helpers/config.helper.js +80 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +53 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +54 -0
- package/dist/utils/log.util.d.ts +1 -0
- package/dist/utils/log.util.js +50 -0
- package/dist/utils/normalize.util.d.ts +1 -0
- package/dist/utils/normalize.util.js +6 -0
- package/dist/watchdog.d.ts +8 -0
- package/dist/watchdog.js +29 -0
- package/dist/watchdog.types.d.ts +17 -0
- package/dist/watchdog.types.js +2 -0
- package/package.json +27 -0
package/README.md
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# deepwork-node-watchdog
|
|
2
|
+
|
|
3
|
+
Watchdog de procesos para Node.js. Monitorea los procesos del sistema en intervalos configurables y mata automáticamente los procesos que estén en una lista negra. Compatible con **Windows**, **Linux** y **macOS**.
|
|
4
|
+
|
|
5
|
+
Pensado para entornos de trabajo enfocado: bloquea apps de distracción (Discord, WhatsApp, etc.) mientras trabajas.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Instalación
|
|
10
|
+
|
|
11
|
+
### Como herramienta global (CLI)
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install -g deepwork-node-watchdog
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Como dependencia en tu proyecto
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install deepwork-node-watchdog
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Uso como CLI
|
|
26
|
+
|
|
27
|
+
### Iniciar el watchdog
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
deepwork-watchdog --blacklist /ruta/absoluta/a/blacklist.txt
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Listar procesos en ejecución
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
deepwork-watchdog --list
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Archivo de lista negra (`blacklist.txt`)
|
|
40
|
+
|
|
41
|
+
Cada línea es el nombre de un proceso a matar. Las líneas vacías y los comentarios (`#`) son ignorados. La extensión `.exe` es opcional.
|
|
42
|
+
|
|
43
|
+
```txt
|
|
44
|
+
# Apps de distracción
|
|
45
|
+
discord
|
|
46
|
+
whatsapp
|
|
47
|
+
spotify
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Uso como librería
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import { start, stop, isRunning, listProcesses } from 'deepwork-node-watchdog';
|
|
56
|
+
|
|
57
|
+
// Iniciar el watchdog con una lista de procesos
|
|
58
|
+
start({
|
|
59
|
+
blacklist: ['discord', 'whatsapp', 'spotify'],
|
|
60
|
+
intervalMs: 5000, // Intervalo de escaneo en ms (default: 3000)
|
|
61
|
+
logFile: 'watchdog.log', // Opcional: archivo de log
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Detener el watchdog
|
|
65
|
+
stop();
|
|
66
|
+
|
|
67
|
+
// Verificar si está corriendo
|
|
68
|
+
console.log(isRunning()); // true | false
|
|
69
|
+
|
|
70
|
+
// Listar procesos activos
|
|
71
|
+
const processes = await listProcesses();
|
|
72
|
+
processes.forEach(p => console.log(`${p.name} (PID: ${p.pid})`));
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### También puedes usar un archivo de lista negra
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
start({
|
|
79
|
+
blacklistPath: '/ruta/absoluta/a/blacklist.txt',
|
|
80
|
+
intervalMs: 3000,
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## API
|
|
87
|
+
|
|
88
|
+
### `start(options: WatchdogOptions): void`
|
|
89
|
+
|
|
90
|
+
Inicia el watchdog. Si ya está corriendo, no hace nada.
|
|
91
|
+
|
|
92
|
+
| Opción | Tipo | Default | Descripción |
|
|
93
|
+
|-----------------|------------|------------------|--------------------------------------------------|
|
|
94
|
+
| `blacklist` | `string[]` | — | Lista de nombres de procesos a matar |
|
|
95
|
+
| `blacklistPath` | `string` | — | Ruta absoluta a un archivo de lista negra |
|
|
96
|
+
| `intervalMs` | `number` | `3000` | Intervalo entre escaneos en milisegundos |
|
|
97
|
+
| `logFile` | `string` | — | Ruta al archivo de log (opcional) |
|
|
98
|
+
|
|
99
|
+
> Se debe especificar `blacklist` o `blacklistPath`. Si no se especifica ninguno, el watchdog se inicia pero no hace nada.
|
|
100
|
+
|
|
101
|
+
### `stop(): void`
|
|
102
|
+
|
|
103
|
+
Detiene el watchdog y limpia el timer interno.
|
|
104
|
+
|
|
105
|
+
### `isRunning(): boolean`
|
|
106
|
+
|
|
107
|
+
Retorna `true` si el watchdog está activo.
|
|
108
|
+
|
|
109
|
+
### `listProcesses(): Promise<{ pid: number; name: string }[]>`
|
|
110
|
+
|
|
111
|
+
Retorna la lista de procesos activos en el sistema.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Configuración CLI (`watchdog.conf`)
|
|
116
|
+
|
|
117
|
+
Cuando se usa como CLI, el watchdog lee un archivo `watchdog.conf` en el directorio de instalación:
|
|
118
|
+
|
|
119
|
+
```ini
|
|
120
|
+
# Intervalo entre escaneos (milisegundos)
|
|
121
|
+
INTERVAL_MS=3000
|
|
122
|
+
|
|
123
|
+
# Archivo de log (dejar vacío para desactivar)
|
|
124
|
+
LOG_FILE=watchdog.log
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Compatibilidad
|
|
130
|
+
|
|
131
|
+
| Sistema operativo | Comando para listar | Comando para matar |
|
|
132
|
+
|-------------------|---------------------|--------------------|
|
|
133
|
+
| Windows | `tasklist` | `taskkill /F /PID` |
|
|
134
|
+
| Linux / macOS | `ps` | `kill -9` |
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Licencia
|
|
139
|
+
|
|
140
|
+
ISC — Kevin Javier Reyes
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.loadBlacklist = loadBlacklist;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const normalize_util_1 = require("../utils/normalize.util");
|
|
39
|
+
/**
|
|
40
|
+
* Read the content file at the given path.
|
|
41
|
+
*
|
|
42
|
+
* @param {string} filePath Path of the blacklist file to read.
|
|
43
|
+
* @returns {string[]} List of process names to blacklist.
|
|
44
|
+
*/
|
|
45
|
+
function loadBlacklist(filePath) {
|
|
46
|
+
// Validate if file exists
|
|
47
|
+
if (!fs.existsSync(filePath))
|
|
48
|
+
return [];
|
|
49
|
+
// Read the file and apply:
|
|
50
|
+
// - Trim each line
|
|
51
|
+
// - Ignore empty lines and comments (lines starting with #)
|
|
52
|
+
// - Normalize to lowercase and remove .exe suffix for consistency
|
|
53
|
+
try {
|
|
54
|
+
return fs
|
|
55
|
+
.readFileSync(filePath, "utf8")
|
|
56
|
+
.split("\n")
|
|
57
|
+
.map((l) => l.trim())
|
|
58
|
+
.filter((l) => l && !l.startsWith("#"))
|
|
59
|
+
.map(normalize_util_1.normalizeProcessName);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.killProcess = killProcess;
|
|
37
|
+
exports.listProcesses = listProcesses;
|
|
38
|
+
const child_process_1 = require("child_process");
|
|
39
|
+
const util_1 = require("util");
|
|
40
|
+
const os = __importStar(require("os"));
|
|
41
|
+
const log_util_1 = require("../utils/log.util");
|
|
42
|
+
const normalize_util_1 = require("../utils/normalize.util");
|
|
43
|
+
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
44
|
+
async function killProcess(pid, name, logFile) {
|
|
45
|
+
try {
|
|
46
|
+
if (os.platform() === "win32") {
|
|
47
|
+
await execAsync(`taskkill /F /PID ${pid}`, { timeout: 5000 });
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
await execAsync(`kill -9 ${pid}`, { timeout: 5000 });
|
|
51
|
+
}
|
|
52
|
+
(0, log_util_1.log)(`Killed process: ${name} (PID: ${pid})`, logFile);
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
(0, log_util_1.log)(`Failed to kill ${name} (PID: ${pid}): ${err}`, logFile);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async function listProcesses() {
|
|
59
|
+
try {
|
|
60
|
+
if (os.platform() === "win32") {
|
|
61
|
+
const { stdout } = await execAsync("tasklist /FO CSV /NH", {
|
|
62
|
+
timeout: 5000,
|
|
63
|
+
});
|
|
64
|
+
return stdout
|
|
65
|
+
.trim()
|
|
66
|
+
.split("\n")
|
|
67
|
+
.map((line) => {
|
|
68
|
+
const parts = line.split('","');
|
|
69
|
+
const name = (parts[0] || "").replace(/^"/, "");
|
|
70
|
+
const pid = parseInt(parts[1] || "0", 10);
|
|
71
|
+
return { pid, name: (0, normalize_util_1.normalizeProcessName)(name) };
|
|
72
|
+
})
|
|
73
|
+
.filter((p) => p.pid > 0);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
const { stdout } = await execAsync("ps -eo pid,comm --no-headers", {
|
|
77
|
+
timeout: 5000,
|
|
78
|
+
});
|
|
79
|
+
return stdout
|
|
80
|
+
.trim()
|
|
81
|
+
.split("\n")
|
|
82
|
+
.map((line) => {
|
|
83
|
+
const [pidStr, ...nameParts] = line.trim().split(/\s+/);
|
|
84
|
+
return {
|
|
85
|
+
pid: parseInt(pidStr, 10),
|
|
86
|
+
name: nameParts.join(" ").toLowerCase(),
|
|
87
|
+
};
|
|
88
|
+
})
|
|
89
|
+
.filter((p) => p.pid > 0);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Config } from "../watchdog.types";
|
|
2
|
+
/**
|
|
3
|
+
* Read "watchdog.conf" from the same directory as this script, parse it, and return a Config object.
|
|
4
|
+
* If the config file does not exist or cannot be read, return default values.
|
|
5
|
+
*
|
|
6
|
+
* @returns {Config} Config object with the configuration values
|
|
7
|
+
*/
|
|
8
|
+
export declare function loadConfig(): Config;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.loadConfig = loadConfig;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
/**
|
|
40
|
+
* Read "watchdog.conf" from the same directory as this script, parse it, and return a Config object.
|
|
41
|
+
* If the config file does not exist or cannot be read, return default values.
|
|
42
|
+
*
|
|
43
|
+
* @returns {Config} Config object with the configuration values
|
|
44
|
+
*/
|
|
45
|
+
function loadConfig() {
|
|
46
|
+
// Define default values
|
|
47
|
+
const defaults = {
|
|
48
|
+
INTERVAL_MS: 3000,
|
|
49
|
+
LOG_FILE: "watchdog.log",
|
|
50
|
+
};
|
|
51
|
+
// Determinate and validate the path to the config file
|
|
52
|
+
const configPath = path.join(__dirname, "watchdog.conf");
|
|
53
|
+
if (!fs.existsSync(configPath))
|
|
54
|
+
return defaults;
|
|
55
|
+
// Read and parse the config file
|
|
56
|
+
try {
|
|
57
|
+
const config = { ...defaults };
|
|
58
|
+
// Read the config file content
|
|
59
|
+
const content = fs.readFileSync(configPath, "utf8");
|
|
60
|
+
// Loop Line by line and parse key-value pairs
|
|
61
|
+
for (const line of content.split("\n")) {
|
|
62
|
+
const trimmed = line.trim();
|
|
63
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
64
|
+
continue;
|
|
65
|
+
const eqIdx = trimmed.indexOf("=");
|
|
66
|
+
if (eqIdx === -1)
|
|
67
|
+
continue;
|
|
68
|
+
const key = trimmed.slice(0, eqIdx).trim();
|
|
69
|
+
const value = trimmed.slice(eqIdx + 1).trim();
|
|
70
|
+
if (key === "INTERVAL_MS")
|
|
71
|
+
config.INTERVAL_MS = parseInt(value, 10) || defaults.INTERVAL_MS;
|
|
72
|
+
if (key === "LOG_FILE")
|
|
73
|
+
config.LOG_FILE = value;
|
|
74
|
+
}
|
|
75
|
+
return config;
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return defaults;
|
|
79
|
+
}
|
|
80
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { WatchdogOptions } from "./watchdog.types";
|
|
2
|
+
export declare function start(options: WatchdogOptions): void;
|
|
3
|
+
export declare function stop(): void;
|
|
4
|
+
export declare function isRunning(): boolean;
|
|
5
|
+
export declare const listProcesses: typeof import("./helpers/command.helper").listProcesses;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.listProcesses = void 0;
|
|
7
|
+
exports.start = start;
|
|
8
|
+
exports.stop = stop;
|
|
9
|
+
exports.isRunning = isRunning;
|
|
10
|
+
const watchdog_1 = __importDefault(require("./watchdog"));
|
|
11
|
+
const log_util_1 = require("./utils/log.util");
|
|
12
|
+
let running = false;
|
|
13
|
+
let timer = null;
|
|
14
|
+
let activeOptions = null;
|
|
15
|
+
async function loop() {
|
|
16
|
+
if (!running || !activeOptions)
|
|
17
|
+
return;
|
|
18
|
+
const { blacklistPath, blacklist, intervalMs = 3000, logFile, } = activeOptions;
|
|
19
|
+
await watchdog_1.default.scan(blacklistPath ?? blacklist, {
|
|
20
|
+
INTERVAL_MS: intervalMs,
|
|
21
|
+
LOG_FILE: logFile,
|
|
22
|
+
});
|
|
23
|
+
if (running) {
|
|
24
|
+
timer = setTimeout(loop, intervalMs);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function start(options) {
|
|
28
|
+
if (running)
|
|
29
|
+
return;
|
|
30
|
+
running = true;
|
|
31
|
+
activeOptions = options;
|
|
32
|
+
if (!options.blacklistPath &&
|
|
33
|
+
(!options.blacklist || options.blacklist.length === 0)) {
|
|
34
|
+
(0, log_util_1.log)("No blacklist specified. Use options.blacklistPath or options.blacklist to set it.", options.logFile);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
loop();
|
|
38
|
+
}
|
|
39
|
+
function stop() {
|
|
40
|
+
if (!running)
|
|
41
|
+
return;
|
|
42
|
+
running = false;
|
|
43
|
+
activeOptions = null;
|
|
44
|
+
if (timer) {
|
|
45
|
+
clearTimeout(timer);
|
|
46
|
+
timer = null;
|
|
47
|
+
}
|
|
48
|
+
(0, log_util_1.log)("Process Watchdog stopped");
|
|
49
|
+
}
|
|
50
|
+
function isRunning() {
|
|
51
|
+
return running;
|
|
52
|
+
}
|
|
53
|
+
exports.listProcesses = watchdog_1.default.listProcesses;
|
package/dist/main.d.ts
ADDED
package/dist/main.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const log_util_1 = require("./utils/log.util");
|
|
8
|
+
const config_helper_1 = require("./helpers/config.helper");
|
|
9
|
+
const watchdog_1 = __importDefault(require("./watchdog"));
|
|
10
|
+
const args = process.argv.slice(2);
|
|
11
|
+
const blacklistIndex = args.indexOf("--blacklist");
|
|
12
|
+
const listIndex = args.indexOf("--list");
|
|
13
|
+
const BLACKLIST_FILE = blacklistIndex !== -1 ? args[blacklistIndex + 1] : null;
|
|
14
|
+
(0, log_util_1.log)("Process Watchdog started" +
|
|
15
|
+
(BLACKLIST_FILE ? ` with blacklist file: ${BLACKLIST_FILE}` : ""));
|
|
16
|
+
let running = true;
|
|
17
|
+
let timer;
|
|
18
|
+
async function loop() {
|
|
19
|
+
if (!running)
|
|
20
|
+
return;
|
|
21
|
+
const config = (0, config_helper_1.loadConfig)();
|
|
22
|
+
if (!BLACKLIST_FILE) {
|
|
23
|
+
(0, log_util_1.log)("No blacklist file specified. Use --blacklist <absolutePath> to set it.", config.LOG_FILE);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
console.log("Scanning processes...");
|
|
27
|
+
await watchdog_1.default.scan(BLACKLIST_FILE, config);
|
|
28
|
+
if (running) {
|
|
29
|
+
timer = setTimeout(loop, config.INTERVAL_MS);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (listIndex !== -1) {
|
|
33
|
+
(async () => {
|
|
34
|
+
const processes = await watchdog_1.default.listProcesses();
|
|
35
|
+
console.log("Current running processes:");
|
|
36
|
+
processes.forEach((p) => console.log(`- ${p.name} (PID: ${p.pid})`));
|
|
37
|
+
process.exit(0);
|
|
38
|
+
})();
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
loop();
|
|
42
|
+
}
|
|
43
|
+
process.on("SIGINT", () => {
|
|
44
|
+
running = false;
|
|
45
|
+
clearTimeout(timer);
|
|
46
|
+
(0, log_util_1.log)("Process Watchdog stopped (SIGINT)");
|
|
47
|
+
process.exit(0);
|
|
48
|
+
});
|
|
49
|
+
process.on("SIGTERM", () => {
|
|
50
|
+
running = false;
|
|
51
|
+
clearTimeout(timer);
|
|
52
|
+
(0, log_util_1.log)("Process Watchdog stopped (SIGTERM)");
|
|
53
|
+
process.exit(0);
|
|
54
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function log(message: string, logFile?: string): void;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.log = log;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
function log(message, logFile) {
|
|
39
|
+
const timestamp = new Date().toISOString();
|
|
40
|
+
const msg = `[${timestamp}] ${message}`;
|
|
41
|
+
console.log(msg);
|
|
42
|
+
if (logFile) {
|
|
43
|
+
try {
|
|
44
|
+
fs.appendFileSync(logFile, msg + "\n");
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
/* ignore */
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function normalizeProcessName(name: string): string;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Config } from "./watchdog.types";
|
|
2
|
+
import { listProcesses } from "./helpers/command.helper";
|
|
3
|
+
declare function scan(blacklistPathOrList: string | string[], config: Config): Promise<void>;
|
|
4
|
+
declare const _default: {
|
|
5
|
+
scan: typeof scan;
|
|
6
|
+
listProcesses: typeof listProcesses;
|
|
7
|
+
};
|
|
8
|
+
export default _default;
|
package/dist/watchdog.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const blacklist_helper_1 = require("./helpers/blacklist.helper");
|
|
4
|
+
const command_helper_1 = require("./helpers/command.helper");
|
|
5
|
+
const normalize_util_1 = require("./utils/normalize.util");
|
|
6
|
+
async function scan(blacklistPathOrList, config) {
|
|
7
|
+
const { LOG_FILE } = config;
|
|
8
|
+
// Load blacklist
|
|
9
|
+
const blacklist = typeof blacklistPathOrList === "string"
|
|
10
|
+
? (0, blacklist_helper_1.loadBlacklist)(blacklistPathOrList)
|
|
11
|
+
: blacklistPathOrList;
|
|
12
|
+
if (blacklist.length === 0)
|
|
13
|
+
return;
|
|
14
|
+
// Get current processes
|
|
15
|
+
const processes = await (0, command_helper_1.listProcesses)();
|
|
16
|
+
// Kill blacklisted processes
|
|
17
|
+
for (const proc of processes) {
|
|
18
|
+
const normalizedName = (0, normalize_util_1.normalizeProcessName)(proc.name);
|
|
19
|
+
for (const black of blacklist) {
|
|
20
|
+
if (normalizedName.indexOf(black) !== -1) {
|
|
21
|
+
await (0, command_helper_1.killProcess)(proc.pid, proc.name, LOG_FILE);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.default = {
|
|
27
|
+
scan,
|
|
28
|
+
listProcesses: command_helper_1.listProcesses,
|
|
29
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface Config {
|
|
2
|
+
INTERVAL_MS: number;
|
|
3
|
+
LOG_FILE: string;
|
|
4
|
+
}
|
|
5
|
+
export interface Profile {
|
|
6
|
+
name: string;
|
|
7
|
+
path: string;
|
|
8
|
+
blacklistPath: string;
|
|
9
|
+
hasBlacklist: boolean;
|
|
10
|
+
processCount: number;
|
|
11
|
+
}
|
|
12
|
+
export interface WatchdogOptions {
|
|
13
|
+
blacklistPath?: string;
|
|
14
|
+
blacklist?: string[];
|
|
15
|
+
intervalMs?: number;
|
|
16
|
+
logFile?: string;
|
|
17
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "deepwork-node-watchdog",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A Node.js watchdog for DeepWork.",
|
|
5
|
+
"license": "ISC",
|
|
6
|
+
"author": "Kevin Javier Reyes",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"bin": {
|
|
13
|
+
"deepwork-watchdog": "dist/main.js"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"start": "ts-node main.ts --blacklist blacklist.txt",
|
|
17
|
+
"dev": "ts-node-dev --respawn --transpile-only --ignore-watch node_modules main.ts --blacklist blacklist.txt",
|
|
18
|
+
"list": "ts-node main.ts --list",
|
|
19
|
+
"build": "tsc"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/node": "^20.14.0",
|
|
23
|
+
"ts-node": "^10.9.2",
|
|
24
|
+
"ts-node-dev": "^2.0.0",
|
|
25
|
+
"typescript": "^5.4.0"
|
|
26
|
+
}
|
|
27
|
+
}
|