@daemonitor/plugins 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/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export { PluginConfigProvider } from "./lib/PluginConfigProvider.js";
2
+ export { BasePlugin } from "./lib/BasePlugin.js";
3
+ export { MonitoringPlugin } from "./lib/MonitoringPlugin.js";
4
+ export { PluginLoader } from "./lib/PluginLoader.js";
5
+ export { PluginManager } from "./lib/PluginManager.js";
6
+ export * as Plugins from "./plugins/index.js";
@@ -0,0 +1,17 @@
1
+ import { PluginConfigProvider } from "./PluginConfigProvider.js";
2
+ class BasePlugin {
3
+ static currentPluginIndex = 0;
4
+ alias;
5
+ name;
6
+ description;
7
+ config;
8
+ constructor(alias, name, description) {
9
+ this.config = PluginConfigProvider.get(alias);
10
+ this.name = name;
11
+ this.description = description;
12
+ }
13
+ getName() {
14
+ return this.name;
15
+ }
16
+ }
17
+ export { BasePlugin };
@@ -0,0 +1,24 @@
1
+ import { BasePlugin } from "./BasePlugin.js";
2
+ import { PluginManager } from "@daemonitor/plugins";
3
+ class MonitoringPlugin extends BasePlugin {
4
+ static currentPluginIndex = 0;
5
+ instanceName;
6
+ refreshTimer;
7
+ uniqueId;
8
+ pluginIndex;
9
+ constructor(alias, name, description) {
10
+ super(alias, name, description);
11
+ this.pluginIndex = MonitoringPlugin.currentPluginIndex++;
12
+ this.instanceName = this.config.name || name;
13
+ this.uniqueId = this.config?.uniqueId || this.alias + "-" + this.pluginIndex;
14
+ }
15
+ async send(data, unique_id) {
16
+ for (const apiConnection of PluginManager.API_CONNECTIONS) {
17
+ await apiConnection.sendData({ name: this.instanceName, ...data }, this.name, unique_id || this.uniqueId);
18
+ }
19
+ }
20
+ getName() {
21
+ return this.name;
22
+ }
23
+ }
24
+ export { MonitoringPlugin };
@@ -0,0 +1,10 @@
1
+ class PluginConfigProvider {
2
+ static config = {};
3
+ static async get(key) {
4
+ if (!PluginConfigProvider.config[key]) {
5
+ return null;
6
+ }
7
+ return PluginConfigProvider.config[key];
8
+ }
9
+ }
10
+ export { PluginConfigProvider };
@@ -0,0 +1,13 @@
1
+ import PluginClasses from "../plugins/index.js";
2
+ export class PluginLoader {
3
+ static async loadPlugins() {
4
+ const plugins = [];
5
+ const pluginClasses = PluginClasses;
6
+ for (const file of Object.keys(pluginClasses)) {
7
+ const PluginClass = pluginClasses[file];
8
+ const pluginInstance = new PluginClass();
9
+ plugins.push(pluginInstance);
10
+ }
11
+ return plugins;
12
+ }
13
+ }
@@ -0,0 +1,69 @@
1
+ import { PluginLoader } from "./PluginLoader.js";
2
+ class PluginManager {
3
+ static API_CONNECTIONS = [];
4
+ availablePlugins;
5
+ activePlugins;
6
+ configuredPlugins;
7
+ constructor(configuredPlugins) {
8
+ this.availablePlugins = [];
9
+ this.activePlugins = [];
10
+ this.configuredPlugins = configuredPlugins;
11
+ }
12
+ async initialize() {
13
+ return this.loadPlugins().then(() => this.setupAll());
14
+ }
15
+ async loadPlugins() {
16
+ return await PluginLoader.loadPlugins().then(plugins => {
17
+ if (!plugins) {
18
+ throw new Error("Failed to load plugins.");
19
+ }
20
+ else if (plugins.length === 0) {
21
+ throw new Error("No plugins found.");
22
+ }
23
+ else {
24
+ console.log(`Loaded ${plugins.length} plugins.`);
25
+ }
26
+ this.availablePlugins = plugins;
27
+ });
28
+ }
29
+ async addConnector(apiConnection) {
30
+ PluginManager.API_CONNECTIONS.push(apiConnection);
31
+ }
32
+ async setupAll() {
33
+ console.log("Setting up plugins...");
34
+ // const configuredPlugins = await AppConfigProvider.get("plugins")
35
+ console.log("Configured plugins:", this.configuredPlugins.join(", "));
36
+ if (!this.configuredPlugins)
37
+ throw new Error("No plugins configured. Set up config.json first.");
38
+ this.activePlugins = this.availablePlugins.filter(plugin => {
39
+ return this.configuredPlugins.includes(plugin.getName().toLowerCase());
40
+ });
41
+ if (!this.activePlugins)
42
+ throw new Error("No plugins to set up.");
43
+ for (const plugin of this.activePlugins) {
44
+ await plugin.setup();
45
+ }
46
+ }
47
+ async monitorAll() {
48
+ const results = [];
49
+ if (!this.availablePlugins)
50
+ throw new Error("Plugins not loaded yet! Call loadPlugins() first.");
51
+ if (this.availablePlugins.length === 0)
52
+ throw new Error("No plugins loaded.");
53
+ if (!PluginManager.API_CONNECTIONS || PluginManager.API_CONNECTIONS.length === 0)
54
+ throw new Error("No connections loaded yet! Call addConnector() first.");
55
+ console.log(`Monitoring ${this.activePlugins.length} plugins...`);
56
+ for (const plugin of this.activePlugins) {
57
+ console.log(` + ${plugin.getName()}`);
58
+ const data = plugin.monitor();
59
+ results.push(data);
60
+ }
61
+ return results;
62
+ }
63
+ async teardownAll() {
64
+ for (const plugin of this.activePlugins) {
65
+ await plugin.teardown();
66
+ }
67
+ }
68
+ }
69
+ export { PluginManager };
@@ -0,0 +1,10 @@
1
+ import { EwelinkPlugin } from "./monitoring/EwelinkPlugin.js";
2
+ import { OSPlugin } from "./monitoring/OSPlugin.js";
3
+ import { PM2Plugin } from "./monitoring/PM2Plugin.js";
4
+ import { WebsitePlugin } from "./monitoring/WebsitePlugin.js";
5
+ export default {
6
+ EwelinkPlugin,
7
+ OSPlugin,
8
+ PM2Plugin,
9
+ WebsitePlugin
10
+ };
@@ -0,0 +1,57 @@
1
+ import ewelink from "ewelink-api";
2
+ import * as dotenv from "dotenv";
3
+ import { MonitoringPlugin } from "../../lib/MonitoringPlugin.js";
4
+ dotenv.config();
5
+ export class EwelinkPlugin extends MonitoringPlugin {
6
+ connection;
7
+ devices;
8
+ constructor() {
9
+ super("ewelink", "Ewelink", "Ewelink Addon");
10
+ this.name = "Ewelink";
11
+ this.description = "Ewelink Addon";
12
+ }
13
+ async setup() {
14
+ if (!process.env.EWELINK_EMAIL || !process.env.EWELINK_PASSWORD) {
15
+ console.error("EWELINK_EMAIL and EWELINK_PASSWORD environment variables must be set");
16
+ return Promise.reject();
17
+ }
18
+ this.connection = new ewelink({
19
+ email: process.env.EWELINK_EMAIL,
20
+ password: process.env.EWELINK_PASSWORD
21
+ });
22
+ this.refresh().then(() => { });
23
+ return Promise.resolve();
24
+ }
25
+ async get(key) {
26
+ let [deviceName, propertiesString] = key.split(":");
27
+ deviceName = deviceName.toLowerCase();
28
+ const properties = propertiesString.split(",");
29
+ const device = this.devices?.find((d) => d.name.toLowerCase() === deviceName);
30
+ if (!device) {
31
+ return Promise.reject();
32
+ }
33
+ const values = {};
34
+ for (const property of properties) {
35
+ values[property] = device?.params[property];
36
+ }
37
+ return Promise.resolve(values);
38
+ }
39
+ async refresh() {
40
+ /* get all devices */
41
+ return this.connection.getDevices().then((devices) => {
42
+ this.devices = devices;
43
+ for (const device of this.devices) {
44
+ this.send(device, device.deviceid);
45
+ }
46
+ });
47
+ }
48
+ async monitor() {
49
+ this.refreshTimer = setInterval(this.refresh.bind(this), this.config.refreshInterval || 30000);
50
+ }
51
+ async teardown() {
52
+ clearInterval(this.refreshTimer);
53
+ }
54
+ async render() {
55
+ return this.devices;
56
+ }
57
+ }
@@ -0,0 +1,43 @@
1
+ import { arch, cpus, freemem, hostname, loadavg, networkInterfaces, platform, release, totalmem, type, uptime } from "os";
2
+ import { MonitoringPlugin } from "../../lib/MonitoringPlugin.js";
3
+ export class OSPlugin extends MonitoringPlugin {
4
+ constructor() {
5
+ super("os", "OS", "OS Monitoring Plugin");
6
+ }
7
+ async setup() {
8
+ // no setup required
9
+ return Promise.resolve();
10
+ }
11
+ async refresh() {
12
+ const interfaces = networkInterfaces();
13
+ const addresses = {};
14
+ for (let [key, value] of Object.entries(interfaces)) {
15
+ if (value) {
16
+ let found = value.find(port => (port.family === "IPv4") && (port.internal !== true));
17
+ if (found) {
18
+ let { address, netmask, mac } = found;
19
+ addresses[key] = { address, netmask, mac };
20
+ }
21
+ }
22
+ }
23
+ await this.send({
24
+ addresses,
25
+ totalmem: totalmem(),
26
+ freemem: freemem(),
27
+ loadavg: loadavg(),
28
+ uptime: uptime(),
29
+ hostname: hostname(),
30
+ platform: platform(),
31
+ release: release(),
32
+ type: type(),
33
+ arch: arch(),
34
+ cpus: cpus()
35
+ });
36
+ }
37
+ async monitor() {
38
+ this.refreshTimer = setInterval(this.refresh.bind(this), this.config.refreshInterval || 5000);
39
+ }
40
+ async teardown() {
41
+ clearInterval(this.refreshTimer);
42
+ }
43
+ }
@@ -0,0 +1,80 @@
1
+ import pm2 from "pm2";
2
+ import { MonitoringPlugin } from "../../lib/MonitoringPlugin.js";
3
+ export class PM2Plugin extends MonitoringPlugin {
4
+ constructor() {
5
+ super("pm2", "PM2", "PM2 Monitoring Plugin");
6
+ }
7
+ async setup() {
8
+ return new Promise((resolve, reject) => {
9
+ try {
10
+ pm2.connect(async (err) => {
11
+ if (err) {
12
+ console.error(err);
13
+ reject(err);
14
+ }
15
+ else {
16
+ resolve();
17
+ }
18
+ });
19
+ }
20
+ catch (e) {
21
+ console.error("ERROR", e);
22
+ reject(e);
23
+ }
24
+ });
25
+ }
26
+ async refresh() {
27
+ pm2.list(async (err, list) => {
28
+ if (!err) {
29
+ for (const p of list) {
30
+ let { pid, name, pm_id, monit,
31
+ // exit_code,
32
+ // prev_restart_delay,
33
+ // versioning,
34
+ // axm_dynamic,
35
+ // axm_actions,
36
+ // merge_logs,
37
+ // vizion,
38
+ // instance_var,
39
+ // pmx,
40
+ // automation,
41
+ // treekill,
42
+ // windowsHide,
43
+ // kill_retry_time
44
+ } = p;
45
+ let { username, watch, axm_options, axm_monitor, node_version, unique_id, restart_time, created_at, unstable_restarts, autorestart, status, pm_uptime } = p.pm2_env;
46
+ const payload = {
47
+ updated: (new Date()).getTime(),
48
+ created_at,
49
+ unstable_restarts,
50
+ restarts: restart_time,
51
+ pid,
52
+ name,
53
+ pm_id,
54
+ monit,
55
+ username,
56
+ watch,
57
+ axm_options,
58
+ axm_monitor,
59
+ node_version,
60
+ unique_id,
61
+ restart_time,
62
+ autorestart,
63
+ status,
64
+ pm_uptime,
65
+ };
66
+ await this.send(payload, `${unique_id}-${pm_id}`);
67
+ }
68
+ }
69
+ else {
70
+ console.error(err);
71
+ }
72
+ });
73
+ }
74
+ async monitor() {
75
+ this.refreshTimer = setInterval(this.refresh.bind(this), this.config.refreshInterval || 5000);
76
+ }
77
+ async teardown() {
78
+ clearInterval(this.refreshTimer);
79
+ }
80
+ }
@@ -0,0 +1,46 @@
1
+ import { MonitoringPlugin } from "../../lib/MonitoringPlugin.js";
2
+ export class WebsitePlugin extends MonitoringPlugin {
3
+ constructor() {
4
+ super("website", "Website", "Website Monitoring Plugin");
5
+ }
6
+ async setup() {
7
+ // no setup required
8
+ return Promise.resolve();
9
+ }
10
+ async refresh() {
11
+ const startTimestamp = Date.now();
12
+ const result = await fetch(this.config.url);
13
+ const endTimestamp = Date.now();
14
+ const text = await result.text();
15
+ const status = result.status;
16
+ const headers = result.headers;
17
+ const ok = result.ok;
18
+ const redirected = result.redirected;
19
+ const type = result.type;
20
+ const url = result.url;
21
+ const body = text;
22
+ const duration = endTimestamp - startTimestamp;
23
+ const expectedStrings = this.config.expectedStrings || [];
24
+ const unexpectedStrings = this.config.unexpectedStrings || [];
25
+ const hasAllExpectedStrings = expectedStrings.every(expectedString => body.indexOf(expectedString) !== -1);
26
+ const hasAnyUnexpectedStrings = unexpectedStrings.some(unexpectedString => body.indexOf(unexpectedString) !== -1);
27
+ await this.send({
28
+ status,
29
+ duration,
30
+ headers,
31
+ ok,
32
+ redirected,
33
+ type,
34
+ url,
35
+ body,
36
+ hasAllExpectedStrings,
37
+ hasAnyUnexpectedStrings
38
+ });
39
+ }
40
+ async monitor() {
41
+ this.refreshTimer = setInterval(this.refresh.bind(this), this.config.refreshInterval || 5000);
42
+ }
43
+ async teardown() {
44
+ clearInterval(this.refreshTimer);
45
+ }
46
+ }
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@daemonitor/plugins",
3
+ "version": "1.0.0",
4
+ "description": "daemonitor plugins",
5
+ "types": "types/index.d.ts",
6
+ "main": "dist/index.js",
7
+ "scripts": {
8
+ "test": "echo \"Error: no test specified\" && exit 1"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "types"
13
+ ],
14
+ "type": "module",
15
+ "author": "",
16
+ "license": "ISC",
17
+ "packageManager": "pnpm@8.2.0",
18
+ "dependencies": {
19
+ "dotenv": "^16.0.3",
20
+ "ewelink-api": "^3.1.1",
21
+ "node-machine-id": "^1.1.12",
22
+ "ohmyfetch": "^0.4.21",
23
+ "pm2": "^5.1.0",
24
+ "string-to-color": "^2.2.2",
25
+ "ts-node": "^10.9.1",
26
+ "@daemonitor/common": "file:../common",
27
+ "tsconfig-paths": "^4.2.0"
28
+ },
29
+ "exports": {
30
+ ".": "./dist/index.js",
31
+ "./types": "./dist/types/index.js"
32
+ },
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/daemonitor/plugins.git"
36
+ },
37
+ "bugs": {
38
+ "url": "https://github.com/daemonitor/plugins/issues"
39
+ },
40
+
41
+ "homepage": "https://github.com/daemonitor/plugins#readme"
42
+ }
@@ -0,0 +1,71 @@
1
+ declare module "@daemonitor/plugins" {
2
+ import { IConnector } from "@daemonitor/common"
3
+
4
+ export abstract class PluginConfigProvider {
5
+ static get(alias: string): any
6
+ }
7
+
8
+ export abstract class MonitoringPlugin extends BasePlugin {
9
+ static currentPluginIndex: number
10
+ protected instanceName: string
11
+ protected refreshTimer: any
12
+ protected uniqueId: string
13
+ protected pluginIndex: number
14
+
15
+ protected constructor(alias: string, name: string, description: string)
16
+
17
+ public send(data: any, unique_id?: string): Promise<void>
18
+
19
+ abstract setup(): Promise<void>;
20
+
21
+ abstract monitor(): Promise<any>;
22
+
23
+ abstract refresh(): Promise<void>;
24
+
25
+ abstract teardown(): Promise<void>;
26
+
27
+ getName(): string
28
+ }
29
+
30
+
31
+ export class PluginManager {
32
+
33
+ constructor(configuredPlugins: any)
34
+
35
+ static API_CONNECTIONS: IConnector[]
36
+
37
+ initialize(): Promise<void>
38
+
39
+ loadPlugins(): Promise<void>
40
+
41
+ setupAll(): Promise<void>
42
+
43
+ monitorAll(): Promise<any>
44
+
45
+ addConnector(connector: IConnector): Promise<void>
46
+
47
+ refreshAll(): Promise<void>
48
+
49
+ teardownAll(): Promise<void>
50
+ }
51
+
52
+ export abstract class BasePlugin {
53
+ static currentPluginIndex: number
54
+ protected alias: string
55
+ protected name: string
56
+ protected description: string
57
+ protected config: any
58
+
59
+ protected constructor(alias: string, name: string, description: string)
60
+
61
+ abstract setup(): Promise<void>;
62
+
63
+ abstract monitor(): Promise<any>;
64
+
65
+ abstract refresh(): Promise<void>;
66
+
67
+ abstract teardown(): Promise<void>;
68
+
69
+ getName(): string
70
+ }
71
+ }