diff --git a/RDMMonitor.js b/RDMMonitor.js index 70dbc39..0d18788 100644 --- a/RDMMonitor.js +++ b/RDMMonitor.js @@ -1,9 +1,7 @@ -const Discord=require('discord.js'); -const bot=new Discord.Client(); +const Discord = require('discord.js'); +const bot = new Discord.Client(); const request = require('request'); const config = require('./RDMMonitorConfig.json'); - - const warningImage = "https://raw.githubusercontent.com/chuckleslove/RDMMonitor/master/static/warned.png"; const okImage = "https://raw.githubusercontent.com/chuckleslove/RDMMonitor/master/static/ok.png"; const offlineImage = "https://raw.githubusercontent.com/chuckleslove/RDMMonitor/master/static/offline.png"; @@ -12,28 +10,28 @@ const pokemonImage = "https://raw.githubusercontent.com/chuckleslove/RDMMonitor/ const raidImage = "https://raw.githubusercontent.com/chuckleslove/RDMMonitor/master/static/raids.png"; const researchImage = "https://raw.githubusercontent.com/chuckleslove/RDMMonitor/master/static/research.png"; const ivImage = "https://raw.githubusercontent.com/chuckleslove/RDMMonitor/master/static/iv.png"; - const warningTime = config.warningTime * 60000; const offlineTime = config.offlineTime * 60000; const rebuildTime = config.rebuildTime * 60000; - +const reopenTime = config.reopenTime * 60000; const okColor = 0x008000; const warningColor = 0xFFFF00; const offlineColor = 0xFF0000; - const pokemonColor = 0xC0C0C0; const raidColor = 0x9400D3; const researchColor = 0xFF7F50; const ivColor = 0xDAA520; - const DEVICE_QUERY = 'api/get_data?show_devices=true'; const INSTANCE_QUERY = 'api/get_data?show_instances=true'; const IV_QUERY = '/api/get_data?show_ivqueue=true&formatted=true&instance='; - -const WEBSITE_AUTH = {'auth': {'user':config.websiteLogin, 'password':config.websitePassword}, 'jar':true}; - +const WEBSITE_AUTH = { + 'auth': { + 'user': config.websiteLogin, + 'password': config.websitePassword + }, + 'jar': true +}; var postingDelay = config.postingDelay * 60000; - var devices = {}; var instances = {}; var okDeviceMessage = ""; @@ -44,1102 +42,1061 @@ var channelsCleared = false; Login(); -function Login(){ +function Login() { let version = Discord.version; version = version.split('.'); let primaryVersion = Number(version[0]); - if(primaryVersion < 12) - { - console.log(GetTimestamp()+"FATAL ERROR: discord.js version must be 12.0 or newer, you are using: "+Discord.version); - console.log(GetTimestamp()+"Bot will not continue at this point, please upgrade discord.js, also requires node version 12 or newer"); - + if(primaryVersion < 12) { + console.log(GetTimestamp() + "FATAL ERROR: discord.js version must be 12.0 or newer, you are using: " + Discord.version); + console.log(GetTimestamp() + "Bot will not continue at this point, please upgrade discord.js, also requires node version 12 or newer"); } - else - { - console.log(GetTimestamp()+"Logging in Discord bot token"); + else { + console.log(GetTimestamp() + "Logging in Discord bot token"); bot.login(config.token); } - } - bot.on('message', message => { - switch(message.channel.id){ - case config.channel: - case config.deviceStatusChannel: - case config.instanceStatusChannel: - case config.deviceSummaryChannel: - if(message.content == 'restart'){ RestartBot('manual'); } break; - default: return; + switch (message.channel.id) { + case config.channel: + case config.deviceStatusChannel: + case config.instanceStatusChannel: + case config.deviceSummaryChannel: + if(message.content == 'restart') { + RestartBot('manual'); + } + break; + default: + return; } return; }); bot.on('ready', () => { - - console.log(GetTimestamp()+"Discord bot logged in and ready"); - - if(config.warningTime > 1000 || config.offlineTime > 1000) - { - console.log(GetTimestamp()+"WARNING warningTime and offlineTime should be in MINUTES not milliseconds"); - } - - - if(isNaN(postingDelay)) { postingDelay = 0; } - - - - StartupSequence(); - + console.log(GetTimestamp() + "Discord bot logged in and ready"); + if(config.warningTime > 1000 || config.offlineTime > 1000) { + console.log(GetTimestamp() + "WARNING warningTime and offlineTime should be in MINUTES not milliseconds"); + } + if(isNaN(postingDelay)) { + postingDelay = 0; + } + StartupSequence(); return; - }); -async function StartupSequence() -{ +async function StartupSequence() { await ClearAllChannels(); - await UpdateStatusLoop(); - await PostStatus(); - - return; + await UpdateStatusLoop(); + await PostStatus(); } -async function UpdateStatusLoop() -{ - console.log(GetTimestamp()+"Beginning RDM query"); +async function UpdateStatusLoop() { + console.log(GetTimestamp() + "Beginning RDM query"); await UpdateDevices(); await UpdateInstances(); - console.log(GetTimestamp()+"Finished RDM query"); + console.log(GetTimestamp() + "Finished RDM query"); setTimeout(UpdateStatusLoop, 5000); - return; - } -function UpdateInstances() -{ +function UpdateInstances() { return new Promise(function(resolve) { - request.get(config.url+INSTANCE_QUERY, WEBSITE_AUTH, (err, res, body) => { - - if(err) - { - console.error(GetTimestamp()+"Error querying RDM: "+err.code); - return resolve(); + if(!config.postInstanceStatus) { + return resolve(); + } + request.get(config.url + INSTANCE_QUERY, WEBSITE_AUTH, (err, res, body) => { + if(err) { + console.error(GetTimestamp() + "Error querying RDM: " + err.code); + return resolve(); } - let data; try { data = JSON.parse(body); - } catch(err) { - console.error(GetTimestamp()+"Could not retrieve data from website: "+body); - console.error(GetTimestamp()+err); - return resolve(); } - - if(data.status=="error" || !data.data || !data) - { - console.error(GetTimestamp()+"Could not retrieve data from website: "+data.error); - return resolve(); + catch (err) { + console.error(GetTimestamp() + "Could not retrieve data from website: " + body); + console.error(GetTimestamp() + err); + return resolve(); } - - if(!data.data.instances) - { - console.error(GetTimestamp()+"Failed to retrieve instance data from the website"); - return resolve(); + if(data.status == "error" || !data.data || !data) { + console.error(GetTimestamp() + "Could not retrieve data from website: " + data.error); + return resolve(); + } + if(!data.data.instances) { + console.error(GetTimestamp() + "Failed to retrieve instance data from the website"); + return resolve(); } - data.data.instances.forEach(async function(instance) { - if(!instances[instance.name]) - { + if(!instances[instance.name]) { await AddInstance(instance); - } - else - { - await UpdateInstance(instance); + else { + await UpdateInstance(instance); } - }); - return resolve(); - }); + }); + return resolve(); + }); }); } -async function AddInstance(instance) -{ - if(config.ignoredInstances.length > 0) - { - if(config.ignoredInstances.indexOf(instance.name) != -1) { return } - } - if(!instance.status) { return; } - switch(instance.type) - { +async function AddInstance(instance) { + if(config.ignoredInstances.length > 0) { + if(config.ignoredInstances.indexOf(instance.name) != -1) { + return + } + } + if(!instance.status) { + return; + } + switch (instance.type) { case "Auto Quest": - if(instance.status.bootstrapping) - { - let percent = instance.status.bootstrapping.current_count / instance.status.bootstrapping.total_count; - percent *= 100; - percent = PrecisionRound(percent, 2); - - instances[instance.name] = { - 'name':instance.name, - 'status':'Boostrapping: '+instance.status.bootstrapping.current_count+'/'+instance.status.bootstrapping.total_count+'('+percent+'%)', - 'type':'research' + if(instance.status.bootstrapping) { + let percent = instance.status.bootstrapping.current_count / instance.status.bootstrapping.total_count; + percent *= 100; + percent = PrecisionRound(percent, 2); + instances[instance.name] = { + 'name': instance.name, + 'status': 'Boostrapping: ' + instance.status.bootstrapping.current_count + '/' + instance.status.bootstrapping.total_count + '(' + percent + '%)', + 'type': 'research' + } } - } - else - { - if(!instance.status.quests) { console.log("Your RDM is out of date, please pull the latest from docker"); process.exit(0); return; } - let percent = instance.status.quests.current_count_db / instance.status.quests.total_count; - percent *= 100; - percent = PrecisionRound(percent, 2); - - instances[instance.name] = { - 'name':instance.name, - 'status':instance.status.quests.current_count_db+'/'+instance.status.quests.total_count+'('+percent+'%)', - 'type':'research' + else { + if(!instance.status.quests) { + console.log("Your RDM is out of date, please pull the latest from docker"); + process.exit(0); + return; + } + let percent = instance.status.quests.current_count_db / instance.status.quests.total_count; + percent *= 100; + percent = PrecisionRound(percent, 2); + instances[instance.name] = { + 'name': instance.name, + 'status': instance.status.quests.current_count_db + '/' + instance.status.quests.total_count + '(' + percent + '%)', + 'type': 'research' + } } - } - break; - case "Circle Raid": - if(instance.status) - { - instances[instance.name] = { - 'name':instance.name, - 'status':'Round Time: '+instance.status.round_time+'s', - 'type':'raid' + break; + case "Circle Raid": + if(instance.status) { + instances[instance.name] = { + 'name': instance.name, + 'status': 'Round Time: ' + instance.status.round_time + 's', + 'type': 'raid' + } } - } - else - { - instances[instance.name] = { - 'name':instance.name, - 'status': 'Round Time: N/A', - 'type':'raid' + else { + instances[instance.name] = { + 'name': instance.name, + 'status': 'Round Time: N/A', + 'type': 'raid' + } } - } - break; + break; case "Circle Pokemon": - if(instance.status) - { - instances[instance.name] = { - 'name':instance.name, - 'status':'Round Time: '+instance.status.round_time+'s', - 'type':'pokemon' + if(instance.status) { + instances[instance.name] = { + 'name': instance.name, + 'status': 'Round Time: ' + instance.status.round_time + 's', + 'type': 'pokemon' + } } - } - else - { - instances[instance.name] = { - 'name':instance.name, - 'status': 'Round Time: N/A', - 'type':'pokemon' + else { + instances[instance.name] = { + 'name': instance.name, + 'status': 'Round Time: N/A', + 'type': 'pokemon' + } } - } - break; + break; case "Pokemon IV": - instances[instance.name] = { - 'name':instance.name, - 'status':instance.status.iv_per_hour+' IV/H', - 'type':'iv', - 'queue': await GetIVQueue(instance.name) - - } - break; + instances[instance.name] = { + 'name': instance.name, + 'status': instance.status.iv_per_hour + ' IV/H', + 'type': 'iv', + 'queue': await GetIVQueue(instance.name) + } + break; case "Circle Smart Raid": - instances[instance.name] = { - 'name':instance.name, - 'status':instance.status.scans_per_h+' Scans/H', - 'type':'raid' - } - break; + instances[instance.name] = { + 'name': instance.name, + 'status': instance.status.scans_per_h + ' Scans/H', + 'type': 'raid' + } + break; default: - return; + return; } - return; } -async function UpdateInstance(instance) -{ - if(!instances[instance.name]) - { +async function UpdateInstance(instance) { + if(!instances[instance.name]) { AddInstance(instance); } - else - { - if(!instance.status) { return; } - switch(instance.type) - { - + else { + if(!instance.status) { + return; + } + switch (instance.type) { case "Auto Quest": - if(instance.status.bootstrapping) - { - let percent = instance.status.bootstrapping.current_count / instance.status.bootstrapping.total_count; - percent *= 100; - percent = PrecisionRound(percent, 2); - - instances[instance.name].status = 'Boostrapping: '+instance.status.bootstrapping.current_count+'/'+instance.status.bootstrapping.total_count+'('+percent+'%)'; - - } - else - { - let percent = instance.status.quests.current_count_db / instance.status.quests.total_count; - percent *= 100; - percent = PrecisionRound(percent, 2); - - instances[instance.name].status = instance.status.quests.current_count_db+'/'+instance.status.quests.total_count+'('+percent+'%)'; - - } - break; + if(instance.status.bootstrapping) { + let percent = instance.status.bootstrapping.current_count / instance.status.bootstrapping.total_count; + percent *= 100; + percent = PrecisionRound(percent, 2); + instances[instance.name].status = 'Boostrapping: ' + instance.status.bootstrapping.current_count + '/' + instance.status.bootstrapping.total_count + '(' + percent + '%)'; + } + else { + let percent = instance.status.quests.current_count_db / instance.status.quests.total_count; + percent *= 100; + percent = PrecisionRound(percent, 2); + instances[instance.name].status = instance.status.quests.current_count_db + '/' + instance.status.quests.total_count + '(' + percent + '%)'; + } + break; case "Circle Raid": case "Circle Pokemon": - if(instance.status) - { - instances[instance.name].status = 'Round Time: '+instance.status.round_time+'s'; - - } - else - { - instances[instance.name].status = 'Round Time: N/A'; - - } - break; + if(instance.status) { + instances[instance.name].status = 'Round Time: ' + instance.status.round_time + 's'; + } + else { + instances[instance.name].status = 'Round Time: N/A'; + } + break; case "Pokemon IV": - instances[instance.name].status = instance.status.iv_per_hour+' IV/H'; - instances[instance.name].queue = await GetIVQueue(instance.name); - break; + instances[instance.name].status = instance.status.iv_per_hour + ' IV/H'; + instances[instance.name].queue = await GetIVQueue(instance.name); + break; case "Circle Smart Raid": - instances[instance.name].status = instance.status.scans_per_h+' Scans/H'; - break; - + instances[instance.name].status = instance.status.scans_per_h + ' Scans/H'; + break; + default: + return; } } - return; } -function UpdateDevices() -{ +function UpdateDevices() { return new Promise(function(resolve) { - request.get(config.url+DEVICE_QUERY, WEBSITE_AUTH, (err, res, body) => { - - if(err) - { - console.error(GetTimestamp()+"Error querying RDM: "+err.code); - return resolve(); + if(!config.postIndividualDevices && !config.postDeviceSummary) { + return resolve(true); + } + request.get(config.url + DEVICE_QUERY, WEBSITE_AUTH, (err, res, body) => { + if(err) { + console.error(GetTimestamp() + "Error querying RDM: " + err.code); + return resolve(); } - let data; try { data = JSON.parse(body); - } catch(err) { - console.error(GetTimestamp()+"Could not retrieve data from website: "+body); - console.error(GetTimestamp()+err); - return resolve(); - } - - if(data.status=="error" || !data.data) - { - console.error(GetTimestamp()+"Could not retrieve data from website: "+data.error); - return resolve(); } - - if(!data.data.devices) - { - console.error(GetTimestamp()+"Failed to retrieve device data from the website"); - return resolve(); + catch (err) { + console.error(GetTimestamp() + "Could not retrieve data from website: " + body); + console.error(GetTimestamp() + err); + return resolve(); + } + if(data.status == "error" || !data.data) { + console.error(GetTimestamp() + "Could not retrieve data from website: " + data.error); + return resolve(); + } + if(!data.data.devices) { + console.error(GetTimestamp() + "Failed to retrieve device data from the website"); + return resolve(); } - data.data.devices.forEach(async function(device) { - if(!devices[device.uuid]) - { + if(!devices[device.uuid]) { await AddDevice(device); } - else - { + else { await UpdateDevice(device); } - }); - return resolve(); + }); + return resolve(); }); - - }); + }); } -function AddDevice(device) -{ - if(config.ignoredDevices.length > 0) - { - if(config.ignoredDevices.indexOf(device.uuid) != -1) { return; } +function AddDevice(device) { + if(config.ignoredDevices.length > 0) { + if(config.ignoredDevices.indexOf(device.uuid) != -1) { + return; + } } - devices[device.uuid] = { - "name":device.uuid, + "name": device.uuid, "lastSeen": device.last_seen, "account": device.username, "instance": device.instance, "host": device.host, "alerted": false, - "builds":0 + "rebooted": false, + "reopened": false, + "builds": 0 }; - - if(!devices[device.uuid].lastSeen) { devices[device.uuid].lastSeen = "Never"} - if(!devices[device.uuid].account) { devices[device.uuid].account = "Unknown"} - if(!devices[device.uuid].instance) {devices[device.uuid].instance = "Unassigned"} - if(!devices[device.uuid].host) {devices[device.uuid].host = "Unknown"} - + if(!devices[device.uuid].lastSeen) { + devices[device.uuid].lastSeen = "Never" + } + if(!devices[device.uuid].account) { + devices[device.uuid].account = "Unknown" + } + if(!devices[device.uuid].instance) { + devices[device.uuid].instance = "Unassigned" + } + if(!devices[device.uuid].host) { + devices[device.uuid].host = "Unknown" + } return UpdateDeviceState(devices[device.uuid]); - } -function UpdateDevice(device) -{ - if(!devices[device.uuid]) - { - return AddDevice(device); - } - else - { +function UpdateDevice(device) { + if(!devices[device.uuid]) { + return AddDevice(device); + } + else { devices[device.uuid].lastSeen = device.last_seen; devices[device.uuid].account = device.username; devices[device.uuid].instance = device.instance; - devices[device.uuid].host = device.host; + devices[device.uuid].host = device.host; + } + if(!devices[device.uuid].lastSeen) { + devices[device.uuid].lastSeen = "Never" + } + if(!devices[device.uuid].account) { + devices[device.uuid].account = "Unknown" + } + if(!devices[device.uuid].instance) { + devices[device.uuid].instance = "Unassigned" + } + if(!devices[device.uuid].host) { + devices[device.uuid].host = "Unknown" } - - if(!devices[device.uuid].lastSeen) { devices[device.uuid].lastSeen = "Never"} - if(!devices[device.uuid].account) { devices[device.uuid].account = "Unknown"} - if(!devices[device.uuid].instance) {devices[device.uuid].instance = "Unassigned"} - if(!devices[device.uuid].host) {devices[device.uuid].host = "Unknown"} - return UpdateDeviceState(devices[device.uuid]); - } -async function PostStatus() -{ +async function PostStatus() { await PostDevices(); await PostInstances(); await PostGroupedDevices(); - await SendOfflineDeviceDMs(); - - return; - + await SendOfflineDeviceDMs(); + await ReopenWarnGame(); + await RebootWarnDevice(); } -async function PostDevices() -{ - if(!config.postIndividualDevices) - { - return; - } - else - { - console.log(GetTimestamp()+"Posting device status"); - for(let deviceID in devices) - { - let device = devices[deviceID]; - if(device.message) - { - await EditDevicePost(device); - await sleep(1000); - } - else - { - await PostDevice(device); - await sleep(1000); - } +async function PostDevices() { + if(!config.postIndividualDevices) { + return; + } + console.log(GetTimestamp() + "Posting device status"); + for(let deviceID in devices) { + let device = devices[deviceID]; + if(device.message) { + await EditDevicePost(device); + await sleep(1000); + } + else { + await PostDevice(device); + await sleep(1000); } - - - console.log(GetTimestamp()+"Finished posting device status"); - setTimeout(PostDevices,postingDelay); - return; - } - + } + console.log(GetTimestamp() + "Finished posting device status"); + setTimeout(PostDevices, postingDelay); } -async function PostGroupedDevices() -{ - - return new Promise(async function(resolve) { - if(config.postDeviceSummary) - { - console.log(GetTimestamp()+"Posting device summary"); +async function PostGroupedDevices() { + return new Promise(async function(resolve) { + if(config.postDeviceSummary) { + console.log(GetTimestamp() + "Posting device summary"); let now = new Date(); now = now.getTime(); - let okDevices = []; - let warnDevices = []; + let warnDevices = []; let offlineDevices = []; - - for(let deviceName in devices) - { + for(let deviceName in devices) { let device = devices[deviceName]; let lastSeen = new Date(0); lastSeen.setUTCSeconds(device.lastSeen); lastSeen = lastSeen.getTime(); - lastSeen = now - lastSeen; - if(lastSeen > offlineTime) - { + lastSeen = now - lastSeen; + if(lastSeen > offlineTime) { offlineDevices.push(device.name); } - else if(lastSeen > warningTime) - { + else if(lastSeen > warningTime) { warnDevices.push(device.name); } - else - { + else { okDevices.push(device.name); } } - if(okDevices.length == 0) {okDevices.push("None")} - if(warnDevices.length == 0) {warnDevices.push("None")} - if(offlineDevices.length == 0) {offlineDevices.push("None")} - - - + if(okDevices.length == 0) { + okDevices.push("None") + } + if(warnDevices.length == 0) { + warnDevices.push("None") + } + if(offlineDevices.length == 0) { + offlineDevices.push("None") + } PostDeviceGroup(okDevices, okColor, okImage, 'Working Devices', okDeviceMessage).then(posted => { okDeviceMessage = posted.id; PostDeviceGroup(warnDevices, warningColor, warningImage, 'Warning Devices', warnDeviceMessage).then(posted => { warnDeviceMessage = posted.id; PostDeviceGroup(offlineDevices, offlineColor, offlineImage, 'Offline Devices', offlineDeviceMessage).then(posted => { offlineDeviceMessage = posted.id; - offlineDeviceList = offlineDevices; + offlineDeviceList = offlineDevices; PostLastUpdated(); - console.log(GetTimestamp()+"Finished posting device summary"); + console.log(GetTimestamp() + "Finished posting device summary"); setTimeout(PostGroupedDevices, postingDelay); - return resolve(); + return resolve(); }); }); - }); - + }); + } + else { + return resolve(); } - else - { - return resolve(); - } }); } -function SendOfflineDeviceDMs() -{ +function SendOfflineDeviceDMs() { let now = new Date(); now = now.getTime(); - let offlineDevices = []; - - for(let deviceName in devices) - { + for(let deviceName in devices) { let device = devices[deviceName]; let lastSeen = new Date(0); lastSeen.setUTCSeconds(device.lastSeen); lastSeen = lastSeen.getTime(); - lastSeen = now - lastSeen; - if(lastSeen > offlineTime) - { + lastSeen = now - lastSeen; + if(lastSeen > offlineTime) { offlineDevices.push(device.name); } } - - for(let i = 0; i < offlineDevices.length; i++) - { - if(!devices[offlineDevices[i]].alerted) - { + for(let i = 0; i < offlineDevices.length; i++) { + if(!devices[offlineDevices[i]].alerted) { SendDMAlert(offlineDevices[i]); devices[offlineDevices[i]].alerted = true; } } - - for(let deviceName in devices) - { - if(devices[deviceName].alerted && offlineDevices.indexOf(deviceName) == -1) - { + for(let deviceName in devices) { + if(devices[deviceName].alerted && offlineDevices.indexOf(deviceName) == -1) { devices[deviceName].alerted = false; SendDeviceOnlineAlert(deviceName); } } + setTimeout(SendOfflineDeviceDMs, 60000); +} - setTimeout(SendOfflineDeviceDMs,60000); - return; - +function ReopenWarnGame() { + if(!config.allowReopenGame) { + return; + } + let now = new Date(); + now = now.getTime(); + let reopenDevices = []; + for(var deviceName in devices) { + let device = devices[deviceName]; + let lastSeen = new Date(0); + lastSeen.setUTCSeconds(device.lastSeen); + lastSeen = lastSeen.getTime(); + lastSeen = now - lastSeen; + if(lastSeen > reopenTime) { + if(!config.excludeFromReopen.includes(deviceName)) { + reopenDevices.push(device.name); + } + } + } + for(var i = 0; i < reopenDevices.length; i++) { + if(!devices[reopenDevices[i]].reopened) { + for(var ii = 0; ii < config.reopenMonitorURL.length; ii++) { + const options = { + url: config.reopenMonitorURL[ii], + json: true, + method: 'POST', + body: { + 'type': 'reopen', + 'device': devices[reopenDevices[i]].name + }, + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + }; + console.info(GetTimestamp() + `Sending reopen game request for ${devices[reopenDevices[i]].name} to remote listener ${config.reopenMonitorURL[ii]}`); + request(options, (err, res, body) => { + if(err) { + console.error(GetTimestamp() + `Failed to send reopen game request to remote listener for ${options.body.device}`); + } + }); + devices[reopenDevices[i]].reopened = true; + } + } + } + for(var deviceName in devices) { + if(devices[deviceName].reopened && reopenDevices.indexOf(deviceName) == -1) { + devices[deviceName].reopened = false; + console.info(GetTimestamp() + `Device ${devices[deviceName].name} has come back online from reopening the game`); + } + } + setTimeout(ReopenWarnGame, 60000); } -async function SendDMAlert(device) -{ - for(let i = 0; i < config.userAlerts.length; i++) - { +function RebootWarnDevice() { + if(!config.allowWarnReboots) { + return; + } + let now = new Date(); + now = now.getTime(); + let warnedDevices = []; + for(var deviceName in devices) { + let device = devices[deviceName]; + let lastSeen = new Date(0); + lastSeen.setUTCSeconds(device.lastSeen); + lastSeen = lastSeen.getTime(); + lastSeen = now - lastSeen; + if(lastSeen > warningTime) { + if(!config.excludeFromReboots.includes(deviceName)) { + warnedDevices.push(device.name); + } + } + } + for(var i = 0; i < warnedDevices.length; i++) { + if(!devices[warnedDevices[i]].rebooted) { + for(var ii = 0; ii < config.rebootMonitorURL.length; ii++) { + const options = { + url: config.rebootMonitorURL[ii], + json: true, + method: 'POST', + body: { + 'type': 'restart', + 'device': devices[warnedDevices[i]].name + }, + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + }; + console.info(GetTimestamp() + `Sending reboot request for ${devices[warnedDevices[i]].name} to remote listener ${config.rebootMonitorURL[ii]}`); + request(options, (err, res, body) => { + if(err) { + console.error(GetTimestamp() + `Failed to send reboot request to remote listener for ${options.body.device}`); + } + }); + SendRebootAlert(warnedDevices[i]); + devices[warnedDevices[i]].rebooted = true; + } + } + } + for(var deviceName in devices) { + if(devices[deviceName].rebooted && warnedDevices.indexOf(deviceName) == -1) { + devices[deviceName].rebooted = false; + console.info(GetTimestamp() + `Device ${devices[deviceName].name} has come back online from rebooting the device`); + } + } + setTimeout(RebootWarnDevice, 60000); +} + +async function SendDMAlert(device) { + for(let i = 0; i < config.userAlerts.length; i++) { let user = await bot.users.fetch(config.userAlerts[i]); - if(!user) - { - console.error(GetTimestamp()+"Cannot find a user to DM with ID: "+config.userAlerts[i]); + if(!user) { + console.error(GetTimestamp() + "Cannot find a user to DM with ID: " + config.userAlerts[i]); } - else - { - user.send(GetTimestamp()+" Device: "+device+" is offline!").catch(error => { - console.error(GetTimestamp()+"Failed to send a DM to user: "+user.id); + else { + user.send(GetTimestamp() + " Device: " + device + " is offline!").catch(error => { + console.error(GetTimestamp() + "Failed to send a DM to user: " + user.id); return; }); } } - return; } -async function SendDeviceOnlineAlert(device) -{ - for(let i = 0; i < config.userAlerts.length; i++) - { +async function SendRebootAlert(device) { + if(!config.sendRebootAlerts) { + return; + } + for(var i = 0; i < config.userAlerts.length; i++) { let user = await bot.users.fetch(config.userAlerts[i]); - if(!user) - { - console.error(GetTimestamp()+"Cannot find a user to DM with ID: "+config.userAlerts[i]); + if(!user) { + console.error(GetTimestamp() + "Cannot find a user to DM with ID: " + config.userAlerts[i]); } - else - { - user.send(GetTimestamp()+" Device: "+device+" has come back online").catch(error => { - console.error(GetTimestamp()+"Failed to send a DM to user: "+user.id); + else { + user.send(GetTimestamp() + " Device: " + device + " was sent the reboot command").catch(error => { + console.error(GetTimestamp() + "Failed to send a DM to user: " + user.id); + return; }); } } - return; } +async function SendDeviceOnlineAlert(device) { + for(let i = 0; i < config.userAlerts.length; i++) { + let user = await bot.users.fetch(config.userAlerts[i]); + if(!user) { + console.error(GetTimestamp() + "Cannot find a user to DM with ID: " + config.userAlerts[i]); + } + else { + user.send(GetTimestamp() + " Device: " + device + " has come back online").catch(error => { + console.error(GetTimestamp() + "Failed to send a DM to user: " + user.id); + }); + } + } +} -function PostDeviceGroup(deviceList, color, image, title, messageID) -{ - +function PostDeviceGroup(deviceList, color, image, title, messageID) { return new Promise(async function(resolve) { let channel = config.deviceSummaryChannel ? config.deviceSummaryChannel : config.channel; channel = await bot.channels.fetch(channel); - let deviceString = GetDeviceString(deviceList); - let embed = new Discord.MessageEmbed(); - embed.setTitle(title); embed.setColor(color); embed.setThumbnail(image); embed.setDescription(deviceString); - - if(messageID) - { + if(messageID) { let message = await channel.messages.fetch(messageID); - if(!message) - { - console.error(GetTimestamp()+"Missing device summary message"); - return resolve(); + if(!message) { + console.error(GetTimestamp() + "Missing device summary message"); + return resolve(); } - message.edit({embed: embed}).then(posted => { + message.edit({ + embed: embed + }).then(posted => { return resolve(posted); }).catch(error => { - console.error(GetTimestamp()+"Failed to edit a post: "+error); + console.error(GetTimestamp() + "Failed to edit a post: " + error); return resolve(); }); - ; } - else - { - channel.send({embed: embed}).then(posted => { - return resolve(posted); + else { + channel.send({ + embed: embed + }).then(posted => { + return resolve(posted); }).catch(err => { - console.error(GetTimestamp()+"Error sending a message: "+err); + console.error(GetTimestamp() + "Error sending a message: " + err); return resolve(); }); - } + } }); } -function GetDeviceString(deviceList) -{ - +function GetDeviceString(deviceList) { let currentString = ""; - - for(let i = 0; i < deviceList.length; i++) - { - if(currentString.length + deviceList[i].length + 2 > 2000) - { + for(let i = 0; i < deviceList.length; i++) { + if(currentString.length + deviceList[i].length + 2 > 2000) { return currentString + "and more..."; } - if(i == deviceList.length - 1) - { + if(i == deviceList.length - 1) { currentString = currentString + deviceList[i]; } - else - { + else { currentString = currentString + deviceList[i] + ", "; } } - - return currentString; } -async function PostInstances() -{ - - if(!config.postInstanceStatus) - { - return; - } - else - { - console.log(GetTimestamp()+"Posting instance status"); - let posts = []; - for(let instanceName in instances) - { - let instance = instances[instanceName]; - if(instance.message) - { - await EditInstancePost(instance); - await sleep(1000); - } - else - { - await PostInstance(instance); - await sleep(1000); - } +async function PostInstances() { + if(!config.postInstanceStatus) { + return; + } + console.log(GetTimestamp() + "Posting instance status"); + let posts = []; + for(let instanceName in instances) { + let instance = instances[instanceName]; + if(instance.message) { + await EditInstancePost(instance); + await sleep(1000); } - - console.log(GetTimestamp()+"Finished posting instance status"); - setTimeout(PostInstances,postingDelay); - return; - - } - + else { + await PostInstance(instance); + await sleep(1000); + } + } + console.log(GetTimestamp() + "Finished posting instance status"); + setTimeout(PostInstances, postingDelay); } - -async function PostLastUpdated() -{ - +async function PostLastUpdated() { let channel = config.deviceSummaryChannel ? config.deviceSummaryChannel : config.channel; channel = await bot.channels.fetch(channel); let now = new Date(); - let lastUpdated = "Last Updated at: **"+now.toLocaleString()+"**"; - - if(lastUpdatedMessage) - { + let lastUpdated = "Last Updated at: **" + now.toLocaleString() + "**"; + if(lastUpdatedMessage) { let message = await channel.messages.fetch(lastUpdatedMessage); - if(!message) - { - return; + if(!message) { + return; } message.edit(lastUpdated).then(edited => { lastUpdatedMessage = edited.id; - return; + return; }).catch(error => { - console.log(GetTimestamp()+"Failed to edit a post: "+error); + console.log(GetTimestamp() + "Failed to edit a post: " + error); return; - }); + }); } - else - { + else { channel.send(lastUpdated).then(message => { lastUpdatedMessage = message.id; - return; + return; }).catch(err => { - console.error(GetTimestamp()+"Error sending a message: "+err); + console.error(GetTimestamp() + "Error sending a message: " + err); return; }); - } - + } } -function PostInstance(instance) -{ +function PostInstance(instance) { return new Promise(async function(resolve) { let channel = config.instanceStatusChannel ? config.instanceStatusChannel : config.channel; channel = await bot.channels.fetch(channel); - let embed = BuildInstanceEmbed(instance); - let message = await channel.send({'embed': embed}); + let embed = BuildInstanceEmbed(instance); + let message = await channel.send({ + 'embed': embed + }); instance.message = message.id; return resolve(true); - }); } -function EditInstancePost(instance) -{ +function EditInstancePost(instance) { return new Promise(async function(resolve) { let channel = config.instanceStatusChannel ? config.instanceStatusChannel : config.channel; channel = await bot.channels.fetch(channel); let message = await channel.messages.fetch(instance.message); - if(!message) - { - console.error(GetTimestamp()+"Missing instance message"); - return resolve(); - } + if(!message) { + console.error(GetTimestamp() + "Missing instance message"); + return resolve(); + } let embed = BuildInstanceEmbed(instance); - message.edit({'embed': embed}).then(edited => { - return resolve(); + message.edit({ + 'embed': embed + }).then(edited => { + return resolve(); }).catch((error) => { - console.error(GetTimestamp()+"Failed to edit an instance message: "+error); + console.error(GetTimestamp() + "Failed to edit an instance message: " + error); return resolve(); }); - }); - + }); } -function EditDevicePost(device) -{ +function EditDevicePost(device) { return new Promise(async function(resolve) { - let channel = config.deviceStatusChannel ? config.deviceStatusChannel :config.channel; + let channel = config.deviceStatusChannel ? config.deviceStatusChannel : config.channel; channel = await bot.channels.fetch(channel); let message = await channel.messages.fetch(device.message); - if(!message) - { - console.error(GetTimestamp()+"Missing device message"); - return resolve(); - } + if(!message) { + console.error(GetTimestamp() + "Missing device message"); + return resolve(); + } let embed = BuildDeviceEmbed(device); - message.edit({'embed': embed}).then(edited => { - return resolve(); + message.edit({ + 'embed': embed + }).then(edited => { + return resolve(); }).catch((error) => { - console.error(GetTimestamp()+"Failed to edit a device post: "+error); + console.error(GetTimestamp() + "Failed to edit a device post: " + error); return resolve(); }); - }); } -function PostDevice(device) -{ - return new Promise(async function(resolve){ +function PostDevice(device) { + return new Promise(async function(resolve) { let channel = config.deviceStatusChannel ? config.deviceStatusChannel : config.channel; channel = await bot.channels.fetch(channel); let message = BuildDeviceEmbed(device); - let sent = await channel.send({embed:message}); + let sent = await channel.send({ + embed: message + }); device.message = sent.id; - return resolve(); + return resolve(); }); } -function BuildInstanceEmbed(instance) -{ +function BuildInstanceEmbed(instance) { let embed = new Discord.MessageEmbed(); let deviceList = GetDeviceList(instance); - - let color = 0x0000FF; - + let color = 0x0000FF; let now = new Date(); - let image = instanceImage; - - switch(instance.type) - { + switch (instance.type) { case 'research': - image = researchImage; - color = researchColor; - break; + image = researchImage; + color = researchColor; + break; case 'pokemon': - image = pokemonImage; - color = pokemonColor; - break; + image = pokemonImage; + color = pokemonColor; + break; case 'raid': - image = raidImage; - color = raidColor; - break; + image = raidImage; + color = raidColor; + break; case 'iv': - image = ivImage; - color = ivColor; - break; + image = ivImage; + color = ivColor; + break; default: - break; + break; } - let instanceDevices = ""; - if(deviceList.devices.length > 0) - { + if(deviceList.devices.length > 0) { instanceDevices = deviceList.devices.toString(); } - else - { + else { instanceDevices = "None"; } - - embed.addField('Status',instance.status,true); - embed.addField('Device Count: ',deviceList.count,true); - embed.addField('Deivce List: ',instanceDevices,true); - - - if(instance.type == 'iv' && instance.queue) - { + embed.addField('Status', instance.status, true); + embed.addField('Device Count: ', deviceList.count, true); + embed.addField('Deivce List: ', instanceDevices, true); + if(instance.type == 'iv' && instance.queue) { embed.addField('Queue', instance.queue, true); - } + } embed.setTitle(instance.name); embed.setColor(color); embed.setThumbnail(image); - embed.setFooter('Last Updated: '+now.toLocaleString()); - + embed.setFooter('Last Updated: ' + now.toLocaleString()); return embed; } -function BuildDeviceEmbed(device) -{ +function BuildDeviceEmbed(device) { let embed = new Discord.MessageEmbed(); - - let color = okColor; let image = okImage; - let now = new Date(); now = now.getTime(); - - if(config.showLastSeen) - { - + if(config.showLastSeen) { let lastSeen = new Date(0); lastSeen.setUTCSeconds(device.lastSeen); - embed.addField('Last Seen: ',lastSeen.toLocaleString(),true); - + embed.addField('Last Seen: ', lastSeen.toLocaleString(), true); let lastSeenDifference = now - lastSeen.getTime(); - if(lastSeenDifference > warningTime) - { + if(lastSeenDifference > warningTime) { color = warningColor; image = warningImage; } - if(lastSeenDifference > offlineTime) - { + if(lastSeenDifference > offlineTime) { color = offlineColor; image = offlineImage; } } - if(config.showInstance) - { - embed.addField('Instance',device.instance,true); + if(config.showInstance) { + embed.addField('Instance', device.instance, true); } - if(config.showAccount) - { - embed.addField('Account',device.account,true); + if(config.showAccount) { + embed.addField('Account', device.account, true); } - if(config.showHost) - { - embed.addField('Host',device.host,true); + if(config.showHost) { + embed.addField('Host', device.host, true); } - if(config.showBuildCount) - { - embed.addField('Build Count',device.builds,true); + if(config.showBuildCount) { + embed.addField('Build Count', device.builds, true); } - if(config.showOnlineTime) - { + if(config.showOnlineTime) { let currentUptime = 0; - if(device.state=="ok") - { + if(device.state == "ok") { currentUptime = (now - device.lastBuildTimestamp) / 1000; } - - embed.addField('Current Uptime',currentUptime+'s',true); - embed.addField('Last Build',device.lastBuild,true); - } - - - + embed.addField('Current Uptime', currentUptime + 's', true); + embed.addField('Last Build', device.lastBuild, true); + } embed.setColor(color); embed.setThumbnail(image); embed.setTitle(device.name); - embed.setFooter('Last Updated: '+new Date().toLocaleString()); - + embed.setFooter('Last Updated: ' + new Date().toLocaleString()); return embed; } -function ClearAllChannels() -{ - +function ClearAllChannels() { return new Promise(function(resolve) { - if(!config.clearMessagesOnStartup || channelsCleared) { return resolve(); } - + if(!config.clearMessagesOnStartup || channelsCleared) { + return resolve(); + } let cleared = []; - - if(config.channel) { cleared.push(ClearMessages(config.channel)); console.log(GetTimestamp()+"Clearing channel ID: "+config.channel); } - if(config.deviceStatusChannel) { cleared.push(ClearMessages(config.deviceStatusChannel)); console.log(GetTimestamp()+"Clearing channel ID: "+config.deviceStatusChannel); } - if(config.instanceStatusChannel) { cleared.push(ClearMessages(config.instanceStatusChannel)); console.log(GetTimestamp()+"Clearing channel ID: "+config.instanceStatusChannel); } - if(config.deviceSummaryChannel) { cleared.push(ClearMessages(config.deviceSummaryChannel)); console.log(GetTimestamp()+"Clearing channel ID: "+config.deviceSummaryChannel); } - + if(config.channel) { + cleared.push(ClearMessages(config.channel)); + console.log(GetTimestamp() + "Clearing channel ID: " + config.channel); + } + if(config.deviceStatusChannel) { + cleared.push(ClearMessages(config.deviceStatusChannel)); + console.log(GetTimestamp() + "Clearing channel ID: " + config.deviceStatusChannel); + } + if(config.instanceStatusChannel) { + cleared.push(ClearMessages(config.instanceStatusChannel)); + console.log(GetTimestamp() + "Clearing channel ID: " + config.instanceStatusChannel); + } + if(config.deviceSummaryChannel) { + cleared.push(ClearMessages(config.deviceSummaryChannel)); + console.log(GetTimestamp() + "Clearing channel ID: " + config.deviceSummaryChannel); + } Promise.all(cleared).then(done => { channelsCleared = true; - console.log(GetTimestamp()+"All channels cleared"); - return resolve(); + console.log(GetTimestamp() + "All channels cleared"); + return resolve(); }); - }); } -function ClearMessages(channelID) -{ +function ClearMessages(channelID) { return new Promise(async function(resolve) { - - if(channelsCleared) { return resolve(); } + if(channelsCleared) { + return resolve(); + } let channel = await bot.channels.fetch(channelID); - if(!channel) { console.error(GetTimestamp()+"Could not find a channel with ID: "+channelID); return resolve(); } - let messages = await channel.bulkDelete(100,true); - if(messages.size > 0) - { + if(!channel) { + console.error(GetTimestamp() + "Could not find a channel with ID: " + channelID); + return resolve(); + } + let messages = await channel.bulkDelete(100, true); + if(messages.size > 0) { await ClearMessages(channelID); - return resolve(true); + return resolve(true); + } + else { + console.log("Finished clearing channel ID: " + channelID); + return resolve(true); } - else - { - console.log("Finished clearing channel ID: "+channelID); - return resolve(true); - } }); } -function GetDeviceList(instance) -{ +function GetDeviceList(instance) { let count = 0; let deviceList = []; - - for(let deviceID in devices) - { + for(let deviceID in devices) { let device = devices[deviceID]; - if(device.instance===instance.name) { count++; deviceList.push(deviceID); } + if(device.instance === instance.name) { + count++; + deviceList.push(deviceID); + } } - - return {'count':count, 'devices':deviceList }; + return { + 'count': count, + 'devices': deviceList + }; } -function UpdateDeviceState(device) -{ +function UpdateDeviceState(device) { let now = new Date().getTime(); let lastSeen = new Date(0); lastSeen.setUTCSeconds(device.lastSeen); lastSeen = lastSeen.getTime(); lastSeen = now - lastSeen; - let deviceState = "ok"; - if(lastSeen > rebuildTime) {deviceState = "warn"} - if(lastSeen > offlineTime) {deviceState = "offline"} - - - if(!device.state) - { + if(lastSeen > rebuildTime) { + deviceState = "warn" + } + if(lastSeen > offlineTime) { + deviceState = "offline" + } + if(!device.state) { device.state = deviceState; - if(deviceState=="ok") - { + if(deviceState == "ok") { device.lastBuild = "Before Bot startup"; device.lastBuildTimestamp = new Date().getTime(); } - else - { + else { device.lastBuild = "Never"; device.lastBuildTimestamp = null; } } - else if(device.state == deviceState) - { + else if(device.state == deviceState) { return; } - else - { + else { device.state = deviceState; - switch(deviceState) - { + switch (deviceState) { case "ok": - device.lastBuild = new Date().toLocaleString(); - device.lastBuildTimestamp = new Date().getTime(); - break; + device.lastBuild = new Date().toLocaleString(); + device.lastBuildTimestamp = new Date().getTime(); + break; case "warn": - device.builds++; - break; + device.builds++; + break; case "offline": - break; + break; default: - break; + break; } } - return; } -function PrecisionRound(number, precision) -{ - let factor = Math.pow(10, precision); - return Math.round(number * factor) / factor; +function PrecisionRound(number, precision) { + let factor = Math.pow(10, precision); + return Math.round(number * factor) / factor; } -function GetTimestamp() -{ +function GetTimestamp() { let now = new Date(); - - return "["+now.toLocaleString()+"]"; + return "[" + now.toLocaleString() + "]"; } -function RestartBot(type) -{ - if(type == 'manual'){ process.exit(1); } - else{ - console.error(GetTimestamp()+"Unexpected error, bot stopping, likely websocket"); +async function RestartBot(type) { + if(type == 'manual') { + process.exit(1); + } + else { + console.error(GetTimestamp() + "Unexpected error, bot stopping, likely websocket"); + await sleep(60000); process.exit(1); } - return; } -bot.on('error', function(err) { - if(typeof err == 'object') - { +bot.on('error', function(err) { + if(typeof err == 'object') { err = JSON.stringify(err); } - console.error(GetTimestamp()+'Uncaught exception: '+err); + console.error(GetTimestamp() + 'Uncaught exception: ' + err); RestartBot(); return; }); -process.on('uncaughtException', function(err) { - if(typeof err == 'object') - { +process.on('uncaughtException', function(err) { + if(typeof err == 'object') { err = JSON.stringify(err); } - console.error(GetTimestamp()+'Uncaught exception: '+err); + console.error(GetTimestamp() + 'Uncaught exception: ' + err); RestartBot(); return; }); -process.on('unhandledRejection', function(err) { - if(typeof err == 'object') - { +process.on('unhandledRejection', function(err) { + if(typeof err == 'object') { err = JSON.stringify(err); - } - console.error(GetTimestamp()+'Uncaught exception: '+err); + } + console.error(GetTimestamp() + 'Uncaught exception: ' + err); RestartBot(); return; }); bot.on('disconnect', function(closed) { - console.error(GetTimestamp()+'Disconnected from Discord'); - return; + console.error(GetTimestamp() + 'Disconnected from Discord'); + return; }); -function sleep(ms) -{ +function sleep(ms) { return new Promise(resolve => { - setTimeout(resolve,ms); + setTimeout(resolve, ms); }); } -function GetIVQueue(instanceName) -{ +function GetIVQueue(instanceName) { let queueLimit = config.queueLimit ? config.queueLimit : 5; - return new Promise(function(resolve) { - if(config.queueLimit == 0) { return resolve(''); } - - if(config.ignoredInstances.indexOf(instanceName) == -1) { return resolve(''); } - - request.get(config.url+IV_QUERY+instanceName, WEBSITE_AUTH, (err, res, body) => { - - + if(config.queueLimit == 0) { + return resolve(''); + } + if(config.ignoredInstances.indexOf(instanceName) == -1) { + return resolve(''); + } + request.get(config.url + IV_QUERY + instanceName, WEBSITE_AUTH, (err, res, body) => { let queue = ''; - if(err) - { - console.error(GetTimestamp()+"Error querying RDM: "+err.code); - return resolve(); + if(err) { + console.error(GetTimestamp() + "Error querying RDM: " + err.code); + return resolve(); } - let data = JSON.parse(body).data; - - - for(let i = 0; i < data.ivqueue.length; i++) - { - queue += "Pokemon: **"+data.ivqueue[i].pokemon_name+"** Location: **"+data.ivqueue[i].location+"**\n"; - if(i >= queueLimit - 1) { i = data.ivqueue.length; } + for(let i = 0; i < data.ivqueue.length; i++) { + queue += "Pokemon: **" + data.ivqueue[i].pokemon_name + "** Location: **" + data.ivqueue[i].location + "**\n"; + if(i >= queueLimit - 1) { + i = data.ivqueue.length; + } } - return resolve(queue); }); }); diff --git a/RDMMonitorConfig.example.json b/RDMMonitorConfig.example.json index dcdb7ef..1dfb0ef 100644 --- a/RDMMonitorConfig.example.json +++ b/RDMMonitorConfig.example.json @@ -13,26 +13,36 @@ "websitePassword": "password", "postIndividualDevices":true, - "postInstanceStatus":true, + "postInstanceStatus":true, "postDeviceSummary":true, "showInstance": true, "showAccount": true, "showHost": true, - "showLastSeen": true, + "showLastSeen": true, "showBuildCount": true, "showOnlineTime": true, - "clearMessagesOnStartup": true, - + "clearMessagesOnStartup": true, + "ignoredDevices": [], "ignoredInstances": [], "postingDelay":1, - "warningTime": 1, + "warningTime": 10, "offlineTime": 15, "rebuildTime": 0.25, - - "queueLimit": 5 + + "queueLimit": 5, + + "allowReopenGame": true, + "reopenTime": 5, + "reopenMonitorURL": ["http://192.168.0.1:6542","http://192.168.0.1:6543"], + "excludeFromReopen": ["Device01","Device02"], + + "allowWarnReboots": true, + "rebootMonitorURL": ["http://192.168.0.1:6542","http://192.168.0.1:6543"], + "sendRebootAlerts": false, + "excludeFromReboots": ["Device01","Device02"] } \ No newline at end of file diff --git a/README.md b/README.md index 45141cc..1c95e07 100644 --- a/README.md +++ b/README.md @@ -12,28 +12,49 @@ Simple Discord Bot to monitor device status for RDM Config options token: Mandator, discord bot token, bot should have send message and manage message permissions in the designated channel -channel: channel ID of where to post device/instance status -userAlerts: an array of user IDs to DM upon device going offline +channel: Default channel ID of where to post device/instance status +deviceStatusChannel: Specific channel ID of where to post device status +instanceStatusChannel: Specific channel ID of where to post instance status +deviceSummaryChannel: Specific channel ID of where to post the device summary -url: url of your RDM website, by default IP:9000 but can use actual URL if you have a properly configured reverse proxy -websiteLogin: username to login with -websitePassword: password for the username +userAlerts: an array of user IDs to DM upon device going offline +The tt +url: URL of your RDM website, by default IP:9000 but can use actual URL if you have a properly configured reverse proxy +websiteLogin: Username to login with +websitePassword: Password for the username The above user must have admin access to the website -postIndividualDevices:true/false - bool to post each device individually -postInstanceStatus:true/false - bool to post instance status -postDeviceSummary:true/false - bool to post device status in a single block by current status +postIndividualDevices: true/false - Bool to post each device individually +postInstanceStatus: true/false - Bool to post instance status +postDeviceSummary: true/false - Bool to post device status in a single block by current status + +showInstance: Show which instance a device is assigned to on the indThe ttividual device post +showAccount: Show account assigned on device post +showHost: Show host IP for the device +showLastSeen: Show when the device was last seen +showBuildCount: Show the amount of times a device rebuilt +showOnlineTime: Show how long the deviceThe ttThe ttThe tt has been online + +clearMessagesOnStartup: Will delete all messages in the channel it is going to post to, this is to clear out posts from past history, DO NOT set this to true if you don't have a dedicated channel for device status as this will wipe out the channel + +ignoredDevices: An array of strings for the overall device blacklist +ignoredInstances: An array of strings for the instance blacklist -showInstance - show which instance a device is assigned to on the individual device post -showAccount - show account assigned on device post -showHost - show host IP for the device -showLastSeen - show when the device was last seen +pollingDelay: Delay in minutes in between checking device/instance status. A value of 0 would check immediately after it finishes checking/posting status, .5 would be 30 seconds, 1 would be 60 seconds, etc... -clearMessagesOnStartup - will delete all messages in the channel it is going to post to, this is to clear out posts from past history, DO NOT set this to true if you don't have a dedicated channel for device status as this will wipe out the channel +warningTime: The time in minutes to consider a device in warning state +offlineTime: The time in minutes a device must be offline before marked as red/offline and send a DM to the designated users +rebuildTime: The time in minutes to consider a device is rebuilding -pollingDelay - delay in minutes in between checking device/instance status. A value of 0 would check immediately after it finishes checking/posting status, .5 would be 30 seconds, 1 would be 60 seconds, etc... +queueLimit: A number for the IV queue limit -warningTime - the time in minutes to consider a device in warning state +allowReopenGame: true/false - Bool to enable RDMDeviceMonitor to send a reopen game request to a monitor +reopenTime: The time in minutes to request a device to reopen the game +reopenMonitorURL: An array of strings for the URLs of the reopen game monitors you are using like iPhone Controller or DCM Listener +excludeFromReopen: An array of strings that are the unique names of the devices to exclude from the reopen game request -offlineTime - the time in minutes a device must be offline before marked as red/offline and send a DM to the designated users +allowWarnReboots: true/false - Bool to enable RDMDeviceMonitor to send a reboot request to a monitor +rebootMonitorURL: An array of strings for the URLs of the reboot monitors you are using like iPhone Controller or DCM Listener +sendRebootAlerts: true/false - Bool to enable the DM message for rebooting a device +excludeFromReboots: An array of strings that are the unique names of the devices to exclude from the reboot request