1
0
Fork 0
forked from mc/VTools

自动关机增加计时器

This commit is contained in:
Sodium-Aluminate 2023-12-08 17:43:31 +08:00
parent 564e1eb5fa
commit c178415969
2 changed files with 126 additions and 49 deletions

View file

@ -3,7 +3,6 @@ package de.strifel.VTools;
import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.connection.DisconnectEvent; import com.velocitypowered.api.event.connection.DisconnectEvent;
import com.velocitypowered.api.event.player.ServerConnectedEvent; import com.velocitypowered.api.event.player.ServerConnectedEvent;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.proxy.ProxyServer;
import de.strifel.VTools.listeners.TGBridge; import de.strifel.VTools.listeners.TGBridge;
import okhttp3.*; import okhttp3.*;
@ -14,13 +13,13 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
public class ServerCloser { public class ServerCloser {
private static final long INACTIVITY_TIMEOUT_MILLISECOND = 15L * 60 * 1000; // 15 minutes private static final long INACTIVITY_TIMEOUT_MILLISECOND = 15L * 60 * 1000; // 15 minutes
private static final long MINUTE = 60L * 1000; // 15 minutes
private static final OkHttpClient CLIENT = new OkHttpClient(); private static final OkHttpClient CLIENT = new OkHttpClient();
private String apiUrl; private String apiUrl;
@ -67,7 +66,8 @@ public class ServerCloser {
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
httpSuccess = executeAzure(); httpSuccess = executeAzure();
if (httpSuccess) { if (httpSuccess) {
TGBridge.log("关机命令发送成功,正在关闭 pymcd。"); TGBridge.log("ServerCloser: 向azure发送关机命令成功正在关闭 pymcd.");
TGBridge.setShuttingDown(0);
break; break;
} }
} }
@ -76,12 +76,14 @@ public class ServerCloser {
} else { } else {
try { try {
Runtime.getRuntime().exec("pkill pymcd"); Runtime.getRuntime().exec("pkill pymcd");
} catch (IOException ignored) {} } catch (IOException e) {
// plugin.getServer().shutdown(); TGBridge.error("关闭 pymcd 时出现问题:" + e.getMessage());
}
} }
} }
private boolean firstInit; private boolean firstInit;
private int countDown = -1;
public void register() { public void register() {
server.getEventManager().register(plugin, this); server.getEventManager().register(plugin, this);
@ -122,30 +124,62 @@ public class ServerCloser {
} }
private void update() { private void update() {
Collection<Player> players = server.getAllPlayers(); var hasPlayer = !server.getAllPlayers().isEmpty();
if (!players.isEmpty()) { if (hasPlayer) {
plugin.logger.info("ServerCloser: 有玩家在线,干掉任何可能的关机计时器。"); plugin.logger.info("ServerCloser: 有玩家在线,干掉任何可能的关机计时器。");
closeServerTimer.cancel(); closeServerTimer.cancel();
countDown = -1;
TGBridge.setShuttingDown(-1);
return; return;
} }
initCountdown();
}
private void initCountdown() {
countDown = firstInit ? 60 : 15;
firstInit = false;
startCountdown();
}
private void startCountdown() {
TGBridge.setShuttingDown(countDown);
Timer timer = new Timer(); Timer timer = new Timer();
timer.schedule(new TimerTask() { timer.schedule(new TimerTask() {
@Override @Override
@SuppressWarnings("java:S1199")
public void run() { public void run() {
if (server.getAllPlayers().isEmpty()) { {
plugin.logger.info("ServerCloser: 即将关机。"); countDown--;
close(); if (countDown < 0) {
} else { TGBridge.error("ServerCloser: #bug @NaAlOH4 计时器写炸了");
plugin.logger.error("ServerCloser: 定时器到点时发现服务器有人。这不应发生,因为定时器本应该被打断。"); closeServerTimer.cancel();
TGBridge.error("ServerCloser: #bug @NaAlOH4 定时器到点时发现服务器有人。这不应发生,因为定时器本应该被打断。"); return;
} }
closeServerTimer.cancel();
}
}, firstInit ? (4 * INACTIVITY_TIMEOUT_MILLISECOND) : INACTIVITY_TIMEOUT_MILLISECOND);
plugin.logger.info("ServerCloser: 将在 {} 后自动关机。", firstInit ? "1h" : "15min");
firstInit = false; if (server.getAllPlayers().isEmpty()) {
switch (countDown) {
case 1 -> {
TGBridge.log("服务器即将在一分钟后关机");
startCountdown();
}
case 0 -> {
plugin.logger.info("ServerCloser: 距离上一个玩家离开已经过了%s即将关机。".formatted(firstInit ? "一小时" : "15分钟"));
TGBridge.log("ServerCloser: 距离上一个玩家离开已经过了%s即将关机。".formatted(firstInit ? "一小时" : "15分钟"));
close();
closeServerTimer.cancel();
}
default -> startCountdown();
}
} else {
plugin.logger.error("ServerCloser: 定时器到点时发现服务器有人。这不应发生,因为定时器本应该被打断。");
TGBridge.error("ServerCloser: #bug @NaAlOH4 定时器到点时发现服务器有人。这不应发生,因为定时器本应该被打断。");
closeServerTimer.cancel();
}
}
}
}, MINUTE);
plugin.logger.info("ServerCloser: 将在 {} 分钟后自动关机。", countDown);
synchronized (lock) { synchronized (lock) {
closeServerTimer.cancel(); closeServerTimer.cancel();
@ -153,4 +187,5 @@ public class ServerCloser {
} }
} }
} }

View file

@ -1,5 +1,7 @@
package de.strifel.VTools.listeners; package de.strifel.VTools.listeners;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.pengrad.telegrambot.Callback; import com.pengrad.telegrambot.Callback;
import com.pengrad.telegrambot.TelegramBot; import com.pengrad.telegrambot.TelegramBot;
import com.pengrad.telegrambot.UpdatesListener; import com.pengrad.telegrambot.UpdatesListener;
@ -40,6 +42,7 @@ import java.util.stream.Collectors;
public class TGBridge { public class TGBridge {
private final VTools plugin; private final VTools plugin;
private final ProxyServer server; private final ProxyServer server;
@SuppressWarnings("java:S3008")
protected static TGBridge INSTANCE = null; protected static TGBridge INSTANCE = null;
private TelegramBot bot; private TelegramBot bot;
@ -56,7 +59,11 @@ public class TGBridge {
*/ */
private String pinNote; private String pinNote;
@SuppressWarnings("java:S3010")
public TGBridge(@NotNull VTools plugin) { public TGBridge(@NotNull VTools plugin) {
if (INSTANCE != null) {
throw new IllegalStateException();
}
INSTANCE = this; INSTANCE = this;
this.plugin = plugin; this.plugin = plugin;
this.server = plugin.getServer(); this.server = plugin.getServer();
@ -100,11 +107,12 @@ public class TGBridge {
for (Update update : updates) { for (Update update : updates) {
try { try {
if (update == null || update.message() == null) break; if (update == null || update.message() == null) continue;
Message message = update.message(); Message message = update.message();
if (message.chat() == null || message.chat().id() != CHAT_ID || message.from() == null) { if (message.chat() == null || message.chat().id() != CHAT_ID || message.from() == null) continue;
break;
} currentAnnounce.abort();
String text = ""; String text = "";
Message replyTo = message.replyToMessage(); Message replyTo = message.replyToMessage();
if (replyTo != null) { if (replyTo != null) {
@ -117,7 +125,7 @@ public class TGBridge {
if (replyType != null) { if (replyType != null) {
replyText += replyType; replyText += replyType;
if (replyTo.caption() != null) { if (replyTo.caption() != null) {
replyText += " \"" + replyTo.caption()+"\""; replyText += " \"" + replyTo.caption() + "\"";
} }
} }
if (replyText.equals("")) { if (replyText.equals("")) {
@ -141,15 +149,15 @@ public class TGBridge {
usage: usage:
use "/setpin" reply a message that from the bot to set that message to pin-message, use "/setpin" reply a message that from the bot to set that message to pin-message,
or use "/setpin <note>" to update current pinned message."""); or use "/setpin <note>" to update current pinned message.""");
break; continue;
} }
ONLINE_STATUS_MESSAGE_ID = replyTo.messageId(); ONLINE_STATUS_MESSAGE_ID = replyTo.messageId();
updateOnlineStatus(); updateOnlineStatus();
break; continue;
} }
if (replyTo != null && (replyTo.from() == null || replyTo.messageId() <= 0)) { if (replyTo != null && (replyTo.from() == null || replyTo.messageId() <= 0)) {
outbound("must reply a message that from the bot (or reply nothing)."); outbound("must reply a message that from the bot (or reply nothing).");
break; continue;
} }
String markdownString = MarkdownString.markdownString(message); String markdownString = MarkdownString.markdownString(message);
@ -157,7 +165,7 @@ public class TGBridge {
String shouldBeCommand = markdownString.substring(0, "/setpin ".length()); String shouldBeCommand = markdownString.substring(0, "/setpin ".length());
if (!shouldBeCommand.matches("/setpin[\t \n]")) { if (!shouldBeCommand.matches("/setpin[\t \n]")) {
outbound("\"/setpin\" must be plain text."); outbound("\"/setpin\" must be plain text.");
break; continue;
} }
@ -179,6 +187,7 @@ public class TGBridge {
} }
}, ParseMode.MarkdownV2 }, ParseMode.MarkdownV2
); );
default -> {}
} }
} }
text += msgText; text += msgText;
@ -255,17 +264,29 @@ public class TGBridge {
*/ */
private String genPinMessage() { private String genPinMessage() {
return (pinNote != null && pinNote.length() != 0) ? return (pinNote != null && pinNote.length() != 0) ?
genOnlineStatus() + "\n" + DIVIDER + pinNote : genOnlineStatus() + "\n\n" + DIVIDER + pinNote :
genOnlineStatus(); genOnlineStatus();
} }
/** /**
* @return markdown escaped str * @return markdown escaped str
*/ */
private int shutdownCountMinutes = -1;
public static void setShuttingDown(int minute) {
INSTANCE.shutdownCountMinutes = minute;
INSTANCE.updateOnlineStatus();
}
private String genOnlineStatus() { private String genOnlineStatus() {
ArrayList<String> out = new ArrayList<>(); ArrayList<String> out = new ArrayList<>();
String fmt = server.getAllPlayers().size() > 1 ? "%d players are currently connected to the proxy\\." : "%d player is currently connected to the proxy\\."; int playerCount = server.getAllPlayers().size();
out.add(String.format(fmt, server.getAllPlayers().size())); out.add(switch (playerCount) {
case 0 -> "nobody here\\.";
case 1 -> "only one player online\\.";
default -> playerCount + " players online\\.";
});
List<RegisteredServer> registeredServers = new ArrayList<>(server.getAllServers()); List<RegisteredServer> registeredServers = new ArrayList<>(server.getAllServers());
for (RegisteredServer registeredServer : registeredServers) { for (RegisteredServer registeredServer : registeredServers) {
LinkedList<Player> onServer = new LinkedList<>(); LinkedList<Player> onServer = new LinkedList<>();
@ -283,7 +304,10 @@ public class TGBridge {
); );
} }
} }
return String.join("\n", out); String result = String.join("\n", out);
if (shutdownCountMinutes < 0) return result;
if (shutdownCountMinutes == 0) return "server is shutdown\\.%n%s".formatted(result);
return "server will shutdown after %s minute\\.%n%s".formatted(shutdownCountMinutes, result);
} }
protected void tgInbound(User user, String content) { protected void tgInbound(User user, String content) {
@ -310,6 +334,7 @@ public class TGBridge {
public static void error(String context) { public static void error(String context) {
INSTANCE.outbound("*" + MarkdownString.escapeStr(context) + "*", ParseMode.MarkdownV2); INSTANCE.outbound("*" + MarkdownString.escapeStr(context) + "*", ParseMode.MarkdownV2);
} }
public static void log(String context) { public static void log(String context) {
INSTANCE.outbound("_" + MarkdownString.escapeStr(context) + "_", ParseMode.MarkdownV2); INSTANCE.outbound("_" + MarkdownString.escapeStr(context) + "_", ParseMode.MarkdownV2);
} }
@ -353,14 +378,12 @@ public class TGBridge {
@Subscribe @Subscribe
public void onServerConnected(ServerConnectedEvent event) { public void onServerConnected(ServerConnectedEvent event) {
if (event.getPreviousServer().isEmpty()) { if (event.getPreviousServer().isEmpty() && !event.getPlayer().hasPermission("vtools.globalchat.bypassbridge.join")) {
if (!event.getPlayer().hasPermission("vtools.globalchat.bypassbridge.join")) { String username = event.getPlayer().getUsername();
String username = event.getPlayer().getUsername(); if (lastDisconnect.equals(username)) {
if (lastDisconnect.equals(username)) { lastDisconnect = "";
lastDisconnect = "";
}
joinLeftAnnounce(String.format("%s joined the proxy", username));
} }
joinLeftAnnounce(String.format("%s joined the proxy", username));
} }
updateRequests.add(new UpdateRequest()); updateRequests.add(new UpdateRequest());
} }
@ -393,6 +416,7 @@ public class TGBridge {
private LinkedBlockingQueue<UpdateRequest> updateRequests = new LinkedBlockingQueue<>(); private LinkedBlockingQueue<UpdateRequest> updateRequests = new LinkedBlockingQueue<>();
@SuppressWarnings("java:S3776")
private void initUpdateThread() { private void initUpdateThread() {
new Thread(() -> { new Thread(() -> {
while (true) { while (true) {
@ -406,15 +430,14 @@ public class TGBridge {
} catch (InterruptedException ignored) {} } catch (InterruptedException ignored) {}
if (oldestRequest == null) { if (oldestRequest == null) {
plugin.logger.warn("updateRequests.take() return a null value, why?"); plugin.logger.warn("updateRequests.take() return a null value, why?");
try { sleep(1000);
Thread.sleep(1000);
} catch (InterruptedException ignored) {}
continue; continue;
} }
updateRequests.clear(); updateRequests.clear();
if (!updateOnlineStatus()) { if (!updateOnlineStatus()) {
updateRequests.add(oldestRequest); // 更新失败 回去吧您内 updateRequests.add(oldestRequest); // 更新失败 回去吧您内
sleep(1000);
} }
} }
}).start(); }).start();
@ -444,6 +467,12 @@ public class TGBridge {
}).start(); }).start();
} }
private static void sleep(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException ignored) {}
}
protected boolean updateOnlineStatus() { protected boolean updateOnlineStatus() {
return editOnlineStatusMessage(genPinMessage()); return editOnlineStatusMessage(genPinMessage());
} }
@ -452,6 +481,8 @@ public class TGBridge {
return editOnlineStatusMessage("proxy already shutdown"); return editOnlineStatusMessage("proxy already shutdown");
} }
private static final Gson prettyGson = new GsonBuilder().setPrettyPrinting().create();
protected boolean editOnlineStatusMessage(String markdownText) { protected boolean editOnlineStatusMessage(String markdownText) {
if (ONLINE_STATUS_MESSAGE_ID < 1) { if (ONLINE_STATUS_MESSAGE_ID < 1) {
return true; return true;
@ -459,8 +490,16 @@ public class TGBridge {
BaseResponse response; BaseResponse response;
try { try {
response = bot.execute(new EditMessageText(CHAT_ID, ONLINE_STATUS_MESSAGE_ID, markdownText).parseMode(ParseMode.MarkdownV2)); response = bot.execute(new EditMessageText(CHAT_ID, ONLINE_STATUS_MESSAGE_ID, markdownText).parseMode(ParseMode.MarkdownV2));
} catch (RuntimeException e) {return false;} if (!response.isOk()) {
return response != null && response.isOk(); String responseJSON = prettyGson.toJson(response);
plugin.logger.warn("update failed: {}", responseJSON);
}
return response.isOk();
} catch (RuntimeException e) {
e.printStackTrace();
return false;
}
} }
private class JoinLeftAnnounceMessage { private class JoinLeftAnnounceMessage {
@ -468,13 +507,16 @@ public class TGBridge {
private long time; private long time;
private StringBuilder text; private StringBuilder text;
private boolean abort = false;
boolean isValid() { boolean isValid() {
if (messageId < 1) { if (abort || messageId < 1) return false;
return false;
}
long dt = System.currentTimeMillis() - time; long dt = System.currentTimeMillis() - time;
return dt <= 60_000 && dt >= 0; return dt <= 30_000 && dt >= 0;
}
private void abort() {
abort = true;
} }
protected JoinLeftAnnounceMessage(String firstMessage) { protected JoinLeftAnnounceMessage(String firstMessage) {
@ -496,7 +538,7 @@ public class TGBridge {
messageId = -1; messageId = -1;
return; return;
} }
if (response.isOk() == false) { if (!response.isOk()) {
messageId = -1; messageId = -1;
return; return;
} }