2019-06-02 05:03:08 +03:00
|
|
|
|
package pro.gravit.launchserver;
|
2018-09-17 10:07:32 +03:00
|
|
|
|
|
2019-06-03 10:58:10 +03:00
|
|
|
|
import java.io.BufferedReader;
|
|
|
|
|
import java.io.BufferedWriter;
|
|
|
|
|
import java.io.File;
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.io.Writer;
|
|
|
|
|
import java.lang.ProcessBuilder.Redirect;
|
|
|
|
|
import java.lang.reflect.InvocationTargetException;
|
|
|
|
|
import java.nio.file.DirectoryStream;
|
|
|
|
|
import java.nio.file.FileVisitResult;
|
|
|
|
|
import java.nio.file.Files;
|
|
|
|
|
import java.nio.file.Path;
|
|
|
|
|
import java.nio.file.SimpleFileVisitor;
|
|
|
|
|
import java.nio.file.attribute.BasicFileAttributes;
|
2019-07-12 16:01:55 +03:00
|
|
|
|
import java.security.InvalidAlgorithmParameterException;
|
2019-06-03 10:58:10 +03:00
|
|
|
|
import java.security.KeyPair;
|
2019-07-12 16:01:55 +03:00
|
|
|
|
import java.security.NoSuchAlgorithmException;
|
2019-06-03 10:58:10 +03:00
|
|
|
|
import java.security.interfaces.RSAPrivateKey;
|
|
|
|
|
import java.security.interfaces.RSAPublicKey;
|
|
|
|
|
import java.security.spec.InvalidKeySpecException;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.Arrays;
|
|
|
|
|
import java.util.Collection;
|
|
|
|
|
import java.util.Collections;
|
|
|
|
|
import java.util.Comparator;
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.LinkedList;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
import java.util.Map.Entry;
|
|
|
|
|
import java.util.Set;
|
|
|
|
|
import java.util.Timer;
|
|
|
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
|
|
import java.util.zip.CRC32;
|
|
|
|
|
|
2019-04-29 11:59:30 +03:00
|
|
|
|
import io.netty.handler.logging.LogLevel;
|
2019-07-12 16:01:55 +03:00
|
|
|
|
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
|
|
|
|
|
import org.bouncycastle.crypto.util.PrivateKeyFactory;
|
|
|
|
|
import org.bouncycastle.crypto.util.PrivateKeyInfoFactory;
|
|
|
|
|
import org.bouncycastle.operator.OperatorCreationException;
|
2019-06-03 10:58:10 +03:00
|
|
|
|
import pro.gravit.launcher.Launcher;
|
|
|
|
|
import pro.gravit.launcher.LauncherConfig;
|
|
|
|
|
import pro.gravit.launcher.NeedGarbageCollection;
|
|
|
|
|
import pro.gravit.launcher.hasher.HashedDir;
|
2019-07-02 11:36:50 +03:00
|
|
|
|
import pro.gravit.launcher.hwid.HWIDProvider;
|
2019-06-03 10:58:10 +03:00
|
|
|
|
import pro.gravit.launcher.managers.ConfigManager;
|
|
|
|
|
import pro.gravit.launcher.managers.GarbageManager;
|
|
|
|
|
import pro.gravit.launcher.profiles.ClientProfile;
|
2019-06-02 05:03:08 +03:00
|
|
|
|
import pro.gravit.launchserver.auth.AuthProviderPair;
|
|
|
|
|
import pro.gravit.launchserver.auth.handler.AuthHandler;
|
|
|
|
|
import pro.gravit.launchserver.auth.handler.MemoryAuthHandler;
|
|
|
|
|
import pro.gravit.launchserver.auth.hwid.AcceptHWIDHandler;
|
|
|
|
|
import pro.gravit.launchserver.auth.hwid.HWIDHandler;
|
|
|
|
|
import pro.gravit.launchserver.auth.permissions.DefaultPermissionsHandler;
|
|
|
|
|
import pro.gravit.launchserver.auth.permissions.JsonFilePermissionsHandler;
|
|
|
|
|
import pro.gravit.launchserver.auth.permissions.PermissionsHandler;
|
|
|
|
|
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
2019-06-07 01:23:33 +03:00
|
|
|
|
import pro.gravit.launchserver.auth.protect.StdProtectHandler;
|
2019-06-02 05:03:08 +03:00
|
|
|
|
import pro.gravit.launchserver.auth.provider.AuthProvider;
|
|
|
|
|
import pro.gravit.launchserver.auth.provider.RejectAuthProvider;
|
|
|
|
|
import pro.gravit.launchserver.auth.texture.RequestTextureProvider;
|
|
|
|
|
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
2019-07-12 16:43:56 +03:00
|
|
|
|
import pro.gravit.launchserver.binary.*;
|
2019-06-02 05:03:08 +03:00
|
|
|
|
import pro.gravit.launchserver.components.AuthLimiterComponent;
|
|
|
|
|
import pro.gravit.launchserver.components.Component;
|
2019-07-01 12:07:33 +03:00
|
|
|
|
import pro.gravit.launchserver.components.RegLimiterComponent;
|
2019-06-02 05:03:08 +03:00
|
|
|
|
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
2019-07-01 11:22:48 +03:00
|
|
|
|
import pro.gravit.launchserver.dao.provider.DaoProvider;
|
2019-07-01 17:45:11 +03:00
|
|
|
|
import pro.gravit.launchserver.manangers.*;
|
2019-06-02 05:03:08 +03:00
|
|
|
|
import pro.gravit.launchserver.manangers.hook.AuthHookManager;
|
|
|
|
|
import pro.gravit.launchserver.manangers.hook.BuildHookManager;
|
2019-07-01 12:59:47 +03:00
|
|
|
|
import pro.gravit.launchserver.socket.WebSocketService;
|
2019-07-01 10:37:01 +03:00
|
|
|
|
import pro.gravit.launchserver.socket.handlers.NettyServerSocketHandler;
|
2019-06-02 05:03:08 +03:00
|
|
|
|
import pro.gravit.utils.Version;
|
|
|
|
|
import pro.gravit.utils.command.CommandHandler;
|
|
|
|
|
import pro.gravit.utils.command.JLineCommandHandler;
|
|
|
|
|
import pro.gravit.utils.command.StdCommandHandler;
|
2019-06-03 10:58:10 +03:00
|
|
|
|
import pro.gravit.utils.helper.CommonHelper;
|
|
|
|
|
import pro.gravit.utils.helper.IOHelper;
|
|
|
|
|
import pro.gravit.utils.helper.JVMHelper;
|
|
|
|
|
import pro.gravit.utils.helper.LogHelper;
|
|
|
|
|
import pro.gravit.utils.helper.SecurityHelper;
|
2018-09-17 10:07:32 +03:00
|
|
|
|
|
2019-03-10 15:28:22 +03:00
|
|
|
|
public final class LaunchServer implements Runnable, AutoCloseable, Reloadable {
|
|
|
|
|
@Override
|
|
|
|
|
public void reload() throws Exception {
|
|
|
|
|
config.close();
|
|
|
|
|
LogHelper.info("Reading LaunchServer config file");
|
|
|
|
|
try (BufferedReader reader = IOHelper.newReader(configFile)) {
|
2019-04-20 01:03:06 +03:00
|
|
|
|
config = Launcher.gsonManager.gson.fromJson(reader, Config.class);
|
2019-03-10 15:28:22 +03:00
|
|
|
|
}
|
2019-06-03 11:50:28 +03:00
|
|
|
|
config.server = this;
|
2019-03-10 15:28:22 +03:00
|
|
|
|
config.verify();
|
2019-04-27 13:05:49 +03:00
|
|
|
|
config.init();
|
2019-03-10 15:28:22 +03:00
|
|
|
|
}
|
|
|
|
|
|
2018-12-23 18:50:31 +03:00
|
|
|
|
public static final class Config {
|
2019-06-03 11:50:28 +03:00
|
|
|
|
private transient LaunchServer server = null;
|
2018-12-26 14:21:08 +03:00
|
|
|
|
|
|
|
|
|
public String projectName;
|
|
|
|
|
|
|
|
|
|
public String[] mirrors;
|
2019-01-15 06:35:39 +03:00
|
|
|
|
|
2018-12-26 14:21:08 +03:00
|
|
|
|
public String binaryName;
|
2019-05-15 14:11:22 +03:00
|
|
|
|
|
2019-04-28 15:06:12 +03:00
|
|
|
|
public boolean copyBinaries = true;
|
2018-12-26 14:21:08 +03:00
|
|
|
|
|
|
|
|
|
public LauncherConfig.LauncherEnvironment env;
|
|
|
|
|
|
|
|
|
|
// Handlers & Providers
|
2018-10-13 11:01:10 +03:00
|
|
|
|
|
2019-03-22 09:14:29 +03:00
|
|
|
|
public AuthProviderPair[] auth;
|
2018-10-13 11:01:10 +03:00
|
|
|
|
|
2019-07-01 11:22:48 +03:00
|
|
|
|
public DaoProvider dao;
|
|
|
|
|
|
2019-03-22 09:14:29 +03:00
|
|
|
|
private transient AuthProviderPair authDefault;
|
2018-12-26 14:21:08 +03:00
|
|
|
|
|
2019-04-03 16:27:40 +03:00
|
|
|
|
public AuthProviderPair getAuthProviderPair(String name) {
|
|
|
|
|
for (AuthProviderPair pair : auth) {
|
|
|
|
|
if (pair.name.equals(name)) return pair;
|
2019-03-22 09:14:29 +03:00
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2019-04-03 16:27:40 +03:00
|
|
|
|
|
2019-03-14 19:54:08 +03:00
|
|
|
|
public ProtectHandler protectHandler;
|
|
|
|
|
|
2018-12-26 14:04:45 +03:00
|
|
|
|
public PermissionsHandler permissionsHandler;
|
|
|
|
|
|
2019-04-03 16:27:40 +03:00
|
|
|
|
public AuthProviderPair getAuthProviderPair() {
|
|
|
|
|
if (authDefault != null) return authDefault;
|
|
|
|
|
for (AuthProviderPair pair : auth) {
|
|
|
|
|
if (pair.isDefault) {
|
2019-03-22 09:14:29 +03:00
|
|
|
|
authDefault = pair;
|
|
|
|
|
return pair;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-23 18:50:31 +03:00
|
|
|
|
public HWIDHandler hwidHandler;
|
2018-09-17 10:07:32 +03:00
|
|
|
|
|
2019-03-23 06:30:05 +03:00
|
|
|
|
public Map<String, Component> components;
|
2019-03-13 12:24:28 +03:00
|
|
|
|
|
2018-12-23 18:50:31 +03:00
|
|
|
|
public ExeConf launch4j;
|
2019-01-29 18:38:23 +03:00
|
|
|
|
public NettyConfig netty;
|
2019-02-06 11:46:58 +03:00
|
|
|
|
public GuardLicenseConf guardLicense;
|
2018-12-23 18:50:31 +03:00
|
|
|
|
|
|
|
|
|
public String whitelistRejectString;
|
|
|
|
|
|
|
|
|
|
public boolean genMappings;
|
2019-04-12 01:15:05 +03:00
|
|
|
|
public LauncherConf launcher;
|
2018-12-23 18:50:31 +03:00
|
|
|
|
|
|
|
|
|
public boolean isWarningMissArchJava;
|
2019-01-05 18:43:05 +03:00
|
|
|
|
public boolean enabledProGuard;
|
2019-01-07 08:01:15 +03:00
|
|
|
|
public boolean stripLineNumbers;
|
2019-01-15 06:35:39 +03:00
|
|
|
|
public boolean deleteTempFiles;
|
|
|
|
|
|
|
|
|
|
public String startScript;
|
2019-01-04 14:32:16 +03:00
|
|
|
|
|
2018-12-26 14:35:28 +03:00
|
|
|
|
public void setProjectName(String projectName) {
|
|
|
|
|
this.projectName = projectName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setBinaryName(String binaryName) {
|
|
|
|
|
this.binaryName = binaryName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setEnv(LauncherConfig.LauncherEnvironment env) {
|
|
|
|
|
this.env = env;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-13 11:01:10 +03:00
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
public void verify() {
|
2019-03-22 09:14:29 +03:00
|
|
|
|
if (auth == null || auth[0] == null) {
|
2018-12-24 08:51:47 +03:00
|
|
|
|
throw new NullPointerException("AuthHandler must not be null");
|
|
|
|
|
}
|
2019-03-22 09:14:29 +03:00
|
|
|
|
boolean isOneDefault = false;
|
2019-04-03 16:27:40 +03:00
|
|
|
|
for (AuthProviderPair pair : auth) {
|
2019-03-22 09:19:58 +03:00
|
|
|
|
if (pair.isDefault) {
|
2019-03-22 09:14:29 +03:00
|
|
|
|
isOneDefault = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-03-22 09:19:58 +03:00
|
|
|
|
}
|
2019-04-03 16:27:40 +03:00
|
|
|
|
if (protectHandler == null) {
|
2019-03-14 19:54:08 +03:00
|
|
|
|
throw new NullPointerException("ProtectHandler must not be null");
|
|
|
|
|
}
|
2019-04-03 16:27:40 +03:00
|
|
|
|
if (!isOneDefault) {
|
2019-03-22 09:14:29 +03:00
|
|
|
|
throw new IllegalStateException("No auth pairs declared by default.");
|
2018-12-24 08:51:47 +03:00
|
|
|
|
}
|
2019-01-15 06:35:39 +03:00
|
|
|
|
if (permissionsHandler == null) {
|
2019-01-12 03:13:24 +03:00
|
|
|
|
throw new NullPointerException("PermissionsHandler must not be null");
|
|
|
|
|
}
|
2019-01-15 06:35:39 +03:00
|
|
|
|
if (env == null) {
|
2019-01-12 03:13:24 +03:00
|
|
|
|
throw new NullPointerException("Env must not be null");
|
|
|
|
|
}
|
2019-04-03 16:27:40 +03:00
|
|
|
|
if (netty == null) {
|
2019-03-10 15:01:14 +03:00
|
|
|
|
throw new NullPointerException("Netty must not be null");
|
|
|
|
|
}
|
2018-09-17 10:07:32 +03:00
|
|
|
|
}
|
2019-05-15 14:11:22 +03:00
|
|
|
|
|
|
|
|
|
public void init() {
|
2019-04-27 13:05:49 +03:00
|
|
|
|
Launcher.applyLauncherEnv(env);
|
|
|
|
|
for (AuthProviderPair provider : auth) {
|
2019-06-03 11:50:28 +03:00
|
|
|
|
provider.init(server);
|
2019-04-27 13:05:49 +03:00
|
|
|
|
}
|
2019-06-07 01:03:42 +03:00
|
|
|
|
permissionsHandler.init(server);
|
2019-04-27 13:05:49 +03:00
|
|
|
|
hwidHandler.init();
|
2019-07-01 11:31:50 +03:00
|
|
|
|
dao.init(server);
|
2019-04-27 13:05:49 +03:00
|
|
|
|
if (protectHandler != null) {
|
|
|
|
|
protectHandler.checkLaunchServerLicense();
|
|
|
|
|
}
|
2019-06-03 11:50:28 +03:00
|
|
|
|
server.registerObject("permissionsHandler", permissionsHandler);
|
2019-07-01 11:31:50 +03:00
|
|
|
|
server.registerObject("daoProvider", dao);
|
2019-05-15 14:09:32 +03:00
|
|
|
|
for (AuthProviderPair pair : auth) {
|
2019-06-03 11:50:28 +03:00
|
|
|
|
server.registerObject("auth.".concat(pair.name).concat(".provider"), pair.provider);
|
|
|
|
|
server.registerObject("auth.".concat(pair.name).concat(".handler"), pair.handler);
|
|
|
|
|
server.registerObject("auth.".concat(pair.name).concat(".texture"), pair.textureProvider);
|
2019-04-27 13:05:49 +03:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-03 11:50:28 +03:00
|
|
|
|
Arrays.stream(mirrors).forEach(server.mirrorManager::addMirror);
|
2019-04-27 13:05:49 +03:00
|
|
|
|
}
|
2019-04-03 16:27:40 +03:00
|
|
|
|
|
|
|
|
|
public void close() {
|
2019-04-27 13:17:10 +03:00
|
|
|
|
try {
|
2019-06-03 11:50:28 +03:00
|
|
|
|
server.unregisterObject("permissionsHandler", permissionsHandler);
|
2019-05-15 14:09:32 +03:00
|
|
|
|
for (AuthProviderPair pair : auth) {
|
2019-06-03 11:50:28 +03:00
|
|
|
|
server.unregisterObject("auth.".concat(pair.name).concat(".provider"), pair.provider);
|
|
|
|
|
server.unregisterObject("auth.".concat(pair.name).concat(".handler"), pair.handler);
|
|
|
|
|
server.unregisterObject("auth.".concat(pair.name).concat(".texture"), pair.textureProvider);
|
2019-04-27 13:17:10 +03:00
|
|
|
|
}
|
2019-05-15 14:11:22 +03:00
|
|
|
|
} catch (Exception e) {
|
2019-04-27 13:17:10 +03:00
|
|
|
|
LogHelper.error(e);
|
|
|
|
|
}
|
2019-03-10 15:28:22 +03:00
|
|
|
|
try {
|
2019-03-22 09:14:29 +03:00
|
|
|
|
for (AuthProviderPair p : auth) p.close();
|
2019-03-10 15:28:22 +03:00
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
LogHelper.error(e);
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
hwidHandler.close();
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
LogHelper.error(e);
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
permissionsHandler.close();
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
LogHelper.error(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-09-17 10:07:32 +03:00
|
|
|
|
}
|
2018-09-22 17:33:00 +03:00
|
|
|
|
|
2018-12-23 18:50:31 +03:00
|
|
|
|
public static class ExeConf {
|
|
|
|
|
public boolean enabled;
|
2019-07-12 16:43:56 +03:00
|
|
|
|
public String alternative;
|
2019-05-26 05:57:22 +03:00
|
|
|
|
public boolean setMaxVersion;
|
|
|
|
|
public String maxVersion;
|
2018-12-23 18:50:31 +03:00
|
|
|
|
public String productName;
|
|
|
|
|
public String productVer;
|
|
|
|
|
public String fileDesc;
|
|
|
|
|
public String fileVer;
|
|
|
|
|
public String internalName;
|
|
|
|
|
public String copyright;
|
|
|
|
|
public String trademarks;
|
|
|
|
|
|
|
|
|
|
public String txtFileVersion;
|
|
|
|
|
public String txtProductVersion;
|
2018-09-17 10:07:32 +03:00
|
|
|
|
}
|
2019-05-31 01:40:19 +03:00
|
|
|
|
|
|
|
|
|
public static class NettyUpdatesBind {
|
2019-05-15 15:58:28 +03:00
|
|
|
|
public String url;
|
|
|
|
|
public boolean zip;
|
|
|
|
|
}
|
2019-04-03 16:27:40 +03:00
|
|
|
|
|
2019-05-15 14:11:22 +03:00
|
|
|
|
public class LauncherConf {
|
2019-04-12 01:15:05 +03:00
|
|
|
|
public String guardType;
|
2019-05-15 18:43:05 +03:00
|
|
|
|
public boolean attachLibraryBeforeProGuard;
|
2019-07-15 22:47:07 +03:00
|
|
|
|
public boolean compress;
|
2019-04-12 01:15:05 +03:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-03 16:27:40 +03:00
|
|
|
|
public class NettyConfig {
|
2019-04-28 15:06:12 +03:00
|
|
|
|
public boolean fileServerEnabled;
|
2019-04-21 00:56:56 +03:00
|
|
|
|
public boolean sendExceptionEnabled;
|
2019-05-09 16:00:10 +03:00
|
|
|
|
public boolean ipForwarding;
|
2019-02-10 13:18:37 +03:00
|
|
|
|
public String launcherURL;
|
2019-04-03 16:40:19 +03:00
|
|
|
|
public String downloadURL;
|
2019-02-10 13:18:37 +03:00
|
|
|
|
public String launcherEXEURL;
|
2019-02-20 13:20:00 +03:00
|
|
|
|
public String address;
|
2019-05-15 16:01:42 +03:00
|
|
|
|
public Map<String, NettyUpdatesBind> bindings = new HashMap<>();
|
2019-04-06 14:41:38 +03:00
|
|
|
|
public NettyPerformanceConfig performance;
|
|
|
|
|
public NettyBindAddress[] binds;
|
2019-04-29 11:59:30 +03:00
|
|
|
|
public LogLevel logLevel = LogLevel.DEBUG;
|
2019-04-06 14:41:38 +03:00
|
|
|
|
}
|
2019-05-15 14:11:22 +03:00
|
|
|
|
|
|
|
|
|
public class NettyPerformanceConfig {
|
2019-07-01 14:34:03 +03:00
|
|
|
|
public boolean usingEpoll;
|
2019-04-06 14:41:38 +03:00
|
|
|
|
public int bossThread;
|
|
|
|
|
public int workerThread;
|
|
|
|
|
}
|
2019-05-15 14:11:22 +03:00
|
|
|
|
|
|
|
|
|
public class NettyBindAddress {
|
2019-04-06 14:41:38 +03:00
|
|
|
|
public String address;
|
|
|
|
|
public int port;
|
|
|
|
|
|
|
|
|
|
public NettyBindAddress(String address, int port) {
|
|
|
|
|
this.address = address;
|
|
|
|
|
this.port = port;
|
|
|
|
|
}
|
2019-01-29 18:38:23 +03:00
|
|
|
|
}
|
2019-04-03 16:27:40 +03:00
|
|
|
|
|
|
|
|
|
public class GuardLicenseConf {
|
2019-02-06 11:46:58 +03:00
|
|
|
|
public String name;
|
|
|
|
|
public String key;
|
|
|
|
|
public String encryptKey;
|
|
|
|
|
}
|
2018-09-22 17:33:00 +03:00
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
private final class ProfilesFileVisitor extends SimpleFileVisitor<Path> {
|
2018-12-23 18:57:40 +03:00
|
|
|
|
private final Collection<ClientProfile> result;
|
2018-09-17 10:07:32 +03:00
|
|
|
|
|
2018-12-23 18:57:40 +03:00
|
|
|
|
private ProfilesFileVisitor(Collection<ClientProfile> result) {
|
2018-09-17 10:07:32 +03:00
|
|
|
|
this.result = result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
|
|
|
|
LogHelper.info("Syncing '%s' profile", IOHelper.getFileName(file));
|
|
|
|
|
|
|
|
|
|
// Read profile
|
|
|
|
|
ClientProfile profile;
|
|
|
|
|
try (BufferedReader reader = IOHelper.newReader(file)) {
|
2019-04-20 01:03:06 +03:00
|
|
|
|
profile = Launcher.gsonManager.gson.fromJson(reader, ClientProfile.class);
|
2018-09-17 10:07:32 +03:00
|
|
|
|
}
|
|
|
|
|
profile.verify();
|
|
|
|
|
|
|
|
|
|
// Add SIGNED profile to result list
|
2018-12-23 18:57:40 +03:00
|
|
|
|
result.add(profile);
|
2018-09-17 10:07:32 +03:00
|
|
|
|
return super.visitFile(file, attrs);
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-09-22 17:33:00 +03:00
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
public static void main(String... args) throws Throwable {
|
2018-10-22 14:05:10 +03:00
|
|
|
|
JVMHelper.checkStackTrace(LaunchServer.class);
|
2018-09-17 10:07:32 +03:00
|
|
|
|
JVMHelper.verifySystemProperties(LaunchServer.class, true);
|
|
|
|
|
LogHelper.addOutput(IOHelper.WORKING_DIR.resolve("LaunchServer.log"));
|
|
|
|
|
LogHelper.printVersion("LaunchServer");
|
2018-12-24 13:16:57 +03:00
|
|
|
|
LogHelper.printLicense("LaunchServer");
|
2019-05-03 11:09:33 +03:00
|
|
|
|
if (!StarterAgent.isAgentStarted()) {
|
2019-05-15 14:11:22 +03:00
|
|
|
|
LogHelper.error("StarterAgent is not started!");
|
|
|
|
|
LogHelper.error("Your should add to JVM options this option: `-javaagent:LaunchServer.jar`");
|
2019-05-03 11:09:33 +03:00
|
|
|
|
}
|
2018-09-17 10:07:32 +03:00
|
|
|
|
|
|
|
|
|
// Start LaunchServer
|
2019-03-13 11:52:50 +03:00
|
|
|
|
long startTime = System.currentTimeMillis();
|
2018-09-17 10:07:32 +03:00
|
|
|
|
try {
|
2019-03-15 17:32:01 +03:00
|
|
|
|
@SuppressWarnings("resource")
|
2019-04-07 10:53:39 +03:00
|
|
|
|
LaunchServer launchserver = new LaunchServer(IOHelper.WORKING_DIR, false, args);
|
2019-04-03 16:27:40 +03:00
|
|
|
|
if (args.length == 0) launchserver.run();
|
2019-02-04 10:20:28 +03:00
|
|
|
|
else { //Обработка команды
|
2019-04-03 16:27:40 +03:00
|
|
|
|
launchserver.commandHandler.eval(args, false);
|
2019-02-04 10:20:28 +03:00
|
|
|
|
}
|
2018-09-17 10:07:32 +03:00
|
|
|
|
} catch (Throwable exc) {
|
|
|
|
|
LogHelper.error(exc);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-03-13 11:52:50 +03:00
|
|
|
|
long endTime = System.currentTimeMillis();
|
|
|
|
|
LogHelper.debug("LaunchServer started in %dms", endTime - startTime);
|
2018-09-17 10:07:32 +03:00
|
|
|
|
}
|
2018-09-22 17:33:00 +03:00
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
// Constant paths
|
2018-10-13 11:01:10 +03:00
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
public final Path dir;
|
|
|
|
|
|
2019-05-15 14:11:22 +03:00
|
|
|
|
public final boolean testEnv;
|
2019-04-07 10:53:39 +03:00
|
|
|
|
|
2019-01-15 06:35:39 +03:00
|
|
|
|
public final Path launcherLibraries;
|
|
|
|
|
|
2019-04-03 16:27:40 +03:00
|
|
|
|
public final Path launcherLibrariesCompile;
|
2019-03-15 17:32:01 +03:00
|
|
|
|
|
2019-01-15 06:35:39 +03:00
|
|
|
|
public final List<String> args;
|
2019-01-08 17:18:35 +03:00
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
public final Path configFile;
|
2019-04-12 00:58:45 +03:00
|
|
|
|
public final Path runtimeConfigFile;
|
2018-10-13 11:01:10 +03:00
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
public final Path publicKeyFile;
|
2018-10-13 11:01:10 +03:00
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
public final Path privateKeyFile;
|
2018-10-13 11:01:10 +03:00
|
|
|
|
|
2019-07-12 16:01:55 +03:00
|
|
|
|
public final Path caCertFile;
|
|
|
|
|
|
|
|
|
|
public final Path caKeyFile;
|
|
|
|
|
|
|
|
|
|
public final Path serverCertFile;
|
|
|
|
|
|
|
|
|
|
public final Path serverKeyFile;
|
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
public final Path updatesDir;
|
2019-01-15 06:35:39 +03:00
|
|
|
|
|
2019-06-03 11:50:28 +03:00
|
|
|
|
//public static LaunchServer server = null;
|
2018-10-13 11:01:10 +03:00
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
public final Path profilesDir;
|
|
|
|
|
// Server config
|
2018-10-13 11:01:10 +03:00
|
|
|
|
|
2019-03-10 15:28:22 +03:00
|
|
|
|
public Config config;
|
2019-04-12 00:58:45 +03:00
|
|
|
|
public LaunchServerRuntimeConfig runtime;
|
2018-09-17 10:07:32 +03:00
|
|
|
|
|
2018-10-13 11:01:10 +03:00
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
public final RSAPublicKey publicKey;
|
2018-10-13 11:01:10 +03:00
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
public final RSAPrivateKey privateKey;
|
|
|
|
|
// Launcher binary
|
2018-10-13 11:01:10 +03:00
|
|
|
|
|
2019-01-07 08:01:15 +03:00
|
|
|
|
public final JARLauncherBinary launcherBinary;
|
2018-10-13 11:01:10 +03:00
|
|
|
|
|
2019-04-07 10:53:39 +03:00
|
|
|
|
public Class<? extends LauncherBinary> launcherEXEBinaryClass;
|
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
public final LauncherBinary launcherEXEBinary;
|
|
|
|
|
// HWID ban + anti-brutforce
|
2018-10-13 11:01:10 +03:00
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
public final SessionManager sessionManager;
|
2018-12-29 13:00:50 +03:00
|
|
|
|
|
2018-12-31 10:51:49 +03:00
|
|
|
|
public final AuthHookManager authHookManager;
|
2018-09-17 10:07:32 +03:00
|
|
|
|
// Server
|
2018-10-13 11:01:10 +03:00
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
public final ModulesManager modulesManager;
|
|
|
|
|
|
2018-10-18 12:39:36 +03:00
|
|
|
|
public final MirrorManager mirrorManager;
|
|
|
|
|
|
2018-12-26 14:54:24 +03:00
|
|
|
|
public final ReloadManager reloadManager;
|
|
|
|
|
|
2018-12-26 15:40:53 +03:00
|
|
|
|
public final ReconfigurableManager reconfigurableManager;
|
|
|
|
|
|
2019-04-03 13:09:53 +03:00
|
|
|
|
public final ConfigManager configManager;
|
|
|
|
|
|
2019-07-01 17:45:11 +03:00
|
|
|
|
public final CertificateManager certificateManager;
|
|
|
|
|
|
2018-10-13 11:01:10 +03:00
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
public final BuildHookManager buildHookManager;
|
2018-10-13 11:01:10 +03:00
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
public final ProguardConf proguardConf;
|
|
|
|
|
|
2018-10-13 11:01:10 +03:00
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
public final CommandHandler commandHandler;
|
|
|
|
|
|
2019-01-29 18:42:31 +03:00
|
|
|
|
public final NettyServerSocketHandler nettyServerSocketHandler;
|
|
|
|
|
|
2018-09-22 17:33:00 +03:00
|
|
|
|
private final AtomicBoolean started = new AtomicBoolean(false);
|
2018-09-17 10:07:32 +03:00
|
|
|
|
|
|
|
|
|
// Updates and profiles
|
2018-12-23 18:57:40 +03:00
|
|
|
|
private volatile List<ClientProfile> profilesList;
|
2019-07-12 02:10:31 +03:00
|
|
|
|
public volatile Map<String, HashedDir> updatesDirMap;
|
2018-09-17 10:07:32 +03:00
|
|
|
|
|
2019-04-03 16:27:40 +03:00
|
|
|
|
public final Timer taskPool;
|
2019-01-21 16:06:13 +03:00
|
|
|
|
|
2019-04-07 10:53:39 +03:00
|
|
|
|
public static Class<? extends LauncherBinary> defaultLauncherEXEBinaryClass = null;
|
|
|
|
|
|
|
|
|
|
public LaunchServer(Path dir, boolean testEnv, String[] args) throws IOException, InvalidKeySpecException {
|
2018-09-17 10:07:32 +03:00
|
|
|
|
this.dir = dir;
|
2019-04-07 10:53:39 +03:00
|
|
|
|
this.testEnv = testEnv;
|
2019-02-03 14:15:30 +03:00
|
|
|
|
taskPool = new Timer("Timered task worker thread", true);
|
2019-01-08 17:18:35 +03:00
|
|
|
|
launcherLibraries = dir.resolve("launcher-libraries");
|
2019-03-15 17:32:01 +03:00
|
|
|
|
launcherLibrariesCompile = dir.resolve("launcher-libraries-compile");
|
2019-01-04 14:32:16 +03:00
|
|
|
|
this.args = Arrays.asList(args);
|
2019-06-28 12:27:05 +03:00
|
|
|
|
if(IOHelper.exists(dir.resolve("LaunchServer.conf")))
|
|
|
|
|
{
|
|
|
|
|
configFile = dir.resolve("LaunchServer.conf");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
configFile = dir.resolve("LaunchServer.json");
|
|
|
|
|
}
|
|
|
|
|
if(IOHelper.exists(dir.resolve("RuntimeLaunchServer.conf")))
|
|
|
|
|
{
|
|
|
|
|
runtimeConfigFile = dir.resolve("RuntimeLaunchServer.conf");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
runtimeConfigFile = dir.resolve("RuntimeLaunchServer.json");
|
|
|
|
|
}
|
2018-09-17 10:07:32 +03:00
|
|
|
|
publicKeyFile = dir.resolve("public.key");
|
|
|
|
|
privateKeyFile = dir.resolve("private.key");
|
|
|
|
|
updatesDir = dir.resolve("updates");
|
|
|
|
|
profilesDir = dir.resolve("profiles");
|
|
|
|
|
|
2019-07-12 16:01:55 +03:00
|
|
|
|
caCertFile = dir.resolve("ca.crt");
|
|
|
|
|
caKeyFile = dir.resolve("ca.key");
|
|
|
|
|
|
|
|
|
|
serverCertFile = dir.resolve("server.crt");
|
|
|
|
|
serverKeyFile = dir.resolve("server.key");
|
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
//Registration handlers and providers
|
|
|
|
|
AuthHandler.registerHandlers();
|
|
|
|
|
AuthProvider.registerProviders();
|
|
|
|
|
TextureProvider.registerProviders();
|
|
|
|
|
HWIDHandler.registerHandlers();
|
2018-12-26 14:04:45 +03:00
|
|
|
|
PermissionsHandler.registerHandlers();
|
2019-03-13 13:09:27 +03:00
|
|
|
|
Component.registerComponents();
|
2019-03-14 19:54:08 +03:00
|
|
|
|
ProtectHandler.registerHandlers();
|
2019-07-01 12:59:47 +03:00
|
|
|
|
WebSocketService.registerResponses();
|
2019-07-02 11:36:50 +03:00
|
|
|
|
HWIDProvider.registerHWIDs();
|
2019-07-04 10:41:30 +03:00
|
|
|
|
DaoProvider.registerProviders();
|
2019-06-03 11:50:28 +03:00
|
|
|
|
//LaunchServer.server = this;
|
2018-09-17 10:07:32 +03:00
|
|
|
|
|
|
|
|
|
// Set command handler
|
|
|
|
|
CommandHandler localCommandHandler;
|
2019-04-07 10:53:39 +03:00
|
|
|
|
if (testEnv)
|
|
|
|
|
localCommandHandler = new StdCommandHandler(false);
|
|
|
|
|
else
|
2019-05-15 14:11:22 +03:00
|
|
|
|
try {
|
|
|
|
|
Class.forName("org.jline.terminal.Terminal");
|
|
|
|
|
|
|
|
|
|
// JLine2 available
|
|
|
|
|
localCommandHandler = new JLineCommandHandler();
|
|
|
|
|
LogHelper.info("JLine2 terminal enabled");
|
|
|
|
|
} catch (ClassNotFoundException ignored) {
|
|
|
|
|
localCommandHandler = new StdCommandHandler(true);
|
|
|
|
|
LogHelper.warning("JLine2 isn't in classpath, using std");
|
|
|
|
|
}
|
2018-09-17 10:07:32 +03:00
|
|
|
|
commandHandler = localCommandHandler;
|
|
|
|
|
|
|
|
|
|
// Set key pair
|
|
|
|
|
if (IOHelper.isFile(publicKeyFile) && IOHelper.isFile(privateKeyFile)) {
|
|
|
|
|
LogHelper.info("Reading RSA keypair");
|
|
|
|
|
publicKey = SecurityHelper.toPublicRSAKey(IOHelper.read(publicKeyFile));
|
|
|
|
|
privateKey = SecurityHelper.toPrivateRSAKey(IOHelper.read(privateKeyFile));
|
|
|
|
|
if (!publicKey.getModulus().equals(privateKey.getModulus()))
|
2018-09-22 17:33:00 +03:00
|
|
|
|
throw new IOException("Private and public key modulus mismatch");
|
2018-09-17 10:07:32 +03:00
|
|
|
|
} else {
|
|
|
|
|
LogHelper.info("Generating RSA keypair");
|
|
|
|
|
KeyPair pair = SecurityHelper.genRSAKeyPair();
|
|
|
|
|
publicKey = (RSAPublicKey) pair.getPublic();
|
|
|
|
|
privateKey = (RSAPrivateKey) pair.getPrivate();
|
|
|
|
|
|
2019-01-22 07:38:41 +03:00
|
|
|
|
// Write key pair list
|
|
|
|
|
LogHelper.info("Writing RSA keypair list");
|
2018-09-17 10:07:32 +03:00
|
|
|
|
IOHelper.write(publicKeyFile, publicKey.getEncoded());
|
|
|
|
|
IOHelper.write(privateKeyFile, privateKey.getEncoded());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Print keypair fingerprints
|
|
|
|
|
CRC32 crc = new CRC32();
|
2018-10-18 12:39:36 +03:00
|
|
|
|
crc.update(publicKey.getModulus().toByteArray()); // IDEA говорит, что это Java 9 API. WTF?
|
2018-09-17 10:07:32 +03:00
|
|
|
|
LogHelper.subInfo("Modulus CRC32: 0x%08x", crc.getValue());
|
2018-09-22 17:33:00 +03:00
|
|
|
|
|
2019-04-07 10:53:39 +03:00
|
|
|
|
// Load class bindings.
|
|
|
|
|
launcherEXEBinaryClass = defaultLauncherEXEBinaryClass;
|
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
// pre init modules
|
|
|
|
|
modulesManager = new ModulesManager(this);
|
2018-09-19 15:03:52 +03:00
|
|
|
|
modulesManager.autoload(dir.resolve("modules"));
|
2018-09-17 10:07:32 +03:00
|
|
|
|
modulesManager.preInitModules();
|
2018-12-23 19:26:57 +03:00
|
|
|
|
initGson();
|
2018-09-22 17:33:00 +03:00
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
// Read LaunchServer config
|
2019-04-07 10:53:39 +03:00
|
|
|
|
generateConfigIfNotExists(testEnv);
|
2018-09-17 10:07:32 +03:00
|
|
|
|
LogHelper.info("Reading LaunchServer config file");
|
|
|
|
|
try (BufferedReader reader = IOHelper.newReader(configFile)) {
|
2019-04-20 01:03:06 +03:00
|
|
|
|
config = Launcher.gsonManager.gson.fromJson(reader, Config.class);
|
2018-09-17 10:07:32 +03:00
|
|
|
|
}
|
2019-06-03 11:50:28 +03:00
|
|
|
|
config.server = this;
|
2019-05-15 14:11:22 +03:00
|
|
|
|
if (!Files.exists(runtimeConfigFile)) {
|
2019-04-12 00:58:45 +03:00
|
|
|
|
LogHelper.info("Reset LaunchServer runtime config file");
|
|
|
|
|
runtime = new LaunchServerRuntimeConfig();
|
|
|
|
|
runtime.reset();
|
2019-05-15 14:11:22 +03:00
|
|
|
|
} else {
|
2019-04-12 00:58:45 +03:00
|
|
|
|
LogHelper.info("Reading LaunchServer runtime config file");
|
|
|
|
|
try (BufferedReader reader = IOHelper.newReader(runtimeConfigFile)) {
|
2019-04-20 01:03:06 +03:00
|
|
|
|
runtime = Launcher.gsonManager.gson.fromJson(reader, LaunchServerRuntimeConfig.class);
|
2019-04-12 00:58:45 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
runtime.verify();
|
2018-09-17 10:07:32 +03:00
|
|
|
|
config.verify();
|
2019-01-15 06:48:20 +03:00
|
|
|
|
Launcher.applyLauncherEnv(config.env);
|
2019-03-22 09:14:29 +03:00
|
|
|
|
for (AuthProviderPair provider : config.auth) {
|
2019-06-03 11:50:28 +03:00
|
|
|
|
provider.init(this);
|
2018-12-26 15:24:38 +03:00
|
|
|
|
}
|
2019-06-07 01:03:42 +03:00
|
|
|
|
config.permissionsHandler.init(this);
|
2019-03-28 13:13:27 +03:00
|
|
|
|
config.hwidHandler.init();
|
2019-07-01 13:08:20 +03:00
|
|
|
|
if(config.dao != null)
|
|
|
|
|
config.dao.init(this);
|
2019-04-03 16:27:40 +03:00
|
|
|
|
if (config.protectHandler != null) {
|
2019-03-14 19:54:08 +03:00
|
|
|
|
config.protectHandler.checkLaunchServerLicense();
|
|
|
|
|
}
|
2019-04-03 16:27:40 +03:00
|
|
|
|
if (config.components != null) {
|
2019-03-13 12:24:28 +03:00
|
|
|
|
LogHelper.debug("PreInit components");
|
2019-04-03 16:27:40 +03:00
|
|
|
|
config.components.forEach((k, v) -> {
|
2019-03-13 12:24:28 +03:00
|
|
|
|
LogHelper.subDebug("PreInit component %s", k);
|
|
|
|
|
v.preInit(this);
|
|
|
|
|
});
|
|
|
|
|
LogHelper.debug("PreInit components successful");
|
|
|
|
|
}
|
2018-09-17 10:07:32 +03:00
|
|
|
|
|
|
|
|
|
// build hooks, anti-brutforce and other
|
|
|
|
|
buildHookManager = new BuildHookManager();
|
|
|
|
|
proguardConf = new ProguardConf(this);
|
|
|
|
|
sessionManager = new SessionManager();
|
2018-10-18 12:39:36 +03:00
|
|
|
|
mirrorManager = new MirrorManager();
|
2018-12-26 14:54:24 +03:00
|
|
|
|
reloadManager = new ReloadManager();
|
2018-12-26 15:40:53 +03:00
|
|
|
|
reconfigurableManager = new ReconfigurableManager();
|
2018-12-31 10:51:49 +03:00
|
|
|
|
authHookManager = new AuthHookManager();
|
2019-04-03 13:09:53 +03:00
|
|
|
|
configManager = new ConfigManager();
|
2019-07-01 17:45:11 +03:00
|
|
|
|
certificateManager = new CertificateManager();
|
2019-07-12 16:01:55 +03:00
|
|
|
|
//Generate or set new Certificate API
|
|
|
|
|
certificateManager.orgName = config.projectName;
|
|
|
|
|
if(IOHelper.isFile(caCertFile) && IOHelper.isFile(caKeyFile))
|
|
|
|
|
{
|
|
|
|
|
certificateManager.ca = certificateManager.readCertificate(caCertFile);
|
|
|
|
|
certificateManager.caKey = certificateManager.readPrivateKey(caKeyFile);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
certificateManager.generateCA();
|
|
|
|
|
certificateManager.writeCertificate(caCertFile, certificateManager.ca);
|
|
|
|
|
certificateManager.writePrivateKey(caKeyFile, certificateManager.caKey);
|
|
|
|
|
} catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | OperatorCreationException e) {
|
|
|
|
|
LogHelper.error(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(IOHelper.isFile(serverCertFile) && IOHelper.isFile(serverKeyFile))
|
|
|
|
|
{
|
|
|
|
|
certificateManager.server = certificateManager.readCertificate(serverCertFile);
|
|
|
|
|
certificateManager.serverKey = certificateManager.readPrivateKey(serverKeyFile);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
KeyPair pair = certificateManager.generateKeyPair();
|
|
|
|
|
certificateManager.server = certificateManager.generateCertificate(config.projectName.concat(" Server"), pair.getPublic());
|
|
|
|
|
certificateManager.serverKey = PrivateKeyFactory.createKey(pair.getPrivate().getEncoded());
|
|
|
|
|
certificateManager.writePrivateKey(serverKeyFile, pair.getPrivate());
|
|
|
|
|
certificateManager.writeCertificate(serverCertFile, certificateManager.server);
|
|
|
|
|
} catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException | OperatorCreationException e) {
|
|
|
|
|
LogHelper.error(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
GarbageManager.registerNeedGC(sessionManager);
|
2019-03-10 15:28:22 +03:00
|
|
|
|
reloadManager.registerReloadable("launchServer", this);
|
2019-04-03 13:09:53 +03:00
|
|
|
|
registerObject("permissionsHandler", config.permissionsHandler);
|
2019-03-22 09:14:29 +03:00
|
|
|
|
for (int i = 0; i < config.auth.length; ++i) {
|
|
|
|
|
AuthProviderPair pair = config.auth[i];
|
2019-04-03 13:09:53 +03:00
|
|
|
|
registerObject("auth.".concat(pair.name).concat(".provider"), pair.provider);
|
|
|
|
|
registerObject("auth.".concat(pair.name).concat(".handler"), pair.handler);
|
|
|
|
|
registerObject("auth.".concat(pair.name).concat(".texture"), pair.textureProvider);
|
2018-12-26 15:54:04 +03:00
|
|
|
|
}
|
|
|
|
|
|
2019-01-15 06:48:20 +03:00
|
|
|
|
Arrays.stream(config.mirrors).forEach(mirrorManager::addMirror);
|
2018-09-22 17:33:00 +03:00
|
|
|
|
|
2019-07-06 15:54:10 +03:00
|
|
|
|
pro.gravit.launchserver.command.handler.CommandHandler.registerCommands(localCommandHandler, this);
|
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
// init modules
|
|
|
|
|
modulesManager.initModules();
|
2019-04-03 16:27:40 +03:00
|
|
|
|
if (config.components != null) {
|
2019-03-13 12:24:28 +03:00
|
|
|
|
LogHelper.debug("Init components");
|
2019-04-03 16:27:40 +03:00
|
|
|
|
config.components.forEach((k, v) -> {
|
2019-03-13 12:24:28 +03:00
|
|
|
|
LogHelper.subDebug("Init component %s", k);
|
2019-04-03 16:27:40 +03:00
|
|
|
|
registerObject("component.".concat(k), v);
|
2019-03-13 12:24:28 +03:00
|
|
|
|
v.init(this);
|
|
|
|
|
});
|
|
|
|
|
LogHelper.debug("Init components successful");
|
|
|
|
|
}
|
2018-09-17 10:07:32 +03:00
|
|
|
|
|
|
|
|
|
// Set launcher EXE binary
|
|
|
|
|
launcherBinary = new JARLauncherBinary(this);
|
|
|
|
|
launcherEXEBinary = binary();
|
2019-01-15 06:35:39 +03:00
|
|
|
|
|
2019-01-08 16:57:01 +03:00
|
|
|
|
launcherBinary.init();
|
|
|
|
|
launcherEXEBinary.init();
|
2018-09-17 10:07:32 +03:00
|
|
|
|
syncLauncherBinaries();
|
|
|
|
|
|
|
|
|
|
// Sync updates dir
|
|
|
|
|
if (!IOHelper.isDir(updatesDir))
|
2018-09-22 17:33:00 +03:00
|
|
|
|
Files.createDirectory(updatesDir);
|
2018-09-17 10:07:32 +03:00
|
|
|
|
syncUpdatesDir(null);
|
|
|
|
|
|
|
|
|
|
// Sync profiles dir
|
|
|
|
|
if (!IOHelper.isDir(profilesDir))
|
2018-09-22 17:33:00 +03:00
|
|
|
|
Files.createDirectory(profilesDir);
|
2018-09-17 10:07:32 +03:00
|
|
|
|
syncProfilesDir();
|
|
|
|
|
|
|
|
|
|
// post init modules
|
|
|
|
|
modulesManager.postInitModules();
|
2019-04-03 16:27:40 +03:00
|
|
|
|
if (config.components != null) {
|
2019-03-13 12:24:28 +03:00
|
|
|
|
LogHelper.debug("PostInit components");
|
2019-04-03 16:27:40 +03:00
|
|
|
|
config.components.forEach((k, v) -> {
|
2019-03-13 12:24:28 +03:00
|
|
|
|
LogHelper.subDebug("PostInit component %s", k);
|
|
|
|
|
v.postInit(this);
|
|
|
|
|
});
|
|
|
|
|
LogHelper.debug("PostInit components successful");
|
|
|
|
|
}
|
2019-01-21 12:11:56 +03:00
|
|
|
|
// start updater
|
2019-04-03 16:27:40 +03:00
|
|
|
|
if (config.netty != null)
|
2019-01-29 18:42:31 +03:00
|
|
|
|
nettyServerSocketHandler = new NettyServerSocketHandler(this);
|
|
|
|
|
else
|
|
|
|
|
nettyServerSocketHandler = null;
|
2018-09-17 10:07:32 +03:00
|
|
|
|
}
|
|
|
|
|
|
2019-01-15 06:35:39 +03:00
|
|
|
|
public static void initGson() {
|
2019-04-20 01:03:06 +03:00
|
|
|
|
Launcher.gsonManager = new LaunchServerGsonManager();
|
|
|
|
|
Launcher.gsonManager.initGson();
|
2018-12-23 19:26:57 +03:00
|
|
|
|
}
|
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
private LauncherBinary binary() {
|
2019-05-15 14:11:22 +03:00
|
|
|
|
if (launcherEXEBinaryClass != null) {
|
|
|
|
|
try {
|
|
|
|
|
return launcherEXEBinaryClass.getConstructor(LaunchServer.class).newInstance(this);
|
|
|
|
|
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
|
|
|
|
|
| InvocationTargetException | NoSuchMethodException | SecurityException e) {
|
|
|
|
|
LogHelper.error(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-07-12 16:43:56 +03:00
|
|
|
|
if(config.launch4j.alternative != null)
|
|
|
|
|
{
|
|
|
|
|
switch (config.launch4j.alternative) {
|
|
|
|
|
case "simple":
|
|
|
|
|
return new SimpleEXELauncherBinary(this);
|
|
|
|
|
case "no":
|
|
|
|
|
//None
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
LogHelper.warning("Alternative %s not found", config.launch4j.alternative);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-01-15 06:35:39 +03:00
|
|
|
|
try {
|
|
|
|
|
Class.forName("net.sf.launch4j.Builder");
|
2018-12-26 16:17:47 +03:00
|
|
|
|
if (config.launch4j.enabled) return new EXEL4JLauncherBinary(this);
|
2019-01-15 06:35:39 +03:00
|
|
|
|
} catch (ClassNotFoundException ignored) {
|
|
|
|
|
LogHelper.warning("Launch4J isn't in classpath.");
|
|
|
|
|
}
|
2018-09-22 17:33:00 +03:00
|
|
|
|
return new EXELauncherBinary(this);
|
2018-09-17 10:07:32 +03:00
|
|
|
|
}
|
|
|
|
|
|
2018-10-13 11:01:10 +03:00
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
public void buildLauncherBinaries() throws IOException {
|
|
|
|
|
launcherBinary.build();
|
|
|
|
|
launcherEXEBinary.build();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void close() {
|
|
|
|
|
|
|
|
|
|
// Close handlers & providers
|
2019-03-10 15:28:22 +03:00
|
|
|
|
config.close();
|
2018-09-17 10:07:32 +03:00
|
|
|
|
modulesManager.close();
|
2019-04-12 00:58:45 +03:00
|
|
|
|
LogHelper.info("Save LaunchServer runtime config");
|
2019-05-15 14:11:22 +03:00
|
|
|
|
try (Writer writer = IOHelper.newWriter(runtimeConfigFile)) {
|
|
|
|
|
if (Launcher.gsonManager.configGson != null) {
|
2019-04-20 01:03:06 +03:00
|
|
|
|
Launcher.gsonManager.configGson.toJson(runtime, writer);
|
2019-04-12 00:58:45 +03:00
|
|
|
|
} else {
|
|
|
|
|
LogHelper.error("Error writing LaunchServer runtime config file. Gson is null");
|
|
|
|
|
}
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
LogHelper.error(e);
|
|
|
|
|
}
|
2018-09-17 10:07:32 +03:00
|
|
|
|
// Print last message before death :(
|
|
|
|
|
LogHelper.info("LaunchServer stopped");
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-07 10:53:39 +03:00
|
|
|
|
private void generateConfigIfNotExists(boolean testEnv) throws IOException {
|
2018-09-17 10:07:32 +03:00
|
|
|
|
if (IOHelper.isFile(configFile))
|
2018-09-22 17:33:00 +03:00
|
|
|
|
return;
|
2018-09-17 10:07:32 +03:00
|
|
|
|
|
|
|
|
|
// Create new config
|
|
|
|
|
LogHelper.info("Creating LaunchServer config");
|
2018-12-23 19:47:07 +03:00
|
|
|
|
Config newConfig = new Config();
|
2019-07-04 12:19:07 +03:00
|
|
|
|
newConfig.mirrors = new String[]{"https://mirror.gravit.pro/"};
|
2018-12-23 19:47:07 +03:00
|
|
|
|
newConfig.launch4j = new ExeConf();
|
2019-04-28 15:20:51 +03:00
|
|
|
|
newConfig.launch4j.enabled = true;
|
2018-12-24 15:16:44 +03:00
|
|
|
|
newConfig.launch4j.copyright = "© GravitLauncher Team";
|
2019-07-12 16:43:56 +03:00
|
|
|
|
newConfig.launch4j.alternative = "no";
|
2019-05-03 17:06:22 +03:00
|
|
|
|
newConfig.launch4j.fileDesc = "GravitLauncher ".concat(Version.getVersion().getVersionString());
|
|
|
|
|
newConfig.launch4j.fileVer = Version.getVersion().getVersionString().concat(".").concat(String.valueOf(Version.getVersion().patch));
|
2018-12-24 15:16:44 +03:00
|
|
|
|
newConfig.launch4j.internalName = "Launcher";
|
|
|
|
|
newConfig.launch4j.trademarks = "This product is licensed under GPLv3";
|
|
|
|
|
newConfig.launch4j.txtFileVersion = "%s, build %d";
|
|
|
|
|
newConfig.launch4j.txtProductVersion = "%s, build %d";
|
2018-12-31 10:51:49 +03:00
|
|
|
|
newConfig.launch4j.productName = "GravitLauncher";
|
|
|
|
|
newConfig.launch4j.productVer = newConfig.launch4j.fileVer;
|
2019-05-26 05:57:22 +03:00
|
|
|
|
newConfig.launch4j.maxVersion = "1.8.999";
|
2018-12-23 19:47:07 +03:00
|
|
|
|
newConfig.env = LauncherConfig.LauncherEnvironment.STD;
|
2019-01-09 18:03:14 +03:00
|
|
|
|
newConfig.startScript = JVMHelper.OS_TYPE.equals(JVMHelper.OS.MUSTDIE) ? "." + File.separator + "start.bat" : "." + File.separator + "start.sh";
|
2018-12-23 20:19:43 +03:00
|
|
|
|
newConfig.hwidHandler = new AcceptHWIDHandler();
|
2019-04-03 16:27:40 +03:00
|
|
|
|
newConfig.auth = new AuthProviderPair[]{new AuthProviderPair(new RejectAuthProvider("Настройте authProvider"),
|
2019-03-22 09:14:29 +03:00
|
|
|
|
new MemoryAuthHandler(),
|
|
|
|
|
new RequestTextureProvider("http://example.com/skins/%username%.png", "http://example.com/cloaks/%username%.png")
|
2019-04-03 16:27:40 +03:00
|
|
|
|
, "std")};
|
2019-04-13 20:55:01 +03:00
|
|
|
|
newConfig.auth[0].displayName = "Default";
|
2019-06-07 01:23:33 +03:00
|
|
|
|
newConfig.protectHandler = new StdProtectHandler();
|
2019-04-07 10:53:39 +03:00
|
|
|
|
if (testEnv) newConfig.permissionsHandler = new DefaultPermissionsHandler();
|
|
|
|
|
else newConfig.permissionsHandler = new JsonFilePermissionsHandler();
|
2018-12-24 13:16:57 +03:00
|
|
|
|
newConfig.binaryName = "Launcher";
|
|
|
|
|
newConfig.whitelistRejectString = "Вас нет в белом списке";
|
2019-01-15 06:35:39 +03:00
|
|
|
|
|
2019-02-20 13:35:04 +03:00
|
|
|
|
newConfig.netty = new NettyConfig();
|
2019-04-28 15:06:12 +03:00
|
|
|
|
newConfig.netty.fileServerEnabled = true;
|
2019-05-15 14:11:22 +03:00
|
|
|
|
newConfig.netty.binds = new NettyBindAddress[]{new NettyBindAddress("0.0.0.0", 9274)};
|
2019-04-06 14:41:38 +03:00
|
|
|
|
newConfig.netty.performance = new NettyPerformanceConfig();
|
2019-07-01 14:34:03 +03:00
|
|
|
|
newConfig.netty.performance.usingEpoll = JVMHelper.OS_TYPE == JVMHelper.OS.LINUX; //Only linux
|
2019-04-06 14:41:38 +03:00
|
|
|
|
newConfig.netty.performance.bossThread = 2;
|
|
|
|
|
newConfig.netty.performance.workerThread = 8;
|
2019-02-20 13:35:04 +03:00
|
|
|
|
|
2019-04-12 23:51:15 +03:00
|
|
|
|
newConfig.launcher = new LauncherConf();
|
|
|
|
|
newConfig.launcher.guardType = "no";
|
2019-07-15 22:47:07 +03:00
|
|
|
|
newConfig.launcher.compress = true;
|
2019-04-12 23:51:15 +03:00
|
|
|
|
|
2019-05-03 10:06:11 +03:00
|
|
|
|
newConfig.genMappings = true;
|
2019-01-05 18:43:05 +03:00
|
|
|
|
newConfig.enabledProGuard = true;
|
2019-01-09 12:20:31 +03:00
|
|
|
|
newConfig.stripLineNumbers = true;
|
|
|
|
|
newConfig.deleteTempFiles = true;
|
2019-01-13 18:51:39 +03:00
|
|
|
|
newConfig.isWarningMissArchJava = true;
|
|
|
|
|
|
2019-03-13 12:49:28 +03:00
|
|
|
|
newConfig.components = new HashMap<>();
|
|
|
|
|
AuthLimiterComponent authLimiterComponent = new AuthLimiterComponent();
|
|
|
|
|
authLimiterComponent.rateLimit = 3;
|
|
|
|
|
authLimiterComponent.rateLimitMilis = 8000;
|
|
|
|
|
authLimiterComponent.message = "Превышен лимит авторизаций";
|
|
|
|
|
newConfig.components.put("authLimiter", authLimiterComponent);
|
2019-07-01 12:07:33 +03:00
|
|
|
|
RegLimiterComponent regLimiterComponent = new RegLimiterComponent();
|
|
|
|
|
regLimiterComponent.rateLimit = 3;
|
|
|
|
|
regLimiterComponent.rateLimitMilis = 1000 * 60 * 60 * 10; //Блок на 10 часов
|
|
|
|
|
regLimiterComponent.message = "Превышен лимит регистраций";
|
|
|
|
|
newConfig.components.put("regLimiter", regLimiterComponent);
|
2019-03-13 12:49:28 +03:00
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
// Set server address
|
2019-04-28 15:06:12 +03:00
|
|
|
|
String address;
|
2019-04-07 10:53:39 +03:00
|
|
|
|
if (testEnv) {
|
2019-05-15 14:11:22 +03:00
|
|
|
|
address = "localhost";
|
|
|
|
|
newConfig.setProjectName("test");
|
2019-04-07 10:53:39 +03:00
|
|
|
|
} else {
|
2019-05-15 14:11:22 +03:00
|
|
|
|
System.out.println("LaunchServer address(default: localhost): ");
|
|
|
|
|
address = commandHandler.readLine();
|
|
|
|
|
System.out.println("LaunchServer projectName: ");
|
|
|
|
|
newConfig.setProjectName(commandHandler.readLine());
|
2019-04-07 10:53:39 +03:00
|
|
|
|
}
|
2019-05-15 14:11:22 +03:00
|
|
|
|
if (address == null || address.isEmpty()) {
|
2019-04-28 15:06:12 +03:00
|
|
|
|
LogHelper.error("Address null. Using localhost");
|
|
|
|
|
address = "localhost";
|
2019-04-27 13:22:45 +03:00
|
|
|
|
}
|
2019-05-15 14:11:22 +03:00
|
|
|
|
if (newConfig.projectName == null || newConfig.projectName.isEmpty()) {
|
2019-04-27 13:22:45 +03:00
|
|
|
|
LogHelper.error("ProjectName null. Using MineCraft");
|
|
|
|
|
newConfig.projectName = "MineCraft";
|
|
|
|
|
}
|
2019-06-28 12:27:05 +03:00
|
|
|
|
|
2019-04-28 15:06:12 +03:00
|
|
|
|
newConfig.netty.address = "ws://" + address + ":9274/api";
|
|
|
|
|
newConfig.netty.downloadURL = "http://" + address + ":9274/%dirname%/";
|
2019-04-28 15:15:12 +03:00
|
|
|
|
newConfig.netty.launcherURL = "http://" + address + ":9274/Launcher.jar";
|
|
|
|
|
newConfig.netty.launcherEXEURL = "http://" + address + ":9274/Launcher.exe";
|
2019-04-28 15:06:12 +03:00
|
|
|
|
newConfig.netty.sendExceptionEnabled = true;
|
2018-09-17 10:07:32 +03:00
|
|
|
|
|
|
|
|
|
// Write LaunchServer config
|
|
|
|
|
LogHelper.info("Writing LaunchServer config file");
|
|
|
|
|
try (BufferedWriter writer = IOHelper.newWriter(configFile)) {
|
2019-04-20 01:03:06 +03:00
|
|
|
|
Launcher.gsonManager.configGson.toJson(newConfig, writer);
|
2018-09-17 10:07:32 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-07 10:53:39 +03:00
|
|
|
|
public List<ClientProfile> getProfiles() {
|
2018-09-17 10:07:32 +03:00
|
|
|
|
return profilesList;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-07 10:53:39 +03:00
|
|
|
|
public void setProfiles(List<ClientProfile> profilesList) {
|
|
|
|
|
this.profilesList = Collections.unmodifiableList(profilesList);
|
|
|
|
|
}
|
2018-10-13 11:01:10 +03:00
|
|
|
|
|
2019-07-12 02:10:31 +03:00
|
|
|
|
public HashedDir getUpdateDir(String name) {
|
2018-09-17 10:07:32 +03:00
|
|
|
|
return updatesDirMap.get(name);
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-13 11:01:10 +03:00
|
|
|
|
|
2019-07-12 02:10:31 +03:00
|
|
|
|
public Set<Entry<String, HashedDir>> getUpdateDirs() {
|
2018-09-17 10:07:32 +03:00
|
|
|
|
return updatesDirMap.entrySet();
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-29 18:42:31 +03:00
|
|
|
|
public void rebindNettyServerSocket() {
|
|
|
|
|
nettyServerSocketHandler.close();
|
|
|
|
|
CommonHelper.newThread("Netty Server Socket Thread", false, nettyServerSocketHandler).start();
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
@Override
|
|
|
|
|
public void run() {
|
|
|
|
|
if (started.getAndSet(true))
|
2018-09-22 17:33:00 +03:00
|
|
|
|
throw new IllegalStateException("LaunchServer has been already started");
|
2018-09-17 10:07:32 +03:00
|
|
|
|
|
|
|
|
|
// Add shutdown hook, then start LaunchServer
|
2019-04-07 10:53:39 +03:00
|
|
|
|
if (!this.testEnv) {
|
2019-05-15 14:11:22 +03:00
|
|
|
|
JVMHelper.RUNTIME.addShutdownHook(CommonHelper.newThread(null, false, this::close));
|
|
|
|
|
CommonHelper.newThread("Command Thread", true, commandHandler).start();
|
2019-04-07 10:53:39 +03:00
|
|
|
|
}
|
2019-04-03 16:27:40 +03:00
|
|
|
|
if (config.netty != null)
|
2019-01-29 18:42:31 +03:00
|
|
|
|
rebindNettyServerSocket();
|
2019-01-18 01:30:55 +03:00
|
|
|
|
modulesManager.finishModules();
|
2018-09-17 10:07:32 +03:00
|
|
|
|
}
|
|
|
|
|
|
2018-10-13 11:01:10 +03:00
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
public void syncLauncherBinaries() throws IOException {
|
|
|
|
|
LogHelper.info("Syncing launcher binaries");
|
|
|
|
|
|
|
|
|
|
// Syncing launcher binary
|
|
|
|
|
LogHelper.info("Syncing launcher binary file");
|
|
|
|
|
if (!launcherBinary.sync()) LogHelper.warning("Missing launcher binary file");
|
|
|
|
|
|
|
|
|
|
// Syncing launcher EXE binary
|
|
|
|
|
LogHelper.info("Syncing launcher EXE binary file");
|
|
|
|
|
if (!launcherEXEBinary.sync() && config.launch4j.enabled)
|
|
|
|
|
LogHelper.warning("Missing launcher EXE binary file");
|
|
|
|
|
|
|
|
|
|
}
|
2018-09-22 17:33:00 +03:00
|
|
|
|
|
2018-10-13 11:01:10 +03:00
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
public void syncProfilesDir() throws IOException {
|
|
|
|
|
LogHelper.info("Syncing profiles dir");
|
2018-12-23 18:57:40 +03:00
|
|
|
|
List<ClientProfile> newProfies = new LinkedList<>();
|
2018-09-17 10:07:32 +03:00
|
|
|
|
IOHelper.walk(profilesDir, new ProfilesFileVisitor(newProfies), false);
|
|
|
|
|
|
|
|
|
|
// Sort and set new profiles
|
2018-12-23 18:57:40 +03:00
|
|
|
|
newProfies.sort(Comparator.comparing(a -> a));
|
2018-09-17 10:07:32 +03:00
|
|
|
|
profilesList = Collections.unmodifiableList(newProfies);
|
|
|
|
|
}
|
2018-09-22 17:33:00 +03:00
|
|
|
|
|
2018-10-13 11:01:10 +03:00
|
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
|
public void syncUpdatesDir(Collection<String> dirs) throws IOException {
|
|
|
|
|
LogHelper.info("Syncing updates dir");
|
2019-07-12 02:10:31 +03:00
|
|
|
|
Map<String, HashedDir> newUpdatesDirMap = new HashMap<>(16);
|
2018-09-17 10:07:32 +03:00
|
|
|
|
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(updatesDir)) {
|
2019-04-28 15:06:12 +03:00
|
|
|
|
for (final Path updateDir : dirStream) {
|
2018-09-17 10:07:32 +03:00
|
|
|
|
if (Files.isHidden(updateDir))
|
2018-09-22 17:33:00 +03:00
|
|
|
|
continue; // Skip hidden
|
2018-09-17 10:07:32 +03:00
|
|
|
|
|
|
|
|
|
// Resolve name and verify is dir
|
|
|
|
|
String name = IOHelper.getFileName(updateDir);
|
|
|
|
|
if (!IOHelper.isDir(updateDir)) {
|
2019-05-15 14:11:22 +03:00
|
|
|
|
if (!IOHelper.isFile(updateDir) && Arrays.asList(".jar", ".exe", ".hash").stream().noneMatch(e -> updateDir.toString().endsWith(e)))
|
|
|
|
|
LogHelper.warning("Not update dir: '%s'", name);
|
2018-09-17 10:07:32 +03:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add from previous map (it's guaranteed to be non-null)
|
|
|
|
|
if (dirs != null && !dirs.contains(name)) {
|
2019-07-12 02:10:31 +03:00
|
|
|
|
HashedDir hdir = updatesDirMap.get(name);
|
2018-09-17 10:07:32 +03:00
|
|
|
|
if (hdir != null) {
|
|
|
|
|
newUpdatesDirMap.put(name, hdir);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sync and sign update dir
|
|
|
|
|
LogHelper.info("Syncing '%s' update dir", name);
|
|
|
|
|
HashedDir updateHDir = new HashedDir(updateDir, null, true, true);
|
2019-07-12 02:10:31 +03:00
|
|
|
|
newUpdatesDirMap.put(name, updateHDir);
|
2018-09-17 10:07:32 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
updatesDirMap = Collections.unmodifiableMap(newUpdatesDirMap);
|
|
|
|
|
}
|
2019-01-15 06:35:39 +03:00
|
|
|
|
|
2019-01-04 14:32:16 +03:00
|
|
|
|
public void restart() {
|
2019-01-15 06:35:39 +03:00
|
|
|
|
ProcessBuilder builder = new ProcessBuilder();
|
2019-01-16 11:52:47 +03:00
|
|
|
|
if (config.startScript != null) builder.command(Collections.singletonList(config.startScript));
|
2019-01-15 06:35:39 +03:00
|
|
|
|
else throw new IllegalArgumentException("Please create start script and link it as startScript in config.");
|
2019-01-04 14:32:16 +03:00
|
|
|
|
builder.directory(this.dir.toFile());
|
|
|
|
|
builder.inheritIO();
|
|
|
|
|
builder.redirectErrorStream(true);
|
|
|
|
|
builder.redirectOutput(Redirect.PIPE);
|
|
|
|
|
try {
|
2019-01-15 06:35:39 +03:00
|
|
|
|
builder.start();
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
LogHelper.error(e);
|
|
|
|
|
}
|
2019-01-04 14:32:16 +03:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-03 16:27:40 +03:00
|
|
|
|
public void registerObject(String name, Object object) {
|
|
|
|
|
if (object instanceof Reloadable) {
|
2019-04-03 13:09:53 +03:00
|
|
|
|
reloadManager.registerReloadable(name, (Reloadable) object);
|
|
|
|
|
}
|
2019-04-03 16:27:40 +03:00
|
|
|
|
if (object instanceof Reconfigurable) {
|
2019-04-03 13:09:53 +03:00
|
|
|
|
reconfigurableManager.registerReconfigurable(name, (Reconfigurable) object);
|
|
|
|
|
}
|
2019-04-03 16:27:40 +03:00
|
|
|
|
if (object instanceof NeedGarbageCollection) {
|
2019-04-03 13:09:53 +03:00
|
|
|
|
GarbageManager.registerNeedGC((NeedGarbageCollection) object);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-05-15 14:11:22 +03:00
|
|
|
|
|
2019-04-27 13:17:10 +03:00
|
|
|
|
public void unregisterObject(String name, Object object) {
|
|
|
|
|
if (object instanceof Reloadable) {
|
|
|
|
|
reloadManager.unregisterReloadable(name);
|
|
|
|
|
}
|
|
|
|
|
if (object instanceof Reconfigurable) {
|
|
|
|
|
reconfigurableManager.unregisterReconfigurable(name);
|
|
|
|
|
}
|
|
|
|
|
if (object instanceof NeedGarbageCollection) {
|
|
|
|
|
GarbageManager.unregisterNeedGC((NeedGarbageCollection) object);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-03 13:09:53 +03:00
|
|
|
|
|
2019-01-15 06:35:39 +03:00
|
|
|
|
public void fullyRestart() {
|
|
|
|
|
restart();
|
2019-01-04 14:32:16 +03:00
|
|
|
|
JVMHelper.RUNTIME.exit(0);
|
2019-01-15 06:35:39 +03:00
|
|
|
|
}
|
2018-09-17 10:07:32 +03:00
|
|
|
|
}
|