Merge branch 'master' into long_discord
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
Dieser Commit ist enthalten in:
Commit
1d8966865f
@ -89,9 +89,10 @@ public class BungeeCore extends Plugin {
|
|||||||
new WorldDownloader();
|
new WorldDownloader();
|
||||||
new BrandListener();
|
new BrandListener();
|
||||||
|
|
||||||
commands.put("/b", null);
|
new Node.LocalNode();
|
||||||
commands.put("/gs", null);
|
new Node.RemoteNode("lx");
|
||||||
commands.put("/bau", null);
|
new Node.RemoteNode("az");
|
||||||
|
|
||||||
commands.put("/tp", null);
|
commands.put("/tp", null);
|
||||||
commands.put("/bc", null);
|
commands.put("/bc", null);
|
||||||
commands.put("/bauchat", null);
|
commands.put("/bauchat", null);
|
||||||
@ -158,14 +159,13 @@ public class BungeeCore extends Plugin {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable(){
|
public void onDisable(){
|
||||||
ErrorLogger.stop();
|
|
||||||
Statement.close();
|
|
||||||
try {
|
try {
|
||||||
SteamwarDiscordBot.instance().getJda().shutdownNow();
|
SteamwarDiscordBot.instance().getJda().shutdownNow();
|
||||||
SteamwarDiscordBot.instance().getJda().awaitStatus(JDA.Status.SHUTDOWN);
|
SteamwarDiscordBot.instance().getJda().awaitStatus(JDA.Status.SHUTDOWN);
|
||||||
} catch (Exception e) {
|
} catch (InterruptedException e) {
|
||||||
// Ignored
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
|
Statement.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BungeeCore get() {
|
public static BungeeCore get() {
|
||||||
|
@ -20,83 +20,51 @@
|
|||||||
package de.steamwar.bungeecore;
|
package de.steamwar.bungeecore;
|
||||||
|
|
||||||
import de.steamwar.bungeecore.sql.SWException;
|
import de.steamwar.bungeecore.sql.SWException;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import de.steamwar.bungeecore.sql.Statement;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.PrintStream;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.logging.Filter;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
import java.util.logging.Handler;
|
import java.util.logging.Handler;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.LogRecord;
|
import java.util.logging.LogRecord;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public class ErrorLogger extends Handler implements Filter {
|
public class ErrorLogger extends Handler {
|
||||||
private static ErrorLogger instance;
|
|
||||||
private int ddosRate = 0;
|
private int ddosRate = 0;
|
||||||
|
|
||||||
ErrorLogger(){
|
ErrorLogger(){
|
||||||
ProxyServer.getInstance().getLogger().addHandler(this);
|
Logger.getLogger("").addHandler(this);
|
||||||
ProxyServer.getInstance().getLogger().setFilter(this);
|
|
||||||
instance = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void stop(){
|
|
||||||
ProxyServer.getInstance().getLogger().removeHandler(instance);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLoggable(LogRecord record) {
|
public void publish(LogRecord logRecord) {
|
||||||
if(record.getLevel() != Level.SEVERE)
|
if(logRecord.getLevel().intValue() < Level.WARNING.intValue())
|
||||||
return true;
|
return;
|
||||||
|
|
||||||
StringBuilder stacktrace = new StringBuilder(record.getSourceClassName() + "\n" + record.getSourceMethodName());
|
String message = MessageFormat.format(logRecord.getMessage(), logRecord.getParameters());
|
||||||
Throwable thrown = record.getThrown();
|
for(String reason : ignoreContains)
|
||||||
while(thrown != null){
|
if(message.contains(reason))
|
||||||
stacktrace.append("\nCaused by ").append(thrown.getMessage());
|
return;
|
||||||
|
|
||||||
for(StackTraceElement ste : thrown.getStackTrace())
|
ByteArrayOutputStream stacktraceOutput = new ByteArrayOutputStream();
|
||||||
stacktrace.append("\n").append(ste.toString());
|
if(logRecord.getThrown() != null)
|
||||||
|
logRecord.getThrown().printStackTrace(new PrintStream(stacktraceOutput));
|
||||||
thrown = thrown.getCause();
|
String stacktrace = stacktraceOutput.toString();
|
||||||
}
|
if(stacktrace.contains("Cannot request protocol")) {
|
||||||
|
if(++ddosRate % 1000 == 0) {
|
||||||
String stacktraceString = stacktrace.toString();
|
|
||||||
if(stacktraceString.contains("Cannot request protocol")){
|
|
||||||
ddosRate++;
|
|
||||||
if(ddosRate % 1000 == 0){
|
|
||||||
SWException.log("Bungee", "DDOS", ddosRate + "");
|
SWException.log("Bungee", "DDOS", ddosRate + "");
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void publish(LogRecord record) {
|
|
||||||
if(record.getLevel() != Level.SEVERE && record.getLevel() != Level.WARNING)
|
|
||||||
return;
|
return;
|
||||||
|
} else if (!Statement.connectionStable()) {
|
||||||
StringBuilder stacktrace = new StringBuilder(record.getSourceClassName() + "\n" + record.getSourceMethodName());
|
return;
|
||||||
Throwable thrown = record.getThrown();
|
|
||||||
while(thrown != null){
|
|
||||||
stacktrace.append("\nCaused by ").append(thrown.getMessage());
|
|
||||||
|
|
||||||
for(StackTraceElement ste : thrown.getStackTrace())
|
|
||||||
stacktrace.append("\n").append(ste.toString());
|
|
||||||
|
|
||||||
thrown = thrown.getCause();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String stacktraceString = stacktrace.toString();
|
|
||||||
String message = MessageFormat.format(record.getMessage(), record.getParameters());
|
|
||||||
|
|
||||||
if(message.contains("ServerConnector")
|
SWException.log("Bungee", message, stacktrace);
|
||||||
|| message.contains("InitialHandler")
|
|
||||||
|| message.contains("UpstreamBridge")
|
|
||||||
|| message.contains("DownstreamBridge")
|
|
||||||
|| message.contains(" took ")
|
|
||||||
|| message.contains("No client connected for pending server!"))
|
|
||||||
return;
|
|
||||||
|
|
||||||
SWException.log("Bungee", message, stacktraceString);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -108,4 +76,17 @@ public class ErrorLogger extends Handler implements Filter {
|
|||||||
public void close() {
|
public void close() {
|
||||||
//ignored
|
//ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final List<String> ignoreContains;
|
||||||
|
|
||||||
|
static {
|
||||||
|
List<String> contains = new ArrayList<>();
|
||||||
|
contains.add("ServerConnector");
|
||||||
|
contains.add("InitialHandler");
|
||||||
|
contains.add("UpstreamBridge");
|
||||||
|
contains.add("DownstreamBridge");
|
||||||
|
contains.add(" took ");
|
||||||
|
contains.add("No client connected for pending server!");
|
||||||
|
ignoreContains = Collections.unmodifiableList(contains);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,96 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bungeecore;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
public class LoadEvaluation {
|
|
||||||
private LoadEvaluation(){}
|
|
||||||
|
|
||||||
private static final File meminfo = new File("/proc/meminfo");
|
|
||||||
|
|
||||||
public static double getRamPercentage() {
|
|
||||||
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(meminfo)))) {
|
|
||||||
String memTotal = bufferedReader.readLine().replaceAll(" +", " ");
|
|
||||||
bufferedReader.readLine();
|
|
||||||
String memAvailable = bufferedReader.readLine().replaceAll(" +", " ");
|
|
||||||
|
|
||||||
long memTotalLong = getNumber(memTotal);
|
|
||||||
long memAvailableLong = getNumber(memAvailable);
|
|
||||||
return (memTotalLong - memAvailableLong) / (double) memTotalLong;
|
|
||||||
} catch (IOException e) {
|
|
||||||
return 1D;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double getRemoteRamPercentage(String remote) {
|
|
||||||
try {
|
|
||||||
// Attention:
|
|
||||||
// memInfo.sh needs to contain: cat /proc/meminfo
|
|
||||||
Process process = new ProcessBuilder("ssh", remote, "\"./memInfo.sh\"").start();
|
|
||||||
process.waitFor();
|
|
||||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
|
||||||
String memTotal = bufferedReader.readLine().replaceAll(" +", " ");
|
|
||||||
bufferedReader.readLine();
|
|
||||||
String memAvailable = bufferedReader.readLine().replaceAll(" +", " ");
|
|
||||||
|
|
||||||
long memTotalLong = getNumber(memTotal);
|
|
||||||
long memAvailableLong = getNumber(memAvailable);
|
|
||||||
return (memTotalLong - memAvailableLong) / (double) memTotalLong;
|
|
||||||
} catch (IOException e) {
|
|
||||||
return 1D;
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
return 1D;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double getCPULoad() {
|
|
||||||
try {
|
|
||||||
Process process = new ProcessBuilder("bash", "-c", "cat <(grep 'cpu ' /proc/stat) <(sleep 1 && grep 'cpu ' /proc/stat) | awk -v RS=\"\" '{printf \"%.2f\\n\", ($13-$2+$15-$4)*100/($13-$2+$15-$4+$16-$5)}'").start();
|
|
||||||
process.waitFor();
|
|
||||||
return Double.parseDouble(new BufferedReader(new InputStreamReader(process.getInputStream())).readLine()) / 100.0;
|
|
||||||
} catch (IOException e) {
|
|
||||||
return 1D;
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
return 1D;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double getRemoteCPULoad(String remote) {
|
|
||||||
try {
|
|
||||||
// Attention:
|
|
||||||
// cpuLoad.sh needs to contain: cat <(grep 'cpu ' /proc/stat) <(sleep 1 && grep 'cpu ' /proc/stat) | awk -v RS="" '{printf "%.2f\n", ($13-$2+$15-$4)*100/($13-$2+$15-$4+$16-$5)}'
|
|
||||||
Process process = new ProcessBuilder("ssh", remote, "\"./cpuLoad.sh\"").start();
|
|
||||||
process.waitFor();
|
|
||||||
return Double.parseDouble(new BufferedReader(new InputStreamReader(process.getInputStream())).readLine()) / 100.0;
|
|
||||||
} catch (IOException e) {
|
|
||||||
return 1D;
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
return 1D;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static long getNumber(String s) {
|
|
||||||
return Long.parseLong(s.split(" ")[1]);
|
|
||||||
}
|
|
||||||
}
|
|
261
src/de/steamwar/bungeecore/Node.java
Normale Datei
261
src/de/steamwar/bungeecore/Node.java
Normale Datei
@ -0,0 +1,261 @@
|
|||||||
|
/*
|
||||||
|
This file is a part of the SteamWar software.
|
||||||
|
|
||||||
|
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bungeecore;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
public abstract class Node {
|
||||||
|
|
||||||
|
private static final List<String> JVM_ARGS = Arrays.asList("-Dlog4j.configurationFile=log4j2.xml", "-server", "-Xms128M", "-XX:+UseCompressedOops", "-XX:+TieredCompilation", "-XX:TargetSurvivorRatio=90", "-XX:SurvivorRatio=8", "-XX:MaxTenuringThreshold=15", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseBiasedLocking", "-XX:UseSSE=3", "-XX:+UseCodeCacheFlushing", "-XX:+UseThreadPriorities", "-XX:+AggressiveOpts", "-XX:+ReduceSignalUsage", "-XX:+UseInterpreter", "-XX:+UseSharedSpaces", "-XX:AllocatePrefetchStyle=1", "-XX:+AlwaysCompileLoopMethods", "-XX:+UseConcMarkSweepGC", "-XX:+RewriteFrequentPairs", "-XX:+OptimizeStringConcat", "-XX:+CMSCleanOnEnter", "-XX:+UseInlineCaches");
|
||||||
|
private static final List<String> JVM8_ARGS = Arrays.asList("-XX:ThreadPriorityPolicy=42", "-XX:SharedReadOnlySize=30m", "-XX:+UseFastEmptyMethods", "-XX:+UseFastAccessorMethods");
|
||||||
|
private static final double MIN_FREE_MEM = 4.0 * 1024 * 1024; // 4 GiB
|
||||||
|
|
||||||
|
private static final List<Node> nodes = new ArrayList<>();
|
||||||
|
public static Node local = null;
|
||||||
|
|
||||||
|
public static Node getNode() {
|
||||||
|
Node node = local;
|
||||||
|
double minLoad = local.getLoad();
|
||||||
|
if(minLoad < 0.5)
|
||||||
|
return local;
|
||||||
|
|
||||||
|
synchronized (nodes) {
|
||||||
|
Iterator<Node> it = nodes.iterator();
|
||||||
|
while(it.hasNext()) {
|
||||||
|
Node n = it.next();
|
||||||
|
double load = n.getLoad();
|
||||||
|
if (load < minLoad) {
|
||||||
|
minLoad = load;
|
||||||
|
node = n;
|
||||||
|
} else if (load == Double.POSITIVE_INFINITY) {
|
||||||
|
BungeeCore.get().getLogger().log(Level.SEVERE, "Removing " + n.getName() + " due to infinite load!");
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void forEach(Consumer<Node> consumer) {
|
||||||
|
consumer.accept(local);
|
||||||
|
synchronized (nodes) {
|
||||||
|
nodes.forEach(consumer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract ProcessBuilder startServer(String serverJar, File directory, String worldDir, String levelName, int port, String xmx, String... dParams);
|
||||||
|
public abstract void execute(String... command);
|
||||||
|
public abstract String getName();
|
||||||
|
public abstract double getLoad();
|
||||||
|
|
||||||
|
protected void constructServerstart(List<String> cmd, String serverJar, String worldDir, String levelName, int port, String xmx, String... dParams) {
|
||||||
|
boolean jdk11 = serverJar.contains("1.15.2");
|
||||||
|
|
||||||
|
if(jdk11)
|
||||||
|
cmd.add("/usr/lib/jvm/java-11-openjdk-amd64/bin/java");
|
||||||
|
else
|
||||||
|
cmd.add("java");
|
||||||
|
|
||||||
|
for(String param : dParams){
|
||||||
|
cmd.add("-D" + param);
|
||||||
|
}
|
||||||
|
cmd.add("-Xmx" + xmx);
|
||||||
|
cmd.addAll(JVM_ARGS);
|
||||||
|
if(!jdk11)
|
||||||
|
cmd.addAll(JVM8_ARGS);
|
||||||
|
cmd.add("-jar");
|
||||||
|
cmd.add("/binarys/" + serverJar);
|
||||||
|
cmd.add("--log-strip-color");
|
||||||
|
cmd.add("--world-dir");
|
||||||
|
cmd.add(worldDir);
|
||||||
|
cmd.add("--level-name");
|
||||||
|
cmd.add(levelName);
|
||||||
|
cmd.add("--port");
|
||||||
|
cmd.add(String.valueOf(port));
|
||||||
|
cmd.add("nogui");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void execute(ProcessBuilder builder) {
|
||||||
|
try {
|
||||||
|
builder.start().waitFor();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new SecurityException("Could not execute command", e);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
ProxyServer.getInstance().getLogger().log(Level.SEVERE, "Interrupted during execution", e);
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class LocalNode extends Node {
|
||||||
|
private static final File meminfo = new File("/proc/meminfo");
|
||||||
|
private static final File loadavg = new File("/proc/loadavg");
|
||||||
|
|
||||||
|
private final int cores;
|
||||||
|
|
||||||
|
public LocalNode() {
|
||||||
|
this.cores = Runtime.getRuntime().availableProcessors();
|
||||||
|
local = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProcessBuilder startServer(String serverJar, File directory, String worldDir, String levelName, int port, String xmx, String... dParams) {
|
||||||
|
List<String> cmd = new ArrayList<>();
|
||||||
|
constructServerstart(cmd, serverJar, worldDir, levelName, port, xmx, dParams);
|
||||||
|
ProcessBuilder builder = new ProcessBuilder(cmd);
|
||||||
|
builder.directory(directory);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(String... command) {
|
||||||
|
execute(new ProcessBuilder(command));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "local";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getLoad() {
|
||||||
|
double totalMem;
|
||||||
|
double freeMem;
|
||||||
|
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(meminfo)))) {
|
||||||
|
totalMem = Double.parseDouble(bufferedReader.readLine().replaceAll(" +", " ").split(" ")[1]);
|
||||||
|
bufferedReader.readLine();
|
||||||
|
freeMem = Double.parseDouble(bufferedReader.readLine().replaceAll(" +", " ").split(" ")[1]);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new SecurityException("Could not read local memory", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
double cpuLoad;
|
||||||
|
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(loadavg)))) {
|
||||||
|
cpuLoad = Double.parseDouble(bufferedReader.readLine().split(" ")[0]);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new SecurityException("Could not read local cpu", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cpuLoad / cores + (freeMem > MIN_FREE_MEM ? 0 : ((totalMem - freeMem) / totalMem));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RemoteNode extends Node {
|
||||||
|
private final int cores;
|
||||||
|
private final String remote;
|
||||||
|
|
||||||
|
public RemoteNode(String remote) {
|
||||||
|
this.remote = remote;
|
||||||
|
|
||||||
|
//Determin core count
|
||||||
|
Process process;
|
||||||
|
try {
|
||||||
|
process = new ProcessBuilder("ssh", remote, "nproc").start();
|
||||||
|
if(!process.waitFor(5, TimeUnit.SECONDS))
|
||||||
|
throw new IOException("Timeout of " + remote + " on init");
|
||||||
|
} catch (IOException e) {
|
||||||
|
BungeeCore.get().getLogger().log(Level.SEVERE, "Could not initialize " + remote);
|
||||||
|
cores = 1;
|
||||||
|
return;
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
cores = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int c;
|
||||||
|
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
|
||||||
|
c = Integer.parseInt(bufferedReader.readLine());
|
||||||
|
} catch (IOException e) {
|
||||||
|
BungeeCore.get().getLogger().log(Level.SEVERE, "Could not read cores of" + remote, e);
|
||||||
|
c = 1;
|
||||||
|
}
|
||||||
|
cores = c;
|
||||||
|
BungeeCore.get().getLogger().log(Level.INFO, "Adding node " + remote + " with " + cores + " cores.");
|
||||||
|
|
||||||
|
synchronized (nodes) {
|
||||||
|
nodes.add(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProcessBuilder startServer(String serverJar, File directory, String worldDir, String levelName, int port, String xmx, String... dParams) {
|
||||||
|
List<String> cmd = new ArrayList<>();
|
||||||
|
cmd.add("ssh");
|
||||||
|
cmd.add("-L");
|
||||||
|
cmd.add(port + ":localhost:" + port);
|
||||||
|
cmd.add(remote);
|
||||||
|
cmd.add("cd");
|
||||||
|
cmd.add(directory.getPath());
|
||||||
|
cmd.add(";");
|
||||||
|
constructServerstart(cmd, serverJar, worldDir, levelName, port, xmx, dParams);
|
||||||
|
return new ProcessBuilder(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(String... command) {
|
||||||
|
List<String> cmd = new ArrayList<>();
|
||||||
|
cmd.add("ssh");
|
||||||
|
cmd.add(remote);
|
||||||
|
cmd.addAll(Arrays.asList(command));
|
||||||
|
execute(new ProcessBuilder(cmd));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return remote;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getLoad() {
|
||||||
|
Process process;
|
||||||
|
try {
|
||||||
|
process = new ProcessBuilder("ssh", remote, "cat /proc/loadavg;cat /proc/meminfo").start();
|
||||||
|
if(!process.waitFor(1, TimeUnit.SECONDS))
|
||||||
|
return Double.POSITIVE_INFINITY;
|
||||||
|
} catch (IOException e) {
|
||||||
|
BungeeCore.get().getLogger().log(Level.SEVERE, "Could starting process to read load", e);
|
||||||
|
return Double.POSITIVE_INFINITY;
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
return Double.POSITIVE_INFINITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
|
||||||
|
double cpuLoad = Double.parseDouble(bufferedReader.readLine().split(" ")[0]);
|
||||||
|
double totalMem = Double.parseDouble(bufferedReader.readLine().replaceAll(" +", " ").split(" ")[1]);
|
||||||
|
bufferedReader.readLine();
|
||||||
|
double freeMem = Double.parseDouble(bufferedReader.readLine().replaceAll(" +", " ").split(" ")[1]);
|
||||||
|
return cpuLoad / cores + (freeMem > MIN_FREE_MEM ? 0 : ((totalMem - freeMem) / totalMem));
|
||||||
|
} catch (IOException e) {
|
||||||
|
BungeeCore.get().getLogger().log(Level.SEVERE, "Could read load", e);
|
||||||
|
return Double.POSITIVE_INFINITY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -27,18 +27,14 @@ import net.md_5.bungee.api.chat.ClickEvent;
|
|||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.*;
|
import java.util.UUID;
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
public class SubserverSystem {
|
public class SubserverSystem {
|
||||||
private SubserverSystem(){}
|
private SubserverSystem(){}
|
||||||
|
|
||||||
private static final String BACKBONE = "/home/minecraft/backbone/";
|
private static final String BACKBONE = "/home/minecraft/";
|
||||||
private static final List<String> JVM_ARGS = Arrays.asList("-Dlog4j.configurationFile=log4j2.xml", "-server", "-Xms128M", "-XX:+UseCompressedOops", "-XX:+TieredCompilation", "-XX:TargetSurvivorRatio=90", "-XX:SurvivorRatio=8", "-XX:MaxTenuringThreshold=15", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseBiasedLocking", "-XX:UseSSE=3", "-XX:+UseCodeCacheFlushing", "-XX:+UseThreadPriorities", "-XX:+AggressiveOpts", "-XX:+ReduceSignalUsage", "-XX:+UseInterpreter", "-XX:+UseSharedSpaces", "-XX:AllocatePrefetchStyle=1", "-XX:+AlwaysCompileLoopMethods", "-XX:+UseConcMarkSweepGC", "-XX:+RewriteFrequentPairs", "-XX:+OptimizeStringConcat", "-XX:+CMSCleanOnEnter", "-XX:+UseInlineCaches");
|
|
||||||
private static final List<String> JVM8_ARGS = Arrays.asList("-XX:ThreadPriorityPolicy=42", "-XX:SharedReadOnlySize=30m", "-XX:+UseFastEmptyMethods", "-XX:+UseFastAccessorMethods");
|
|
||||||
private static final String ARENA_PATH = BACKBONE + "arenaserver/";
|
private static final String ARENA_PATH = BACKBONE + "arenaserver/";
|
||||||
private static final String SERVER_PATH = BACKBONE + "server/";
|
private static final String SERVER_PATH = BACKBONE + "server/";
|
||||||
private static final String EVENT_PATH = BACKBONE + "event/";
|
private static final String EVENT_PATH = BACKBONE + "event/";
|
||||||
@ -91,6 +87,7 @@ public class SubserverSystem {
|
|||||||
*/
|
*/
|
||||||
public static synchronized Subserver startArena(ArenaMode modus, String map, int eventFightID, int checkSchemID, int prepareSchemID, String serverName, String mapName, UUID player1, UUID player2, boolean ranked){
|
public static synchronized Subserver startArena(ArenaMode modus, String map, int eventFightID, int checkSchemID, int prepareSchemID, String serverName, String mapName, UUID player1, UUID player2, boolean ranked){
|
||||||
//Generate missing parameters
|
//Generate missing parameters
|
||||||
|
Node node = eventFightID > 0 ? Node.local : Node.getNode();
|
||||||
int port = freePort(FIRST_ARENA_PORT);
|
int port = freePort(FIRST_ARENA_PORT);
|
||||||
|
|
||||||
if(serverName == null){
|
if(serverName == null){
|
||||||
@ -109,56 +106,31 @@ public class SubserverSystem {
|
|||||||
worldDir = ARENA_PATH;
|
worldDir = ARENA_PATH;
|
||||||
|
|
||||||
//Copy world
|
//Copy world
|
||||||
try {
|
node.execute("cp", "-r", SERVER_PATH + modus.getFolder() + "/arenas/" + map, worldDir + mapName);
|
||||||
new ProcessBuilder("cp", "-r", SERVER_PATH + modus.getFolder() + "/arenas/" + map, worldDir + mapName).start().waitFor();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new SecurityException("Could not copy folder", e);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
ProxyServer.getInstance().getLogger().log(Level.SEVERE, "Interrupted while copying folder", e);
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
|
|
||||||
File directory = new File(SERVER_PATH, modus.getFolder());
|
File directory = new File(SERVER_PATH, modus.getFolder());
|
||||||
List<String> cmd = serverStartCommand(
|
ProcessBuilder builder = node.startServer(
|
||||||
modus.serverJar(),
|
modus.serverJar(), directory, worldDir, mapName, port, "2G",
|
||||||
directory,
|
"logPath=" + mapName, "config=" + modus.getConfig(),
|
||||||
worldDir,
|
"fightID=" + eventFightID, "ranked=" + ranked,
|
||||||
mapName,
|
"checkSchemID=" + checkSchemID, "prepareSchemID=" + prepareSchemID,
|
||||||
port,
|
|
||||||
"2G",
|
|
||||||
"logPath=" + mapName,
|
|
||||||
"config="+modus.getConfig(),
|
|
||||||
"fightID=" + eventFightID,
|
|
||||||
"ranked=" + ranked,
|
|
||||||
"checkSchemID=" + checkSchemID,
|
|
||||||
"prepareSchemID=" + prepareSchemID,
|
|
||||||
player1 != null && eventFightID != -1 ? "blueLeader=" + player1 : null,
|
player1 != null && eventFightID != -1 ? "blueLeader=" + player1 : null,
|
||||||
player2 != null ? "redLeader=" + player2 : null);
|
player2 != null ? "redLeader=" + player2 : null
|
||||||
|
);
|
||||||
//Start server
|
|
||||||
ProcessBuilder process = new ProcessBuilder(cmd);
|
|
||||||
process.directory(directory);
|
|
||||||
|
|
||||||
String finalMapName = mapName;
|
String finalMapName = mapName;
|
||||||
if(eventFightID == -1)
|
if(eventFightID == -1)
|
||||||
return new Bauserver(serverName, player1, port, process, () -> deleteFolder(ARENA_PATH + finalMapName));
|
return new Bauserver(serverName, player1, port, builder, () -> deleteFolder(node, ARENA_PATH + finalMapName));
|
||||||
else
|
else
|
||||||
return new Subserver(Servertype.ARENA, serverName, port, process, () -> {
|
return new Subserver(Servertype.ARENA, serverName, port, builder, () -> {
|
||||||
if(eventFightID > 0)
|
if(eventFightID > 0)
|
||||||
return;
|
return;
|
||||||
deleteFolder(ARENA_PATH + finalMapName);
|
deleteFolder(node, ARENA_PATH + finalMapName);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void deleteFolder(String worldName){
|
public static void deleteFolder(Node node, String worldName){
|
||||||
try {
|
node.execute("rm", "-r", worldName);
|
||||||
new ProcessBuilder("rm", "-r", worldName).start().waitFor();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new SecurityException("Could not clean up folder", e);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
ProxyServer.getInstance().getLogger().log(Level.SEVERE, "Interrupted while deleting folder", e);
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Subserver startEventArena(EventFight eventFight, String serverName){
|
public static Subserver startEventArena(EventFight eventFight, String serverName){
|
||||||
@ -183,25 +155,15 @@ public class SubserverSystem {
|
|||||||
if(bauRunning(p, owner))
|
if(bauRunning(p, owner))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
copyBauweltIfRequired(prototype, worldFolder + worldName);
|
||||||
SteamwarUser user = SteamwarUser.get(owner);
|
SteamwarUser user = SteamwarUser.get(owner);
|
||||||
copyBauweltIfRequired(p, prototype, worldFolder + worldName);
|
File directory = new File(SERVER_PATH, serverName);
|
||||||
|
Node node = Node.getNode();
|
||||||
int port = freePort(4000);
|
int port = freePort(4000);
|
||||||
|
|
||||||
File directory = new File(SERVER_PATH, serverName);
|
new Bauserver(user.getUserName() + "s Bau", owner, port, node.startServer(
|
||||||
List<String> cmd = serverStartCommand(
|
serverJar, directory, worldDir, worldName, port, xmx, "logPath=" + worldName
|
||||||
serverJar,
|
), () -> {}).sendPlayer(p);
|
||||||
directory,
|
|
||||||
worldDir,
|
|
||||||
worldName,
|
|
||||||
port,
|
|
||||||
xmx,
|
|
||||||
"logPath=" + worldName);
|
|
||||||
|
|
||||||
//Start server
|
|
||||||
ProcessBuilder process = new ProcessBuilder(cmd);
|
|
||||||
process.directory(directory);
|
|
||||||
|
|
||||||
new Bauserver(user.getUserName() + "s Bau", owner, port, process, () -> {}).sendPlayer(p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void sendToBauServer(ProxiedPlayer p, UUID owner){
|
public static void sendToBauServer(ProxiedPlayer p, UUID owner){
|
||||||
@ -235,63 +197,6 @@ public class SubserverSystem {
|
|||||||
new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/bau addmember " + p.getName()));
|
new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/bau addmember " + p.getName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<String> serverStartCommand(String serverJar, File directory, String worldDir, String levelName, int port, String xmx, String... dParams){
|
|
||||||
List<String> cmd = new ArrayList<>();
|
|
||||||
boolean jdk11 = serverJar.contains("1.15.2");
|
|
||||||
|
|
||||||
boolean fallback = false;
|
|
||||||
if (!steamwarStartAvailable()) {
|
|
||||||
cmd.add("ssh");
|
|
||||||
cmd.add("-L");
|
|
||||||
cmd.add(port + ":localhost:" + port);
|
|
||||||
if (remoteStartAvailable("lx")) {
|
|
||||||
cmd.add("lx");
|
|
||||||
} else if (remoteStartAvailable("az")) {
|
|
||||||
cmd.add("az");
|
|
||||||
} else {
|
|
||||||
fallback = true;
|
|
||||||
}
|
|
||||||
cmd.add("cd");
|
|
||||||
cmd.add(directory.getPath());
|
|
||||||
cmd.add(";");
|
|
||||||
}
|
|
||||||
if (fallback) {
|
|
||||||
cmd.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(jdk11)
|
|
||||||
cmd.add("/usr/lib/jvm/java-11-openjdk-amd64/bin/java");
|
|
||||||
else
|
|
||||||
cmd.add("java");
|
|
||||||
|
|
||||||
for(String param : dParams){
|
|
||||||
cmd.add("-D" + param);
|
|
||||||
}
|
|
||||||
cmd.add("-Xmx" + xmx);
|
|
||||||
cmd.addAll(JVM_ARGS);
|
|
||||||
if(!jdk11)
|
|
||||||
cmd.addAll(JVM8_ARGS);
|
|
||||||
cmd.add("-jar");
|
|
||||||
cmd.add("/binarys/" + serverJar);
|
|
||||||
cmd.add("--log-strip-color");
|
|
||||||
cmd.add("--world-dir");
|
|
||||||
cmd.add(worldDir);
|
|
||||||
cmd.add("--level-name");
|
|
||||||
cmd.add(levelName);
|
|
||||||
cmd.add("--port");
|
|
||||||
cmd.add(String.valueOf(port));
|
|
||||||
|
|
||||||
return cmd;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean steamwarStartAvailable(){
|
|
||||||
return LoadEvaluation.getCPULoad() < 0.7 && LoadEvaluation.getRamPercentage() < 0.8;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean remoteStartAvailable(String remote) {
|
|
||||||
return LoadEvaluation.getRemoteCPULoad(remote) < 0.7 && LoadEvaluation.getRemoteRamPercentage(remote) < 0.8;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean bauRunning(ProxiedPlayer p, UUID owner){
|
private static boolean bauRunning(ProxiedPlayer p, UUID owner){
|
||||||
for(Subserver subserver : Subserver.getServerList()){
|
for(Subserver subserver : Subserver.getServerList()){
|
||||||
if(subserver.getType() == Servertype.BAUSERVER && ((Bauserver)subserver).getOwner().equals(owner)){
|
if(subserver.getType() == Servertype.BAUSERVER && ((Bauserver)subserver).getOwner().equals(owner)){
|
||||||
@ -302,20 +207,10 @@ public class SubserverSystem {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void copyBauweltIfRequired(ProxiedPlayer p, String sourcePath, String targetPath){
|
private static void copyBauweltIfRequired(String sourcePath, String targetPath){
|
||||||
File w = new File(targetPath);
|
File w = new File(targetPath);
|
||||||
if (!w.exists() || !w.isDirectory()){
|
if (!w.exists() || !w.isDirectory())
|
||||||
try {
|
Node.local.execute("cp", "-r", sourcePath, targetPath);
|
||||||
new ProcessBuilder("cp", "-r", sourcePath, targetPath).start().waitFor();
|
|
||||||
} catch (IOException e) {
|
|
||||||
Message.send("SERVER_WORLD_ERROR", p);
|
|
||||||
throw new SecurityException("Could not create Bauwelt", e);
|
|
||||||
} catch (InterruptedException e){
|
|
||||||
BungeeCore.log("Could not create Bauwelt", e);
|
|
||||||
Message.send("SERVER_WORLD_ERROR", p);
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int freePort(int start){
|
private static int freePort(int start){
|
||||||
|
@ -257,7 +257,7 @@ public class BauCommand extends BasicCommand {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SubserverSystem.deleteFolder(world);
|
SubserverSystem.deleteFolder(Node.local, world);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,8 +19,8 @@
|
|||||||
|
|
||||||
package de.steamwar.bungeecore.commands;
|
package de.steamwar.bungeecore.commands;
|
||||||
|
|
||||||
import de.steamwar.bungeecore.LoadEvaluation;
|
|
||||||
import de.steamwar.bungeecore.Message;
|
import de.steamwar.bungeecore.Message;
|
||||||
|
import de.steamwar.bungeecore.Node;
|
||||||
import net.md_5.bungee.api.CommandSender;
|
import net.md_5.bungee.api.CommandSender;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
@ -36,34 +36,22 @@ public class StatCommand extends BasicCommand {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(CommandSender sender, String[] args) {
|
public void execute(CommandSender sender, String[] args) {
|
||||||
|
Map<String, Integer> serverCount = new HashMap<>();
|
||||||
try {
|
try {
|
||||||
Process process = new ProcessBuilder("ps", "x").start();
|
Process process = new ProcessBuilder("ps", "x").start();
|
||||||
process.waitFor();
|
new BufferedReader(new InputStreamReader(process.getInputStream())).lines().forEach(s -> {
|
||||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
if (!s.contains("--port"))
|
||||||
Map<String, Integer> serverCounts = new HashMap<>();
|
|
||||||
bufferedReader.lines().forEach(s -> {
|
|
||||||
if (!s.contains("--port")) {
|
|
||||||
return;
|
return;
|
||||||
}
|
serverCount.compute(
|
||||||
String server = "SW";
|
s.contains("ssh -L") ? s.substring(s.indexOf("ssh -L") + 6).split(" ")[2] : "local",
|
||||||
if (s.contains("ssh -L")) {
|
(server, count) -> (count != null ? count : 0) + 1
|
||||||
server = s.substring(s.indexOf("ssh -L") + 6).split(" ")[2];
|
);
|
||||||
}
|
|
||||||
serverCounts.put(server, serverCounts.computeIfAbsent(server, s1 -> 0) + 1);
|
|
||||||
});
|
});
|
||||||
serverCounts.forEach((s, integer) -> {
|
|
||||||
if (s.equals("SW")) {
|
|
||||||
Message.send("STAT_SERVER", sender, s, LoadEvaluation.getRamPercentage(), LoadEvaluation.getCPULoad(), integer);
|
|
||||||
} else {
|
|
||||||
Message.send("STAT_SERVER", sender, s.toUpperCase(), LoadEvaluation.getRemoteRamPercentage(s), LoadEvaluation.getRemoteCPULoad(s), integer);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (serverCounts.isEmpty()) {
|
|
||||||
Message.send("NO_STATS", sender);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new SecurityException(e.getMessage(), e);
|
throw new SecurityException(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Node.forEach(node -> Message.send("STAT_SERVER", sender, node.getName(), node.getLoad(), serverCount.getOrDefault(node.getName(), 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -40,27 +40,27 @@ public class Statement {
|
|||||||
Statement.user = user;
|
Statement.user = user;
|
||||||
Statement.password = password;
|
Statement.password = password;
|
||||||
try {
|
try {
|
||||||
con = DriverManager.getConnection(url + "?autoreconnect=true", user, password);
|
con = DriverManager.getConnection(url + "?autoreconnect=true&useServerPrepStmts=true", user, password);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
ProxyServer.getInstance().stop();
|
ProxyServer.getInstance().stop();
|
||||||
throw new SecurityException("Could not start SQL-Connection", e);
|
throw new SecurityException("Could not start SQL-Connection", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void reset(SQLException e) {
|
private static void reset() {
|
||||||
BungeeCore.get().getLogger().log(Level.WARNING, "SQL Exception thrown", e);
|
|
||||||
close();
|
close();
|
||||||
connect(url, user, password);
|
connect(url, user, password);
|
||||||
try {
|
try {
|
||||||
for (Statement statement : statements) {
|
for (Statement statement : statements) {
|
||||||
statement.init();
|
statement.init();
|
||||||
}
|
}
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException e) {
|
||||||
throw new SecurityException("Could not reprepare SQL Statements", ex);
|
throw new SecurityException("Could not reprepare SQL statements", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void close() {
|
public static void close() {
|
||||||
|
synchronized (statements) {
|
||||||
for (Statement statement : statements) {
|
for (Statement statement : statements) {
|
||||||
try {
|
try {
|
||||||
statement.st.close();
|
statement.st.close();
|
||||||
@ -72,7 +72,16 @@ public class Statement {
|
|||||||
try {
|
try {
|
||||||
con.close();
|
con.close();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
BungeeCore.log("Could not close SQL-Connection", e);
|
BungeeCore.get().getLogger().log(Level.INFO, "Could not close SQL connection", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean connectionStable() {
|
||||||
|
try {
|
||||||
|
return !con.isClosed();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,15 +94,16 @@ public class Statement {
|
|||||||
try {
|
try {
|
||||||
init();
|
init();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
reset(e);
|
throw new SecurityException("Could not init SQL statement", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void init() throws SQLException {
|
private void init() throws SQLException {
|
||||||
st = con.prepareStatement(sql);
|
st = con.prepareStatement(sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
<T> T select(ResultSetUser<T> user, Object... objects) {
|
<T> T select(ResultSetUser<T> user, Object... objects) {
|
||||||
|
synchronized (statements) {
|
||||||
return prepare(() -> {
|
return prepare(() -> {
|
||||||
ResultSet rs = st.executeQuery();
|
ResultSet rs = st.executeQuery();
|
||||||
T result = user.use(rs);
|
T result = user.use(rs);
|
||||||
@ -101,23 +111,21 @@ public class Statement {
|
|||||||
return result;
|
return result;
|
||||||
}, objects);
|
}, objects);
|
||||||
}
|
}
|
||||||
|
|
||||||
void update(Object... objects) {
|
|
||||||
prepare(st::executeUpdate, objects);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized <T> T prepare(SQLRunnable<T> runnable, Object... objects) {
|
void update(Object... objects) {
|
||||||
|
synchronized (statements) {
|
||||||
|
prepare(st::executeUpdate, objects);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> T prepare(SQLRunnable<T> runnable, Object... objects) {
|
||||||
try {
|
try {
|
||||||
setObjects(objects);
|
setObjects(objects);
|
||||||
return runnable.run();
|
return runnable.run();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
reset(e);
|
reset();
|
||||||
try {
|
throw new SecurityException("Could not execute SQL statement", e);
|
||||||
setObjects(objects);
|
|
||||||
return runnable.run();
|
|
||||||
} catch (SQLException ex) {
|
|
||||||
throw new SecurityException("Could not execute SQL statement", ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,8 +107,7 @@ MOD_YELLOW_PLUR=§7Deaktiviere die Mods\n§e{0}\n§7um weiter auf §eSteam§8War
|
|||||||
|
|
||||||
#Various commands
|
#Various commands
|
||||||
ALERT=§f{0}
|
ALERT=§f{0}
|
||||||
STAT_SERVER=§7Server §f{0} - §7Ram §f{1} §7CPU §f{2} §7Server Count §f{3}
|
STAT_SERVER=§7Server §e{0}§8: §7Load §e{1} §7Serveranzahl §e{2}
|
||||||
NO_STATS=§7Kein Bau oder Fight Server gestartet
|
|
||||||
|
|
||||||
#Ban&Mute-Command
|
#Ban&Mute-Command
|
||||||
BAN_TEAM_BANNED={0} §c{1} wurde von {2} {3} gebannt. §f§lGrund: §f{4}
|
BAN_TEAM_BANNED={0} §c{1} wurde von {2} {3} gebannt. §f§lGrund: §f{4}
|
||||||
|
6
steamwarci.yml
Normale Datei
6
steamwarci.yml
Normale Datei
@ -0,0 +1,6 @@
|
|||||||
|
build:
|
||||||
|
- "ln -s /home/gitea/lib"
|
||||||
|
- "mvn package -B"
|
||||||
|
|
||||||
|
artifacts:
|
||||||
|
"/binarys/bungeecore.jar": "target/bungeecore.jar"
|
In neuem Issue referenzieren
Einen Benutzer sperren