-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.mjs
109 lines (99 loc) · 4.93 KB
/
index.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import { cloudLogin, listDevicesByType, loginDevice, turnOff, turnOn } from 'tp-link-tapo-connect';
import { config } from 'dotenv';
import { check } from 'tcp-port-used';
import { Webhook } from 'webhook-discord';
import { wake } from 'wol';
config();
// App status, used for graceful shutdowns
let app_busy = false;
// Discord webhook name
const webhook_name = 'Offline Server Auto Restart';
// Verify that process.env.CHECK_OPEN_PORT is a valid port
if (isNaN(Number(process.env.CHECK_OPEN_PORT))) {
console.error(`CHECK_OPEN_PORT must be a valid port number. You provided ${process.env.CHECK_OPEN_PORT}`);
process.exit(1);
}
const port_to_check = Number(process.env.CHECK_OPEN_PORT);
// Setup Discord webhook
let Hook = false;
if (process.env.DISCORD_WEBHOOK_URL) {
console.log(`Discord webhook URL provided, will send notifications to Discord`);
Hook = new Webhook(process.env.DISCORD_WEBHOOK_URL);
Hook.success(webhook_name, `Server monitor started.`);
} else {
console.log(`No Discord webhook URL provided, will not send notifications to Discord`);
}
async function main() {
app_busy = true; // For graceful shutdowns
try {
console.log(`Checking if port ${port_to_check} is open...`)
let port_open = false;
try {
port_open = await check(port_to_check, process.env.SERVER_ADDRESS);
} catch(e) {
// If the port is closed, tcp-port-used throws an error. We don't care about the error, so we're just catching it and ignoring it.
console.log(`Error: ${e} - assuming the server is down.`)
}
console.log(`Port ${port_to_check} is ${port_open ? 'open' : 'closed'}`)
if (port_open) {
console.log(`Server appears to be online, not doing anything.`)
} else {
// Send a warning message to Discord
if (Hook) Hook.warn(webhook_name, `Server appears to be offline, restarting...`);
console.log(`Restarting server...`)
console.log(`Logging in to TP-Link cloud...`);
const cloudToken = await cloudLogin(process.env.TAPO_EMAIL, process.env.TAPO_PASSWORD);
console.log(`Cloud token obtained, looking for device`)
const devices = await listDevicesByType(cloudToken, 'SMART.TAPOPLUG');
console.log(`Found ${devices.length} devices`)
const device = devices.find(device => device.deviceId === process.env.TAPO_DEVICE_ID);
if (!device) return console.error(`Couldn't find your device ID in the list of devices. Please check your TAPO_DEVICE_ID environment variable.`);
console.log(`Getting device token...`);
const deviceToken = await loginDevice(process.env.TAPO_EMAIL, process.env.TAPO_PASSWORD, device);
// Power cycle the device using the smart plug
console.log(`Device token obtained, restarting device...`);
await turnOff(deviceToken);
console.log(`Device turned off, waiting 25 seconds...`);
await new Promise(resolve => setTimeout(resolve, 25 * 1000));
await turnOn(deviceToken);
// Send a success message to Discord
if (Hook) Hook.success(webhook_name, `Server restarted. Please see the logs for details.`);
console.log(`Device turned on!`);
console.log(`Waiting 8 seconds before sending wake-on-lan packet...`);
await new Promise(resolve => setTimeout(resolve, 8 * 1000));
console.log(`Sending wake-on-lan packet...`);
wake(process.env.SERVER_MAC_ADDRESS, (err, res) => {
if (err) {
console.error(`Error sending wake-on-lan packet: ${err}`);
if (Hook) Hook.err(webhook_name, `An error occurred while sending the wake-on-lan packet, please check the logs.`);
}
console.log(`Wake-on-lan packet sent!`);
});
console.log(`Sleeping for 8 minutes to give the server time to start...`);
await new Promise(resolve => setTimeout(resolve, 8 * 60 * 1000));
}
} catch(e) {
if (Hook) Hook.err(webhook_name, `An error occurred while running the script, please check the logs.`);
console.error(`An error occurred: ${e}`);
}
app_busy = false; // We're no longer checking or restarting the server
// Check again in 6 minutes. We're using setTimeout instead of setInterval to avoid race conditions
console.log(`Checking again in 6 minutes.`)
setTimeout(main, 6 * 60 * 1000);
}
process.on('SIGINT', (signal) => {
console.log("Gracefully shutting down");
if (app_busy) {
console.log("App is busy, please wait for it to finish before exiting");
setInterval(() => {
if (!app_busy) {
console.log("App is no longer busy, exiting");
process.exit(0);
}
}, 100);
} else {
console.log("App is not busy, exiting");
process.exit(0);
}
})
main();