自动关机
This commit is contained in:
parent
425210963f
commit
b7e4b668fe
3 changed files with 159 additions and 0 deletions
154
src/main/java/de/strifel/VTools/ServerCloser.java
Normal file
154
src/main/java/de/strifel/VTools/ServerCloser.java
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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() {
|
||||
|
|
|
@ -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);}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue