1
0
Fork 0
forked from mc/VTools

自动关机

This commit is contained in:
Sodium-Aluminate 2023-11-12 14:18:24 +08:00
parent 425210963f
commit b7e4b668fe
3 changed files with 159 additions and 0 deletions

View file

@ -0,0 +1,154 @@
package de.strifel.VTools;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.connection.DisconnectEvent;
import com.velocitypowered.api.event.player.ServerConnectedEvent;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer;
import de.strifel.VTools.listeners.TGBridge;
import okhttp3.*;
import org.yaml.snakeyaml.Yaml;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
public class ServerCloser {
private static final long INACTIVITY_TIMEOUT_MILLISECOND = 15L * 60 * 1000; // 15 minutes
private static final OkHttpClient CLIENT = new OkHttpClient();
private String apiUrl;
private static final String ACTION_STOP_JSON = "{\"action\":\"stop\"}";
@SuppressWarnings("java:S1068")
private static final String ACTION_START_JSON = "{\"action\":\"start\"}";
private final VTools plugin;
private final ProxyServer server;
private Timer closeServerTimer = new Timer();
private final Object lock = new Object();
public ServerCloser(VTools plugin) {
this.plugin = plugin;
this.server = plugin.getServer();
}
private boolean executeAzure() {
return executeAzure(ACTION_STOP_JSON);
}
private boolean executeAzure(String action) {
RequestBody requestBody = RequestBody.create(action, MediaType.parse("application/json"));
Request request = new Request.Builder()
.url(apiUrl)
.post(requestBody)
.addHeader("Content-Type", "application/json")
.build();
try {
Response response = CLIENT.newCall(request).execute();
plugin.logger.info("ServerCloser: http request response: {} ({}).", response.body().string(), response.code());
return (response.code() >= 200 && response.code() < 300);
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
private void close() {
boolean httpSuccess = false;
for (int i = 0; i < 3; i++) {
httpSuccess = executeAzure();
if (httpSuccess) break;
}
if (!httpSuccess) {
TGBridge.error("服务器关机 http 请求失效,服务器可能没有正常关闭。");
} else {
try {
Runtime.getRuntime().exec("pkill pymcd");
} catch (IOException ignored) {}
// plugin.getServer().shutdown();
}
}
private boolean firstInit;
public void register() {
server.getEventManager().register(plugin, this);
firstInit = true;
update();
loadConfig();
}
private void loadConfig() {
try {
File configDir = plugin.dataDirectory.toFile();
if (!configDir.exists()) {
configDir.mkdir();
}
File configFile = new File(configDir, "config.yaml");
if (!configFile.exists()) {
Files.write(Path.of(configFile.toURI()), "chat_id: \"0\"\ntoken: \"\"\n".getBytes(StandardCharsets.UTF_8));
}
String configStr = Files.readString(Path.of(configFile.toURI()), StandardCharsets.UTF_8);
Yaml yaml = new Yaml();
Map<String, String> config = yaml.load(configStr);
apiUrl = config.getOrDefault("azure_api_url", "https://example.com/");
} catch (Exception e) {
plugin.logger.error("parsing config", e);
}
}
@SuppressWarnings("java:S106")
@Subscribe
public void onDisconnect(DisconnectEvent event) {
update();
}
@Subscribe
public void onServerConnected(ServerConnectedEvent event) {
update();
}
private void update() {
Collection<Player> players = server.getAllPlayers();
if (!players.isEmpty()) {
plugin.logger.info("ServerCloser: 有玩家在线,干掉任何可能的关机计时器。");
closeServerTimer.cancel();
return;
}
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
if (server.getAllPlayers().isEmpty()) {
plugin.logger.info("ServerCloser: 即将关机。");
close();
} else {
plugin.logger.error("ServerCloser: 定时器到点时发现服务器有人。这不应发生,因为定时器本应该被打断。");
TGBridge.error("ServerCloser: #bug @NaAlOH4 定时器到点时发现服务器有人。这不应发生,因为定时器本应该被打断。");
}
closeServerTimer.cancel();
}
}, firstInit ? (4 * INACTIVITY_TIMEOUT_MILLISECOND) : INACTIVITY_TIMEOUT_MILLISECOND);
plugin.logger.info("ServerCloser: 将在 {} 后自动关机。", firstInit ? "1h" : "15min");
firstInit = false;
synchronized (lock) {
closeServerTimer.cancel();
closeServerTimer = timer;
}
}
}

View file

@ -45,6 +45,7 @@ public class VTools {
new TGBridge(this).register();
new PlayerStatus(this).register();
new GlobalChat(this).register();
new ServerCloser(this).register();
}
public ProxyServer getServer() {

View file

@ -273,6 +273,10 @@ public class TGBridge {
}, parseMode);
}
public static void error(String context) {
INSTANCE.outbound("*" + MarkdownString.escapeStr(context) + "*", ParseMode.MarkdownV2);
}
protected void outbound(String content) {outbound(content, (ParseMode) null);}