From a5ddbf0d2e0d5f0109ae4145801dc2070a7508c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beatrice=20Dellac=C3=A0?= Date: Mon, 21 Nov 2022 19:54:49 +0100 Subject: [PATCH] Implement heartbeat for uptime monitoring You can now monitor the bot's uptime via any external tool that supports push heartbeats. The bots sends a GET request every 30 seconds to show that it's online. The URL is hardcoded for the moment, but very easy to change. --- .../wtf/beatrice/hidekobot/Configuration.java | 15 ++++++ .../wtf/beatrice/hidekobot/HidekoBot.java | 18 ++++++- .../hidekobot/runnables/HeartBeatTask.java | 53 +++++++++++++++++++ 3 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 src/main/java/wtf/beatrice/hidekobot/runnables/HeartBeatTask.java diff --git a/src/main/java/wtf/beatrice/hidekobot/Configuration.java b/src/main/java/wtf/beatrice/hidekobot/Configuration.java index 4b9e35f..4239169 100644 --- a/src/main/java/wtf/beatrice/hidekobot/Configuration.java +++ b/src/main/java/wtf/beatrice/hidekobot/Configuration.java @@ -30,6 +30,10 @@ public class Configuration // used to count eg. uptime private static LocalDateTime startupTime; + // todo: allow people to set their own url + private static final String heartbeatLink = "https://status.beatrice.wtf/api/push/%apikey%?status=up&msg=OK&ping="; + private static String heartbeatApiKey = ""; + private static final String botVersion = "0.1.4-slash"; // we should probably find a way to make this consistent with Maven private static final String botName = "HidekoBot"; @@ -211,4 +215,15 @@ public class Configuration */ public static LocalDateTime getStartupTime() { return startupTime; } + public static String getFullHeartBeatLink() { + return heartbeatLink.replace("%apikey%", heartbeatApiKey); + } + //todo javadocs + public static void setHeartBeatApiKey(String key) { + heartbeatApiKey = key; + } + public static String getHeartBeatApiKey() { + return heartbeatApiKey; + } + } diff --git a/src/main/java/wtf/beatrice/hidekobot/HidekoBot.java b/src/main/java/wtf/beatrice/hidekobot/HidekoBot.java index d77bf72..eaf2d0b 100644 --- a/src/main/java/wtf/beatrice/hidekobot/HidekoBot.java +++ b/src/main/java/wtf/beatrice/hidekobot/HidekoBot.java @@ -13,6 +13,7 @@ import wtf.beatrice.hidekobot.listeners.SlashCommandCompleter; import wtf.beatrice.hidekobot.listeners.SlashCommandListener; import wtf.beatrice.hidekobot.runnables.CommandsUpdateTask; import wtf.beatrice.hidekobot.runnables.ExpiredMessageTask; +import wtf.beatrice.hidekobot.runnables.HeartBeatTask; import wtf.beatrice.hidekobot.utils.Logger; import wtf.beatrice.hidekobot.utils.SlashCommandUtil; @@ -79,8 +80,19 @@ public class HidekoBot if(args.length > 1) { List argsList = new ArrayList<>(Arrays.asList(args).subList(1, args.length)); - if(argsList.contains("verbose")) Configuration.setVerbose(true); - if(argsList.contains("refresh")) forceUpdateCommands = true; + for(int i = 0; i < argsList.size(); i++) + { + String arg = argsList.get(i); + + if(arg.equals("verbose")) Configuration.setVerbose(true); + if(arg.equals("refresh")) forceUpdateCommands = true; + if(arg.startsWith("heartbeat=")) + { + String apiKey = arg.replaceAll(".*=", ""); //remove the "heartbeat=" part + Configuration.setHeartBeatApiKey(apiKey); + } + } + } // register listeners @@ -120,6 +132,8 @@ public class HidekoBot scheduler.scheduleAtFixedRate(expiredMessageTask, 5, 5, TimeUnit.SECONDS); //every 5 seconds CommandsUpdateTask commandsUpdateTask = new CommandsUpdateTask(); scheduler.scheduleAtFixedRate(commandsUpdateTask, 10, 300, TimeUnit.SECONDS); //every 5 minutes + HeartBeatTask heartBeatTask = new HeartBeatTask(); + scheduler.scheduleAtFixedRate(heartBeatTask, 10, 30, TimeUnit.SECONDS); //every 30 seconds // register shutdown interrupt signal listener for proper shutdown. Signal.handle(new Signal("INT"), signal -> shutdown()); diff --git a/src/main/java/wtf/beatrice/hidekobot/runnables/HeartBeatTask.java b/src/main/java/wtf/beatrice/hidekobot/runnables/HeartBeatTask.java new file mode 100644 index 0000000..ae6530c --- /dev/null +++ b/src/main/java/wtf/beatrice/hidekobot/runnables/HeartBeatTask.java @@ -0,0 +1,53 @@ +package wtf.beatrice.hidekobot.runnables; + +import wtf.beatrice.hidekobot.Configuration; +import wtf.beatrice.hidekobot.utils.Logger; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; + +public class HeartBeatTask implements Runnable +{ + private final Logger logger; + + public HeartBeatTask() + { + logger = new Logger(getClass()); + } + + + + @Override + public void run() + { + String apiKey = Configuration.getHeartBeatApiKey(); + if(apiKey == null || apiKey.isEmpty()) return; + + String urlString = Configuration.getFullHeartBeatLink(); + try { + + URL heartbeatUrl = new URL(urlString); + + HttpURLConnection connection = (HttpURLConnection) heartbeatUrl.openConnection(); + connection.setRequestMethod("GET"); + connection.setConnectTimeout(5000); + connection.setReadTimeout(5000); + + int responseCode = connection.getResponseCode(); + if(200 <= responseCode && responseCode < 300) + { + // only log ok response codes when verbosity is enabled + if(Configuration.isVerbose()) logger.log("Heartbeat response code: " + responseCode); + } + else + { + logger.log("Heartbeat returned problematic response code: " + responseCode); + } + + } catch (IOException e) { + logger.log("Error while trying to push heartbeat: " + e.getMessage()); + } + + } +}