Новый модуль: MultiServer
Данный модуль разработан для работы с множеством однотипных серверов.
This commit is contained in:
78
MultiServer/pom.xml
Normal file
78
MultiServer/pom.xml
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
||||||
|
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<name>ASys Multi server</name>
|
||||||
|
|
||||||
|
<developers>
|
||||||
|
<developer>
|
||||||
|
<name>DmitriyMX</name>
|
||||||
|
<email>mail@dmiriymx.ru</email>
|
||||||
|
</developer>
|
||||||
|
</developers>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<java.version>1.8</java.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<groupId>asys</groupId>
|
||||||
|
<artifactId>multiserver</artifactId>
|
||||||
|
<version>0.1</version>
|
||||||
|
<packaging>bundle</packaging>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>asys</groupId>
|
||||||
|
<artifactId>api</artifactId>
|
||||||
|
<version>0.10</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.osgi</groupId>
|
||||||
|
<artifactId>org.osgi.core</artifactId>
|
||||||
|
<version>6.0.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.felix</groupId>
|
||||||
|
<artifactId>org.apache.felix.gogo.runtime</artifactId>
|
||||||
|
<version>0.10.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-io</groupId>
|
||||||
|
<artifactId>commons-io</artifactId>
|
||||||
|
<version>2.5</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<finalName>${project.groupId}.${project.artifactId}-${project.version}</finalName>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.5.1</version>
|
||||||
|
<configuration>
|
||||||
|
<source>${java.version}</source>
|
||||||
|
<target>${java.version}</target>
|
||||||
|
<encoding>${project.build.sourceEncoding}</encoding>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.felix</groupId>
|
||||||
|
<artifactId>maven-bundle-plugin</artifactId>
|
||||||
|
<version>3.0.1</version>
|
||||||
|
<extensions>true</extensions>
|
||||||
|
<configuration>
|
||||||
|
<instructions>
|
||||||
|
<Bundle-Name>${project.name}</Bundle-Name>
|
||||||
|
<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
|
||||||
|
<Bundle-Activator>asys.multiserver.Activator</Bundle-Activator>
|
||||||
|
<Import-Package>asys.api, *</Import-Package>
|
||||||
|
</instructions>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
79
MultiServer/src/main/java/asys/multiserver/Activator.java
Normal file
79
MultiServer/src/main/java/asys/multiserver/Activator.java
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* DmitriyMX <mail@dmitriymx.ru>
|
||||||
|
* 2016-08-15
|
||||||
|
*/
|
||||||
|
package asys.multiserver;
|
||||||
|
|
||||||
|
import asys.api.BankObject;
|
||||||
|
import asys.api.MinecraftServerFactory;
|
||||||
|
import asys.api.ServerManager;
|
||||||
|
import org.osgi.framework.BundleActivator;
|
||||||
|
import org.osgi.framework.BundleContext;
|
||||||
|
import org.osgi.framework.ServiceRegistration;
|
||||||
|
import org.osgi.util.tracker.ServiceTracker;
|
||||||
|
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import static asys.api.ASysUtils.*;
|
||||||
|
|
||||||
|
public class Activator implements BundleActivator {
|
||||||
|
private ServiceTracker<?, MinecraftServerFactory> mcServerFactoryTracker;
|
||||||
|
private ServiceTracker<?, BankObject> bankObjectTracker;
|
||||||
|
private ServiceRegistration<?> commands, serverManager;
|
||||||
|
private MultiServer multiServer;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start(BundleContext bundleContext) throws Exception {
|
||||||
|
mcServerFactoryTracker = new ServiceTracker<>(bundleContext, MinecraftServerFactory.class.getName(), null);
|
||||||
|
mcServerFactoryTracker.open();
|
||||||
|
bankObjectTracker = new ServiceTracker<>(bundleContext, BankObject.class.getName(), null);
|
||||||
|
bankObjectTracker.open();
|
||||||
|
|
||||||
|
multiServer = new MultiServer(
|
||||||
|
loadProps(GetProperty(bundleContext, "asys.config.dir", "conf")),
|
||||||
|
mcServerFactoryTracker);
|
||||||
|
multiServer.loadState(bankObjectTracker.getService());
|
||||||
|
serverManager = bundleContext.registerService(ServerManager.class.getName(), multiServer, null);
|
||||||
|
|
||||||
|
commands = RegisterCommands(bundleContext, new Commands(multiServer), "asys.server");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop(BundleContext bundleContext) throws Exception {
|
||||||
|
commands.unregister();
|
||||||
|
serverManager.unregister();
|
||||||
|
multiServer.saveState(bankObjectTracker.getService());
|
||||||
|
multiServer = null;
|
||||||
|
bankObjectTracker.close();
|
||||||
|
mcServerFactoryTracker.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Properties loadProps(String confDir) {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
|
||||||
|
final String propsFileName = "asys-multiserver.properties";
|
||||||
|
Path propsPath = Paths.get(confDir).resolve(propsFileName);
|
||||||
|
if (Files.notExists(propsPath)) {
|
||||||
|
try {
|
||||||
|
SaveResource(Activator.class.getResourceAsStream("/"+propsFileName), propsPath.toFile());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
properties.load(new FileReader(propsPath.toFile()));
|
||||||
|
return properties;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
}
|
||||||
165
MultiServer/src/main/java/asys/multiserver/Commands.java
Normal file
165
MultiServer/src/main/java/asys/multiserver/Commands.java
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
/*
|
||||||
|
* DmitriyMX <mail@dmitriymx.ru>
|
||||||
|
* 2016-08-15
|
||||||
|
*/
|
||||||
|
package asys.multiserver;
|
||||||
|
|
||||||
|
import asys.api.ASysUtils;
|
||||||
|
import asys.api.Command;
|
||||||
|
import asys.api.MinecraftServer;
|
||||||
|
import org.apache.felix.service.command.Descriptor;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.StringJoiner;
|
||||||
|
|
||||||
|
public class Commands {
|
||||||
|
private MultiServer multiServer;
|
||||||
|
|
||||||
|
public Commands(MultiServer multiServer) {
|
||||||
|
this.multiServer = multiServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command
|
||||||
|
@Descriptor("Распечатать текущие настройки модуля")
|
||||||
|
public void config() {
|
||||||
|
ASysUtils.Log("------ Config ------");
|
||||||
|
ASysUtils.Log("%-20s %s", "BuildScript folder:", multiServer.buildScriptPath.toAbsolutePath());
|
||||||
|
ASysUtils.Log("%-20s %s", "Distributive folder:", multiServer.distrPath.toAbsolutePath());
|
||||||
|
ASysUtils.Log("%-20s %s", "Servers folder:", multiServer.serversPath.toAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command
|
||||||
|
@Descriptor("Развернуть новый сервер")
|
||||||
|
public void deploy(@Descriptor("тип сервера") String type) {
|
||||||
|
try {
|
||||||
|
ASysUtils.Log("New server id: %s", multiServer.deployServer(type));
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command
|
||||||
|
@Descriptor("Развернуть новый сервер")
|
||||||
|
public void deploy(@Descriptor("тип сервера") String type, @Descriptor("количество") int count) {
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
try {
|
||||||
|
ASysUtils.Log("New server id: %s", multiServer.deployServer(type));
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command
|
||||||
|
@Descriptor("Получить список серверов")
|
||||||
|
public void list() {
|
||||||
|
ASysUtils.Log("------ List servers ------");
|
||||||
|
final String format = " %-9s | %-6s";
|
||||||
|
ASysUtils.Log("%10s | %-6s", "ID", "STATUS");
|
||||||
|
multiServer.listServers().forEach(mcServer -> ASysUtils.Log(
|
||||||
|
format,
|
||||||
|
mcServer.getName(),
|
||||||
|
mcServer.isAlive() ? "Active" : "Ready"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command
|
||||||
|
@Descriptor("Получить список серверов")
|
||||||
|
public void list(@Descriptor("статус") String status) {
|
||||||
|
ASysUtils.Log("------ List servers ------");
|
||||||
|
final String format = " %-9s | %-6s";
|
||||||
|
ASysUtils.Log("%10s | %-6s", "ID", "STATUS");
|
||||||
|
multiServer.listServers().stream()
|
||||||
|
.filter(mcServer -> ((status.equalsIgnoreCase("active") && mcServer.isAlive()) ||
|
||||||
|
(status.equalsIgnoreCase("ready") && !mcServer.isAlive())))
|
||||||
|
.forEach(mcServer -> ASysUtils.Log(
|
||||||
|
format,
|
||||||
|
mcServer.getName(),
|
||||||
|
mcServer.isAlive() ? "Active" : "Ready"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command
|
||||||
|
@Descriptor("Получить список типов серверов")
|
||||||
|
public void types() {
|
||||||
|
ASysUtils.Log("------ Type servers ------");
|
||||||
|
multiServer.getTypes().forEach(type -> ASysUtils.Log(" %s", type));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command
|
||||||
|
@Descriptor("Старт сервера")
|
||||||
|
public void start(@Descriptor("id сервера") String serverId) {
|
||||||
|
MinecraftServer server = multiServer.getServer(serverId);
|
||||||
|
if (server == null) {
|
||||||
|
ASysUtils.Log("Server \"%s\" not found", serverId);
|
||||||
|
} else if (!server.isAlive()) {
|
||||||
|
server.start();
|
||||||
|
ASysUtils.Log("Server \"%s\" started", serverId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command
|
||||||
|
@Descriptor("Остановка сервера")
|
||||||
|
public void stop(@Descriptor("id сервера") String serverId) {
|
||||||
|
MinecraftServer server = multiServer.getServer(serverId);
|
||||||
|
if (server == null) {
|
||||||
|
ASysUtils.Log("Server \"%s\" not found", serverId);
|
||||||
|
} else if (server.isAlive()) {
|
||||||
|
server.stop();
|
||||||
|
ASysUtils.Log("Server \"%s\" stoppind", serverId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command
|
||||||
|
@Descriptor("Убить процесс сервера")
|
||||||
|
public void kill(@Descriptor("id сервера") String serverId) {
|
||||||
|
MinecraftServer server = multiServer.getServer(serverId);
|
||||||
|
if (server == null) {
|
||||||
|
ASysUtils.Log("Server \"%s\" not found", serverId);
|
||||||
|
} else if (server.isAlive()) {
|
||||||
|
server.forceStop();
|
||||||
|
ASysUtils.Log("Server \"%s\" killing", serverId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command
|
||||||
|
@Descriptor("Отправить на сервер комманду")
|
||||||
|
public void cmd(@Descriptor("id сервера") String serverId, @Descriptor("коменда") String... command) {
|
||||||
|
MinecraftServer server = multiServer.getServer(serverId);
|
||||||
|
if (server == null) {
|
||||||
|
ASysUtils.Log("Server \"%s\" not found", serverId);
|
||||||
|
} else if (server.isAlive()) {
|
||||||
|
StringJoiner sj = new StringJoiner(" ");
|
||||||
|
Arrays.asList(command).forEach(sj::add);
|
||||||
|
server.sendCommand(sj.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Command
|
||||||
|
@Descriptor("Получить информацию о сервере")
|
||||||
|
public void info(@Descriptor("id сервера") String serverId) {
|
||||||
|
/*TODO вывести информацию о соответствующем сервере
|
||||||
|
* информация должна содержать следующее:
|
||||||
|
* - id сервера
|
||||||
|
* - текущий онлайн
|
||||||
|
* - максимальный онлайн
|
||||||
|
* - TPS
|
||||||
|
* - политику доступа
|
||||||
|
* - время uptime
|
||||||
|
* - использумое кол-во оперативной памяти
|
||||||
|
* - максимально доступное кол-во памяти
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Command
|
||||||
|
@Descriptor("Установить серверу политику доступа")
|
||||||
|
public void accessPolicy(@Descriptor("id сервера") String serverid, String newPolicy) {
|
||||||
|
//TODO устанавливает соответствующему серверу политику доступа
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Command
|
||||||
|
@Descriptor("Удалить сервер (физически)")
|
||||||
|
public void remove(@Descriptor("id сервера") String serverId) {
|
||||||
|
//TODO удаляет сервер с диска
|
||||||
|
}
|
||||||
|
}
|
||||||
185
MultiServer/src/main/java/asys/multiserver/MultiServer.java
Normal file
185
MultiServer/src/main/java/asys/multiserver/MultiServer.java
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
/*
|
||||||
|
* DmitriyMX <mail@dmitriymx.ru>
|
||||||
|
* 2016-08-15
|
||||||
|
*/
|
||||||
|
package asys.multiserver;
|
||||||
|
|
||||||
|
import asys.api.BankObject;
|
||||||
|
import asys.api.MinecraftServer;
|
||||||
|
import asys.api.MinecraftServerFactory;
|
||||||
|
import asys.api.ServerManager;
|
||||||
|
import asys.multiserver.buildscript.BuildScript;
|
||||||
|
import asys.multiserver.buildscript.CommandException;
|
||||||
|
import org.osgi.util.tracker.ServiceTracker;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class MultiServer implements ServerManager {
|
||||||
|
private Map<String, MinecraftServer> mapMcServers = new HashMap<>();
|
||||||
|
private Random random = new Random(System.currentTimeMillis());
|
||||||
|
private ServiceTracker<?, MinecraftServerFactory> mcsfTracker;
|
||||||
|
Path buildScriptPath, distrPath, serversPath;
|
||||||
|
|
||||||
|
public MultiServer(Properties properties, ServiceTracker<?, MinecraftServerFactory> mcServerFactoryTracker) {
|
||||||
|
buildScriptPath = Paths.get(properties.getProperty("buildscript.dir", "scripts"));
|
||||||
|
distrPath = Paths.get(properties.getProperty("distributive.dir", "distr"));
|
||||||
|
serversPath = Paths.get(properties.getProperty("servers.dir", "servers"));
|
||||||
|
this.mcsfTracker = mcServerFactoryTracker;
|
||||||
|
|
||||||
|
File[] serverDirs = serversPath.toFile().listFiles((dir, name) -> dir.isDirectory());
|
||||||
|
if (serverDirs != null) {
|
||||||
|
for(File serverDir :serverDirs) {
|
||||||
|
Path asysPropsPath = serverDir.toPath().resolve("asys.properties");
|
||||||
|
if (Files.exists(asysPropsPath)) {
|
||||||
|
Properties asysProps = new Properties();
|
||||||
|
try {
|
||||||
|
FileReader fileReader = new FileReader(asysPropsPath.toFile());
|
||||||
|
asysProps.load(fileReader);
|
||||||
|
fileReader.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// e.printStackTrace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
putServer(asysProps, serverDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getTypes() {
|
||||||
|
List<String> list = new ArrayList<>();
|
||||||
|
String[] files = buildScriptPath.toFile().list((dir, name) -> name.indexOf(' ') == -1 && name.endsWith(".bs"));
|
||||||
|
if (files != null) {
|
||||||
|
Arrays.stream(files).map(s -> {
|
||||||
|
int i = s.lastIndexOf(".bs");
|
||||||
|
return s.substring(0, i);
|
||||||
|
}).forEach(list::add);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String deployServer(String type) throws IOException {
|
||||||
|
String serverId;
|
||||||
|
Path newServerPath;
|
||||||
|
final int max = 99;
|
||||||
|
int _try = 0;
|
||||||
|
int nId;
|
||||||
|
do {
|
||||||
|
if (_try == max*2) throw new IOException("End of free server id");
|
||||||
|
nId = random.nextInt(max);
|
||||||
|
serverId = type + nId;
|
||||||
|
newServerPath = serversPath.resolve(serverId);
|
||||||
|
_try++;
|
||||||
|
} while (Files.exists(newServerPath));
|
||||||
|
|
||||||
|
Files.createDirectory(newServerPath);
|
||||||
|
|
||||||
|
try {
|
||||||
|
BuildScript buildScript = BuildScript.loadFromFile(buildScriptPath.resolve(type + ".bs").toFile());
|
||||||
|
buildScript.setVariable("servers", serversPath.toAbsolutePath().toString());
|
||||||
|
buildScript.setVariable("distrib", distrPath.toAbsolutePath().toString());
|
||||||
|
buildScript.setVariable("serverId", serverId);
|
||||||
|
buildScript.execute();
|
||||||
|
} catch (CommandException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
Properties asysProps = new Properties();
|
||||||
|
Path serverDirPath = serversPath.resolve(serverId);
|
||||||
|
Path asysPropPath = serverDirPath.resolve("asys.properties");
|
||||||
|
if (Files.exists(asysPropPath)) {
|
||||||
|
asysProps.load(new FileReader(asysPropPath.toFile()));
|
||||||
|
}
|
||||||
|
asysProps.setProperty("server.id", serverId);
|
||||||
|
if (asysProps.getProperty("server.mainjar", null) == null) {
|
||||||
|
asysProps.setProperty("server.mainjar", "spigot.jar");
|
||||||
|
}
|
||||||
|
if (asysProps.getProperty("server.port.prefix", null) == null) {
|
||||||
|
asysProps.setProperty("server.port.prefix", "00");
|
||||||
|
}
|
||||||
|
asysProps.setProperty("server.port",
|
||||||
|
"2"+asysProps.getProperty("server.port.prefix")+nId);
|
||||||
|
asysProps.store(new FileWriter(asysPropPath.toFile()), "ASys Server settings");
|
||||||
|
|
||||||
|
putServer(asysProps, serverDirPath.toFile());
|
||||||
|
|
||||||
|
return serverId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void putServer(Properties asysProps, File serverDir) {
|
||||||
|
if (asysProps.getProperty("server.id", null) == null)
|
||||||
|
return; //TODO ошибку бы генерировать
|
||||||
|
if (asysProps.getProperty("server.port", null) == null)
|
||||||
|
return; //TODO ошибку бы генерировать
|
||||||
|
|
||||||
|
MinecraftServerFactory serverFactory = null;
|
||||||
|
try {
|
||||||
|
serverFactory = mcsfTracker.waitForService(1000L);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serverFactory == null)
|
||||||
|
return; //TODO ошибку бы генерировать
|
||||||
|
|
||||||
|
mapMcServers.put(
|
||||||
|
asysProps.getProperty("server.id"),
|
||||||
|
serverFactory.createServer(
|
||||||
|
asysProps.getProperty("server.id"),
|
||||||
|
serverDir,
|
||||||
|
asysProps.getProperty("server.mainjar"),
|
||||||
|
Short.valueOf(asysProps.getProperty("server.port")), //TODO надо сделать защиту от дурака: что если буквы введут?
|
||||||
|
asysProps.getProperty("server.jvm.args"),
|
||||||
|
asysProps.getProperty("server.params")
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<MinecraftServer> listServers() {
|
||||||
|
return new ArrayList<>(mapMcServers.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MinecraftServer getServer(String serverId) {
|
||||||
|
return mapMcServers.get(serverId); //TODO по хорошему, надо бы возвращать какой-нибудь EmptyPbject, а не null
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeServer(String serverId) {
|
||||||
|
mapMcServers.remove(serverId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
void loadState(BankObject bankObject) {
|
||||||
|
if(bankObject == null) return;
|
||||||
|
|
||||||
|
List<MinecraftServer> serversState = (List<MinecraftServer>) bankObject.get(MultiServer.class.getName()+"#servers");
|
||||||
|
if (serversState == null) return;
|
||||||
|
|
||||||
|
serversState.forEach(server -> {
|
||||||
|
if (server.isAlive()) {
|
||||||
|
mapMcServers.put(server.getName(), server);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void saveState(BankObject bankObject) {
|
||||||
|
if(bankObject == null) return;
|
||||||
|
|
||||||
|
List<MinecraftServer> serversState = new ArrayList<>();
|
||||||
|
mapMcServers.values().forEach(server -> {
|
||||||
|
if (server.isAlive()) {
|
||||||
|
serversState.add(server);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bankObject.save(MultiServer.class.getName()+"#servers", serversState);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,277 @@
|
|||||||
|
/*
|
||||||
|
* DmitriyMX <mail@dmitriymx.ru>
|
||||||
|
* 2016-06-23
|
||||||
|
*/
|
||||||
|
package asys.multiserver.buildscript;
|
||||||
|
|
||||||
|
import asys.api.ASysUtils;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Скрипт формирования окружения игрового сервера.<br><br>
|
||||||
|
*
|
||||||
|
* Команды:<br>
|
||||||
|
* - <code>lnk [источник] [цель]</code> - создание ссылки;<br>
|
||||||
|
* - <code>copy [источник] [цель]</code> - копирование;<br>
|
||||||
|
* - <code>mkdir [путь]</code> - создание папки или древа папок;<br>
|
||||||
|
* - <code>unpack [архив] [папка]</code> - распаковка архива в указанную папку;<br>
|
||||||
|
* - <code>undoparent</code> - отменить запланированные действия вышестоящего скрипта.
|
||||||
|
*/
|
||||||
|
public class BuildScript {
|
||||||
|
List<String[]> scriptLines = new ArrayList<>();
|
||||||
|
private Map<String, String> variables = new HashMap<>();
|
||||||
|
|
||||||
|
public static BuildScript loadFromFile(File file) throws IOException, UnknowCommandException {
|
||||||
|
return new BuildScript(FileUtils.readFileToString(file, Charset.forName("UTF-8")));
|
||||||
|
}
|
||||||
|
|
||||||
|
public BuildScript(String script) throws UnknowCommandException {
|
||||||
|
if (script == null || script.trim().isEmpty()) {
|
||||||
|
ASysUtils.Log("[WARN] Empty script!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (script.contains("\r\n")) {
|
||||||
|
// ASysUtils.Log("[WARN] Finded CRLF! Replaced...");
|
||||||
|
script = script.replaceAll("\r\n", "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String line : script.split("\n")) {
|
||||||
|
scriptLines.add(parseCommandLine(line));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVariables(Map<String, String> variables) {
|
||||||
|
this.variables = variables;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVariable(String name, String value) {
|
||||||
|
this.variables.put(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] parseCommandLine(String line) throws UnknowCommandException {
|
||||||
|
final StringTokenizer strTok = new StringTokenizer(line, " \"\'", true);
|
||||||
|
final List<String> preArr = new ArrayList<>();
|
||||||
|
byte state = 0; // 0-normal, 1-quoting1, 2-quoting2
|
||||||
|
String buff = "";
|
||||||
|
boolean foundCmd = false;
|
||||||
|
|
||||||
|
while (strTok.hasMoreTokens()) {
|
||||||
|
String partLine = strTok.nextToken();
|
||||||
|
|
||||||
|
if (!foundCmd) {
|
||||||
|
switch (partLine) {
|
||||||
|
case "lnk":
|
||||||
|
case "copy":
|
||||||
|
case "mkdir":
|
||||||
|
case "unpack":
|
||||||
|
case "undoparent":
|
||||||
|
foundCmd = true; // cmd correct;
|
||||||
|
partLine = partLine.toLowerCase();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
foundCmd = false; // cmd correct;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundCmd) {
|
||||||
|
throw new UnknowCommandException(partLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (partLine.equals("\"")) {
|
||||||
|
if (state == 0) {
|
||||||
|
state = 1;
|
||||||
|
continue;
|
||||||
|
} else if (state == 1){
|
||||||
|
state = 0;
|
||||||
|
preArr.add(buff);
|
||||||
|
buff = "";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (partLine.equals("\'")) {
|
||||||
|
if (state == 0) {
|
||||||
|
state = 2;
|
||||||
|
continue;
|
||||||
|
} else if (state == 2){
|
||||||
|
state = 0;
|
||||||
|
preArr.add(buff);
|
||||||
|
buff = "";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state == 1 || state == 2) {
|
||||||
|
buff += partLine;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (partLine.equals(" ")) continue;
|
||||||
|
|
||||||
|
preArr.add(partLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
return preArr.toArray(new String[preArr.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute() throws CommandException {
|
||||||
|
for (String[] cmdline : scriptLines) {
|
||||||
|
switch (cmdline[0]) {
|
||||||
|
case "lnk": cmd_lnk(cmdline[1], cmdline[2]); break;
|
||||||
|
case "copy": cmd_copy(cmdline[1], cmdline[2]); break;
|
||||||
|
case "mkdir": cmd_mkdir(cmdline[1]); break;
|
||||||
|
case "unpack": cmd_unpack(cmdline[1], cmdline[2]); break;
|
||||||
|
case "undoparent": cmd_undo(); break;
|
||||||
|
default: return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String applyVariables(String string) {
|
||||||
|
if (variables != null && !variables.isEmpty()) {
|
||||||
|
for (Map.Entry<String, String> entry : variables.entrySet()) {
|
||||||
|
string = string.replace("%"+entry.getKey()+"%", entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Создание символьной ссылки */
|
||||||
|
private void cmd_lnk(String source, String target) throws CommandException {
|
||||||
|
try {
|
||||||
|
Files.createSymbolicLink(
|
||||||
|
Paths.get(applyVariables(target)),
|
||||||
|
Paths.get(applyVariables(source)));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new CommandException("LNK", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Коирование */
|
||||||
|
private void cmd_copy(String source, String target) throws CommandException {
|
||||||
|
//TODO надо изюавиться от излишних Path.toFile()
|
||||||
|
Path sourcePath = Paths.get(applyVariables(source));
|
||||||
|
if (!sourcePath.toFile().exists()) {
|
||||||
|
throw new CommandException(String.format("COPY: source not found %s [%s]", source, sourcePath.toAbsolutePath()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Path targetPath = Paths.get(applyVariables(target));
|
||||||
|
if (!targetPath.toFile().exists()) {
|
||||||
|
if (sourcePath.toFile().isDirectory()) {
|
||||||
|
try {
|
||||||
|
FileUtils.copyDirectory(sourcePath.toFile(), targetPath.toFile());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new CommandException("COPY: error copy directory", e);
|
||||||
|
}
|
||||||
|
} else if (sourcePath.toFile().isFile()) {
|
||||||
|
try {
|
||||||
|
FileUtils.copyFile(sourcePath.toFile(), targetPath.toFile());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new CommandException("COPY: error copy file", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new CommandException("COPY: unknow type source file");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (sourcePath.toFile().isDirectory()) {
|
||||||
|
if (targetPath.toFile().isFile()) {
|
||||||
|
throw new CommandException("COPY: can't be copy dir to file");
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
FileUtils.copyDirectory(sourcePath.toFile(), targetPath.toFile());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new CommandException("COPY: error copy directory", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (sourcePath.toFile().isFile()) {
|
||||||
|
if (targetPath.toFile().isDirectory()) {
|
||||||
|
try {
|
||||||
|
FileUtils.copyFileToDirectory(sourcePath.toFile(), targetPath.toFile());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new CommandException("COPY: error copy file", e);
|
||||||
|
}
|
||||||
|
} else if (targetPath.toFile().isFile()) {
|
||||||
|
try {
|
||||||
|
FileUtils.copyFile(sourcePath.toFile(), targetPath.toFile());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new CommandException("COPY: error copy file", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Создание папки/древа папок
|
||||||
|
* параметры: цель */
|
||||||
|
private void cmd_mkdir(String dir) throws CommandException {
|
||||||
|
File treeDir = Paths.get(applyVariables(dir)).toFile();
|
||||||
|
if (treeDir.mkdirs() && !treeDir.exists()) {
|
||||||
|
throw new CommandException(String.format("MKDIR: can't create dirs %s [%s]", dir, treeDir.getAbsolutePath()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmd_unpack(String source, String target) throws CommandException {
|
||||||
|
Path sourcePath = Paths.get(applyVariables(source));
|
||||||
|
if (!sourcePath.toFile().exists()) {
|
||||||
|
throw new CommandException(String.format("UNPACK: source not found %s [%s]", source, sourcePath.toFile().getAbsolutePath()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sourcePath.toFile().isFile()) {
|
||||||
|
throw new CommandException(String.format("UNPACK: source is not file %s [%s]", source, sourcePath.toFile().getAbsolutePath()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Path targetPath = Paths.get(applyVariables(target));
|
||||||
|
if (!targetPath.toFile().exists()) {
|
||||||
|
if (targetPath.toFile().mkdirs() && !targetPath.toFile().exists()) {
|
||||||
|
throw new CommandException(String.format("UNPACK: can't create dir %s [%s]", target, targetPath.toFile().getAbsolutePath()));
|
||||||
|
}
|
||||||
|
} else if (targetPath.toFile().exists() && targetPath.toFile().isFile()) {
|
||||||
|
throw new CommandException(String.format("UNPACK: target can't be file %s [%s]", target, targetPath.toFile().getAbsolutePath()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// unzip
|
||||||
|
byte[] buffer = new byte[65536];
|
||||||
|
try {
|
||||||
|
ZipInputStream zis = new ZipInputStream(new FileInputStream(sourcePath.toFile()));
|
||||||
|
|
||||||
|
ZipEntry ze;
|
||||||
|
while ((ze = zis.getNextEntry()) != null) {
|
||||||
|
if (ze.isDirectory()) continue;
|
||||||
|
String fileName = ze.getName();
|
||||||
|
File newFile = new File(targetPath.toFile(), fileName);
|
||||||
|
Files.createDirectories(Paths.get(newFile.getParent()));
|
||||||
|
|
||||||
|
FileOutputStream fos = new FileOutputStream(newFile);
|
||||||
|
int len;
|
||||||
|
while ((len = zis.read(buffer)) > 0) {
|
||||||
|
fos.write(buffer, 0, len);
|
||||||
|
}
|
||||||
|
fos.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
zis.closeEntry();
|
||||||
|
zis.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new CommandException("UNPACK", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmd_undo() {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* DmitriyMX <mail@dmitriymx.ru>
|
||||||
|
* 2016-06-28
|
||||||
|
*/
|
||||||
|
package asys.multiserver.buildscript;
|
||||||
|
|
||||||
|
public class CommandException extends Exception {
|
||||||
|
CommandException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* DmitriyMX <mail@dmitriymx.ru>
|
||||||
|
* 2016-06-23
|
||||||
|
*/
|
||||||
|
package asys.multiserver.buildscript;
|
||||||
|
|
||||||
|
public class UnknowCommandException extends CommandException {
|
||||||
|
UnknowCommandException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
buildscript.dir=scripts
|
||||||
|
distributive.dir=distr
|
||||||
|
servers.dir=servers
|
||||||
Reference in New Issue
Block a user