mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-12-23 09:01:08 +03:00
Merge branch 'release/5.0.7'
This commit is contained in:
commit
da6313e1cc
134 changed files with 3124 additions and 1548 deletions
|
@ -2,6 +2,7 @@ image: frekele/java
|
|||
|
||||
stages:
|
||||
- build
|
||||
- test
|
||||
- deploy
|
||||
|
||||
before_script:
|
||||
|
@ -11,6 +12,7 @@ before_script:
|
|||
- apt-get update -qq && apt-get install -y -qq git git-core
|
||||
|
||||
cache:
|
||||
key: ${CI_COMMIT_REF_NAME}
|
||||
paths:
|
||||
- .gradle/wrapper
|
||||
- .gradle/caches
|
||||
|
@ -22,11 +24,19 @@ build:
|
|||
- git submodule sync
|
||||
- git submodule update --init --recursive
|
||||
- ./gradlew assemble
|
||||
- mv LaunchServer/build/libs/*.jar LaunchServer
|
||||
- mv ServerWrapper/build/libs/*.jar ServerWrapper
|
||||
- mv modules/*_module/build/libs/*.jar modules
|
||||
artifacts:
|
||||
paths:
|
||||
- LaunchServer/build/libs/*
|
||||
- ServerWrapper/build/libs/*.jar
|
||||
- LaunchServer/*.jar
|
||||
- ServerWrapper/*.jar
|
||||
- modules/*.jar
|
||||
expire_in: 1 week
|
||||
test:
|
||||
stage: test
|
||||
script:
|
||||
- ./gradlew check
|
||||
|
||||
after_script:
|
||||
- echo "End CI"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
def mainClassName = "pro.gravit.launchserver.LaunchServer"
|
||||
def mainClassName = "pro.gravit.launchserver.LaunchServerStarter"
|
||||
def mainAgentName = "pro.gravit.launchserver.StarterAgent"
|
||||
|
||||
evaluationDependsOn(':Launcher')
|
||||
|
@ -40,6 +40,22 @@
|
|||
)
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
testLogging {
|
||||
events "passed", "skipped", "failed"
|
||||
}
|
||||
}
|
||||
|
||||
task sourcesJar(type: Jar) {
|
||||
from sourceSets.main.allJava
|
||||
archiveClassifier = 'sources'
|
||||
}
|
||||
|
||||
task javadocJar(type: Jar) {
|
||||
from javadoc
|
||||
archiveClassifier = 'javadoc'
|
||||
}
|
||||
|
||||
task cleanjar(type: Jar, dependsOn: jar) {
|
||||
classifier = 'clean'
|
||||
|
@ -98,6 +114,7 @@ pack project(':LauncherAPI')
|
|||
compileOnlyA 'com.google.guava:guava:26.0-jre'
|
||||
compileOnlyA 'log4j:log4j:1.2.17' // Do not update (laggy dep).
|
||||
compileOnlyA 'org.apache.logging.log4j:log4j-core:2.11.2'
|
||||
testCompile 'org.junit.jupiter:junit-jupiter:5.4.1'
|
||||
}
|
||||
|
||||
task hikari(type: Copy) {
|
||||
|
@ -167,7 +184,11 @@ task dumpClientLibs(type: Copy) {
|
|||
publications {
|
||||
launchserverapi(MavenPublication) {
|
||||
artifactId = 'launchserver-api'
|
||||
artifact cleanjar
|
||||
artifact(cleanjar) {
|
||||
classifier ""
|
||||
}
|
||||
artifact sourcesJar
|
||||
artifact javadocJar
|
||||
pom {
|
||||
name = 'GravitLauncher LaunchServer API'
|
||||
description = 'GravitLauncher LaunchServer Module API'
|
||||
|
@ -178,6 +199,18 @@ task dumpClientLibs(type: Copy) {
|
|||
url = 'https://www.gnu.org/licenses/gpl-3.0.html'
|
||||
}
|
||||
}
|
||||
developers {
|
||||
developer {
|
||||
id = 'gravit'
|
||||
name = 'Gravit'
|
||||
email = 'gravit.min@ya.ru'
|
||||
}
|
||||
developer {
|
||||
id = 'zaxar163'
|
||||
name = 'Zaxar163'
|
||||
email = 'zahar.vcherachny@yandex.ru'
|
||||
}
|
||||
}
|
||||
|
||||
scm {
|
||||
connection = 'scm:git:https://github.com/GravitLauncher/Launcher.git'
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
package pro.gravit.launchserver;
|
||||
|
||||
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;
|
||||
|
@ -33,301 +30,137 @@
|
|||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.zip.CRC32;
|
||||
|
||||
import io.netty.channel.epoll.Epoll;
|
||||
import org.bouncycastle.crypto.util.PrivateKeyFactory;
|
||||
import org.bouncycastle.operator.OperatorCreationException;
|
||||
|
||||
import io.netty.handler.logging.LogLevel;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.LauncherConfig;
|
||||
import pro.gravit.launcher.NeedGarbageCollection;
|
||||
import pro.gravit.launcher.hasher.HashedDir;
|
||||
import pro.gravit.launcher.hwid.HWIDProvider;
|
||||
import pro.gravit.launcher.managers.ConfigManager;
|
||||
import pro.gravit.launcher.managers.GarbageManager;
|
||||
import pro.gravit.launcher.modules.LauncherModulesManager;
|
||||
import pro.gravit.launcher.modules.events.ClosePhase;
|
||||
import pro.gravit.launcher.profiles.ClientProfile;
|
||||
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;
|
||||
import pro.gravit.launchserver.auth.protect.StdProtectHandler;
|
||||
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;
|
||||
import pro.gravit.launchserver.binary.EXEL4JLauncherBinary;
|
||||
import pro.gravit.launchserver.binary.EXELauncherBinary;
|
||||
import pro.gravit.launchserver.binary.JARLauncherBinary;
|
||||
import pro.gravit.launchserver.binary.LauncherBinary;
|
||||
import pro.gravit.launchserver.binary.ProguardConf;
|
||||
import pro.gravit.launchserver.binary.SimpleEXELauncherBinary;
|
||||
import pro.gravit.launchserver.components.AuthLimiterComponent;
|
||||
import pro.gravit.launchserver.components.Component;
|
||||
import pro.gravit.launchserver.components.RegLimiterComponent;
|
||||
import pro.gravit.launchserver.config.LaunchServerConfig;
|
||||
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
||||
import pro.gravit.launchserver.dao.provider.DaoProvider;
|
||||
import pro.gravit.launchserver.manangers.CertificateManager;
|
||||
import pro.gravit.launchserver.manangers.LaunchServerGsonManager;
|
||||
import pro.gravit.launchserver.manangers.MirrorManager;
|
||||
import pro.gravit.launchserver.manangers.ModulesManager;
|
||||
import pro.gravit.launchserver.manangers.ReconfigurableManager;
|
||||
import pro.gravit.launchserver.manangers.ReloadManager;
|
||||
import pro.gravit.launchserver.manangers.SessionManager;
|
||||
import pro.gravit.launchserver.manangers.*;
|
||||
import pro.gravit.launchserver.manangers.hook.AuthHookManager;
|
||||
import pro.gravit.launchserver.manangers.hook.BuildHookManager;
|
||||
import pro.gravit.launchserver.socket.WebSocketService;
|
||||
import pro.gravit.launchserver.modules.events.LaunchServerFullInitEvent;
|
||||
import pro.gravit.launchserver.modules.events.LaunchServerInitPhase;
|
||||
import pro.gravit.launchserver.modules.events.LaunchServerPostInitPhase;
|
||||
import pro.gravit.launchserver.modules.events.NewLaunchServerInstanceEvent;
|
||||
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
|
||||
import pro.gravit.launchserver.socket.handlers.NettyServerSocketHandler;
|
||||
import pro.gravit.utils.Version;
|
||||
import pro.gravit.utils.command.CommandHandler;
|
||||
import pro.gravit.utils.command.JLineCommandHandler;
|
||||
import pro.gravit.utils.command.StdCommandHandler;
|
||||
import pro.gravit.utils.command.*;
|
||||
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;
|
||||
|
||||
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)) {
|
||||
config = Launcher.gsonManager.gson.fromJson(reader, Config.class);
|
||||
}
|
||||
config.server = this;
|
||||
config.verify();
|
||||
config.init();
|
||||
}
|
||||
public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurable {
|
||||
|
||||
public static final class Config {
|
||||
private transient LaunchServer server = null;
|
||||
|
||||
public String projectName;
|
||||
|
||||
public String[] mirrors;
|
||||
|
||||
public String binaryName;
|
||||
|
||||
public boolean copyBinaries = true;
|
||||
|
||||
public LauncherConfig.LauncherEnvironment env;
|
||||
|
||||
// Handlers & Providers
|
||||
|
||||
public AuthProviderPair[] auth;
|
||||
|
||||
public DaoProvider dao;
|
||||
|
||||
private transient AuthProviderPair authDefault;
|
||||
|
||||
public AuthProviderPair getAuthProviderPair(String name) {
|
||||
for (AuthProviderPair pair : auth) {
|
||||
if (pair.name.equals(name)) return pair;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ProtectHandler protectHandler;
|
||||
|
||||
public PermissionsHandler permissionsHandler;
|
||||
|
||||
public AuthProviderPair getAuthProviderPair() {
|
||||
if (authDefault != null) return authDefault;
|
||||
for (AuthProviderPair pair : auth) {
|
||||
if (pair.isDefault) {
|
||||
authDefault = pair;
|
||||
return pair;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public HWIDHandler hwidHandler;
|
||||
|
||||
public Map<String, Component> components;
|
||||
|
||||
public ExeConf launch4j;
|
||||
public NettyConfig netty;
|
||||
public GuardLicenseConf guardLicense;
|
||||
|
||||
public String whitelistRejectString;
|
||||
public LauncherConf launcher;
|
||||
public CertificateConf certificate;
|
||||
|
||||
public String startScript;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
public void verify() {
|
||||
if (auth == null || auth[0] == null) {
|
||||
throw new NullPointerException("AuthHandler must not be null");
|
||||
}
|
||||
boolean isOneDefault = false;
|
||||
for (AuthProviderPair pair : auth) {
|
||||
if (pair.isDefault) {
|
||||
isOneDefault = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (protectHandler == null) {
|
||||
throw new NullPointerException("ProtectHandler must not be null");
|
||||
}
|
||||
if (!isOneDefault) {
|
||||
throw new IllegalStateException("No auth pairs declared by default.");
|
||||
}
|
||||
if (permissionsHandler == null) {
|
||||
throw new NullPointerException("PermissionsHandler must not be null");
|
||||
}
|
||||
if (env == null) {
|
||||
throw new NullPointerException("Env must not be null");
|
||||
}
|
||||
if (netty == null) {
|
||||
throw new NullPointerException("Netty must not be null");
|
||||
}
|
||||
}
|
||||
|
||||
public void init() {
|
||||
Launcher.applyLauncherEnv(env);
|
||||
for (AuthProviderPair provider : auth) {
|
||||
provider.init(server);
|
||||
}
|
||||
permissionsHandler.init(server);
|
||||
hwidHandler.init();
|
||||
dao.init(server);
|
||||
if (protectHandler != null) {
|
||||
protectHandler.checkLaunchServerLicense();
|
||||
}
|
||||
server.registerObject("permissionsHandler", permissionsHandler);
|
||||
server.registerObject("daoProvider", dao);
|
||||
for (AuthProviderPair pair : auth) {
|
||||
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);
|
||||
}
|
||||
|
||||
Arrays.stream(mirrors).forEach(server.mirrorManager::addMirror);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
try {
|
||||
server.unregisterObject("permissionsHandler", permissionsHandler);
|
||||
for (AuthProviderPair pair : auth) {
|
||||
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);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogHelper.error(e);
|
||||
}
|
||||
try {
|
||||
for (AuthProviderPair p : auth) p.close();
|
||||
} catch (IOException e) {
|
||||
LogHelper.error(e);
|
||||
}
|
||||
try {
|
||||
hwidHandler.close();
|
||||
} catch (Exception e) {
|
||||
LogHelper.error(e);
|
||||
}
|
||||
try {
|
||||
permissionsHandler.close();
|
||||
} catch (Exception e) {
|
||||
LogHelper.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class ExeConf {
|
||||
public boolean enabled;
|
||||
public String alternative;
|
||||
public boolean setMaxVersion;
|
||||
public String maxVersion;
|
||||
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;
|
||||
}
|
||||
|
||||
public static class CertificateConf
|
||||
public enum ReloadType
|
||||
{
|
||||
public boolean enabled;
|
||||
NO_AUTH,
|
||||
NO_COMPONENTS,
|
||||
FULL
|
||||
}
|
||||
public enum LaunchServerEnv
|
||||
{
|
||||
TEST,
|
||||
DEV,
|
||||
DEBUG,
|
||||
PRODUCTION
|
||||
}
|
||||
public interface LaunchServerConfigManager
|
||||
{
|
||||
LaunchServerConfig readConfig() throws IOException;
|
||||
LaunchServerRuntimeConfig readRuntimeConfig() throws IOException;
|
||||
void writeConfig(LaunchServerConfig config) throws IOException;
|
||||
void writeRuntimeConfig(LaunchServerRuntimeConfig config) throws IOException;
|
||||
}
|
||||
|
||||
public static class NettyUpdatesBind {
|
||||
public String url;
|
||||
public boolean zip;
|
||||
}
|
||||
|
||||
public class LauncherConf {
|
||||
public String guardType;
|
||||
public boolean attachLibraryBeforeProGuard;
|
||||
public boolean compress;
|
||||
public boolean warningMissArchJava;
|
||||
public boolean enabledProGuard;
|
||||
public boolean stripLineNumbers;
|
||||
public boolean deleteTempFiles;
|
||||
public boolean proguardGenMappings;
|
||||
}
|
||||
|
||||
public class NettyConfig {
|
||||
public boolean fileServerEnabled;
|
||||
public boolean sendExceptionEnabled;
|
||||
public boolean ipForwarding;
|
||||
public String launcherURL;
|
||||
public String downloadURL;
|
||||
public String launcherEXEURL;
|
||||
public String address;
|
||||
public Map<String, NettyUpdatesBind> bindings = new HashMap<>();
|
||||
public NettyPerformanceConfig performance;
|
||||
public NettyBindAddress[] binds;
|
||||
public LogLevel logLevel = LogLevel.DEBUG;
|
||||
}
|
||||
|
||||
public class NettyPerformanceConfig {
|
||||
public boolean usingEpoll;
|
||||
public int bossThread;
|
||||
public int workerThread;
|
||||
}
|
||||
|
||||
public class NettyBindAddress {
|
||||
public String address;
|
||||
public int port;
|
||||
|
||||
public NettyBindAddress(String address, int port) {
|
||||
this.address = address;
|
||||
this.port = port;
|
||||
public void reload(ReloadType type) throws Exception {
|
||||
config.close(type);
|
||||
AuthProviderPair[] pairs = null;
|
||||
if(type.equals(ReloadType.NO_AUTH))
|
||||
{
|
||||
pairs = config.auth;
|
||||
}
|
||||
LogHelper.info("Reading LaunchServer config file");
|
||||
config = launchServerConfigManager.readConfig();
|
||||
config.setLaunchServer(this);
|
||||
if(type.equals(ReloadType.NO_AUTH))
|
||||
{
|
||||
config.auth = pairs;
|
||||
}
|
||||
config.verify();
|
||||
config.init(type);
|
||||
if (type.equals(ReloadType.FULL) && config.components != null) {
|
||||
LogHelper.debug("PreInit components");
|
||||
config.components.forEach((k, v) -> {
|
||||
LogHelper.subDebug("PreInit component %s", k);
|
||||
v.preInit(this);
|
||||
});
|
||||
LogHelper.debug("PreInit components successful");
|
||||
LogHelper.debug("Init components");
|
||||
config.components.forEach((k, v) -> {
|
||||
LogHelper.subDebug("Init component %s", k);
|
||||
registerObject("component.".concat(k), v);
|
||||
v.init(this);
|
||||
});
|
||||
LogHelper.debug("Init components successful");
|
||||
LogHelper.debug("PostInit components");
|
||||
config.components.forEach((k, v) -> {
|
||||
LogHelper.subDebug("PostInit component %s", k);
|
||||
v.postInit(this);
|
||||
});
|
||||
LogHelper.debug("PostInit components successful");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class GuardLicenseConf {
|
||||
public String name;
|
||||
public String key;
|
||||
public String encryptKey;
|
||||
@Override
|
||||
public Map<String, Command> getCommands() {
|
||||
Map<String, Command> commands = new HashMap<>();
|
||||
SubCommand reload = new SubCommand() {
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
if(args.length == 0)
|
||||
{
|
||||
reload(ReloadType.FULL);
|
||||
return;
|
||||
}
|
||||
switch (args[0])
|
||||
{
|
||||
case "full":
|
||||
reload(ReloadType.FULL);
|
||||
break;
|
||||
case "no_auth":
|
||||
reload(ReloadType.NO_AUTH);
|
||||
break;
|
||||
case "no_components":
|
||||
reload(ReloadType.NO_COMPONENTS);
|
||||
break;
|
||||
default:
|
||||
reload(ReloadType.FULL);;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
commands.put("reload", reload);
|
||||
return commands;
|
||||
}
|
||||
|
||||
|
||||
private final class ProfilesFileVisitor extends SimpleFileVisitor<Path> {
|
||||
private final Collection<ClientProfile> result;
|
||||
|
||||
|
@ -352,53 +185,16 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
|
|||
}
|
||||
}
|
||||
|
||||
public static void main(String... args) throws Throwable {
|
||||
JVMHelper.checkStackTrace(LaunchServer.class);
|
||||
JVMHelper.verifySystemProperties(LaunchServer.class, true);
|
||||
LogHelper.addOutput(IOHelper.WORKING_DIR.resolve("LaunchServer.log"));
|
||||
LogHelper.printVersion("LaunchServer");
|
||||
LogHelper.printLicense("LaunchServer");
|
||||
if (!StarterAgent.isAgentStarted()) {
|
||||
LogHelper.error("StarterAgent is not started!");
|
||||
LogHelper.error("You should add to JVM options this option: `-javaagent:LaunchServer.jar`");
|
||||
}
|
||||
|
||||
// Start LaunchServer
|
||||
long startTime = System.currentTimeMillis();
|
||||
try {
|
||||
@SuppressWarnings("resource")
|
||||
LaunchServer launchserver = new LaunchServer(IOHelper.WORKING_DIR, false, args);
|
||||
if (args.length == 0) launchserver.run();
|
||||
else { //Обработка команды
|
||||
launchserver.commandHandler.eval(args, false);
|
||||
}
|
||||
} catch (Throwable exc) {
|
||||
LogHelper.error(exc);
|
||||
return;
|
||||
}
|
||||
long endTime = System.currentTimeMillis();
|
||||
LogHelper.debug("LaunchServer started in %dms", endTime - startTime);
|
||||
}
|
||||
|
||||
// Constant paths
|
||||
|
||||
public final Path dir;
|
||||
|
||||
public final boolean testEnv;
|
||||
public final LaunchServerEnv env;
|
||||
|
||||
public final Path launcherLibraries;
|
||||
|
||||
public final Path launcherLibrariesCompile;
|
||||
|
||||
public final List<String> args;
|
||||
|
||||
public final Path configFile;
|
||||
public final Path runtimeConfigFile;
|
||||
|
||||
public final Path publicKeyFile;
|
||||
|
||||
public final Path privateKeyFile;
|
||||
|
||||
public final Path caCertFile;
|
||||
|
||||
public final Path caKeyFile;
|
||||
|
@ -409,12 +205,14 @@ public static void main(String... args) throws Throwable {
|
|||
|
||||
public final Path updatesDir;
|
||||
|
||||
public final LaunchServerConfigManager launchServerConfigManager;
|
||||
|
||||
//public static LaunchServer server = null;
|
||||
|
||||
public final Path profilesDir;
|
||||
// Server config
|
||||
|
||||
public Config config;
|
||||
public LaunchServerConfig config;
|
||||
public LaunchServerRuntimeConfig runtime;
|
||||
|
||||
|
||||
|
@ -435,12 +233,10 @@ public static void main(String... args) throws Throwable {
|
|||
public final AuthHookManager authHookManager;
|
||||
// Server
|
||||
|
||||
public final ModulesManager modulesManager;
|
||||
public final LaunchServerModulesManager modulesManager;
|
||||
|
||||
public final MirrorManager mirrorManager;
|
||||
|
||||
public final ReloadManager reloadManager;
|
||||
|
||||
public final ReconfigurableManager reconfigurableManager;
|
||||
|
||||
public final ConfigManager configManager;
|
||||
|
@ -467,33 +263,35 @@ public static void main(String... args) throws Throwable {
|
|||
|
||||
public static Class<? extends LauncherBinary> defaultLauncherEXEBinaryClass = null;
|
||||
|
||||
public LaunchServer(Path dir, boolean testEnv, String[] args) throws IOException, InvalidKeySpecException {
|
||||
this.dir = dir;
|
||||
this.testEnv = testEnv;
|
||||
public static class LaunchServerDirectories
|
||||
{
|
||||
public Path updatesDir;
|
||||
public Path profilesDir;
|
||||
public Path dir;
|
||||
public void collect()
|
||||
{
|
||||
if(updatesDir == null) updatesDir = dir.resolve("updates");
|
||||
if(profilesDir == null) profilesDir = dir.resolve("profiles");
|
||||
}
|
||||
}
|
||||
|
||||
public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, LaunchServerConfig config, LaunchServerRuntimeConfig runtimeConfig, LaunchServerConfigManager launchServerConfigManager, LaunchServerModulesManager modulesManager, RSAPublicKey publicKey, RSAPrivateKey privateKey, CommandHandler commandHandler) throws IOException, InvalidKeySpecException {
|
||||
this.dir = directories.dir;
|
||||
this.env = env;
|
||||
this.config = config;
|
||||
this.launchServerConfigManager = launchServerConfigManager;
|
||||
this.modulesManager = modulesManager;
|
||||
this.profilesDir = directories.profilesDir;
|
||||
this.updatesDir = directories.updatesDir;
|
||||
this.publicKey = publicKey;
|
||||
this.privateKey = privateKey;
|
||||
this.commandHandler = commandHandler;
|
||||
this.runtime = runtimeConfig;
|
||||
taskPool = new Timer("Timered task worker thread", true);
|
||||
launcherLibraries = dir.resolve("launcher-libraries");
|
||||
launcherLibrariesCompile = dir.resolve("launcher-libraries-compile");
|
||||
this.args = Arrays.asList(args);
|
||||
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");
|
||||
}
|
||||
publicKeyFile = dir.resolve("public.key");
|
||||
privateKeyFile = dir.resolve("private.key");
|
||||
updatesDir = dir.resolve("updates");
|
||||
profilesDir = dir.resolve("profiles");
|
||||
|
||||
config.setLaunchServer(this);
|
||||
|
||||
caCertFile = dir.resolve("ca.crt");
|
||||
caKeyFile = dir.resolve("ca.key");
|
||||
|
@ -501,54 +299,7 @@ public LaunchServer(Path dir, boolean testEnv, String[] args) throws IOException
|
|||
serverCertFile = dir.resolve("server.crt");
|
||||
serverKeyFile = dir.resolve("server.key");
|
||||
|
||||
//Registration handlers and providers
|
||||
AuthHandler.registerHandlers();
|
||||
AuthProvider.registerProviders();
|
||||
TextureProvider.registerProviders();
|
||||
HWIDHandler.registerHandlers();
|
||||
PermissionsHandler.registerHandlers();
|
||||
Component.registerComponents();
|
||||
ProtectHandler.registerHandlers();
|
||||
WebSocketService.registerResponses();
|
||||
HWIDProvider.registerHWIDs();
|
||||
DaoProvider.registerProviders();
|
||||
//LaunchServer.server = this;
|
||||
|
||||
// Set command handler
|
||||
CommandHandler localCommandHandler;
|
||||
if (testEnv)
|
||||
localCommandHandler = new StdCommandHandler(false);
|
||||
else
|
||||
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");
|
||||
}
|
||||
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()))
|
||||
throw new IOException("Private and public key modulus mismatch");
|
||||
} else {
|
||||
LogHelper.info("Generating RSA keypair");
|
||||
KeyPair pair = SecurityHelper.genRSAKeyPair();
|
||||
publicKey = (RSAPublicKey) pair.getPublic();
|
||||
privateKey = (RSAPrivateKey) pair.getPrivate();
|
||||
|
||||
// Write key pair list
|
||||
LogHelper.info("Writing RSA keypair list");
|
||||
IOHelper.write(publicKeyFile, publicKey.getEncoded());
|
||||
IOHelper.write(privateKeyFile, privateKey.getEncoded());
|
||||
}
|
||||
modulesManager.invokeEvent(new NewLaunchServerInstanceEvent(this));
|
||||
|
||||
// Print keypair fingerprints
|
||||
CRC32 crc = new CRC32();
|
||||
|
@ -558,42 +309,8 @@ public LaunchServer(Path dir, boolean testEnv, String[] args) throws IOException
|
|||
// Load class bindings.
|
||||
launcherEXEBinaryClass = defaultLauncherEXEBinaryClass;
|
||||
|
||||
// pre init modules
|
||||
modulesManager = new ModulesManager(this);
|
||||
modulesManager.autoload(dir.resolve("modules"));
|
||||
modulesManager.preInitModules();
|
||||
initGson();
|
||||
|
||||
// Read LaunchServer config
|
||||
generateConfigIfNotExists(testEnv);
|
||||
LogHelper.info("Reading LaunchServer config file");
|
||||
try (BufferedReader reader = IOHelper.newReader(configFile)) {
|
||||
config = Launcher.gsonManager.gson.fromJson(reader, Config.class);
|
||||
}
|
||||
config.server = this;
|
||||
if (!Files.exists(runtimeConfigFile)) {
|
||||
LogHelper.info("Reset LaunchServer runtime config file");
|
||||
runtime = new LaunchServerRuntimeConfig();
|
||||
runtime.reset();
|
||||
} else {
|
||||
LogHelper.info("Reading LaunchServer runtime config file");
|
||||
try (BufferedReader reader = IOHelper.newReader(runtimeConfigFile)) {
|
||||
runtime = Launcher.gsonManager.gson.fromJson(reader, LaunchServerRuntimeConfig.class);
|
||||
}
|
||||
}
|
||||
runtime.verify();
|
||||
config.verify();
|
||||
Launcher.applyLauncherEnv(config.env);
|
||||
for (AuthProviderPair provider : config.auth) {
|
||||
provider.init(this);
|
||||
}
|
||||
config.permissionsHandler.init(this);
|
||||
config.hwidHandler.init();
|
||||
if(config.dao != null)
|
||||
config.dao.init(this);
|
||||
if (config.protectHandler != null) {
|
||||
config.protectHandler.checkLaunchServerLicense();
|
||||
}
|
||||
if (config.components != null) {
|
||||
LogHelper.debug("PreInit components");
|
||||
config.components.forEach((k, v) -> {
|
||||
|
@ -608,7 +325,6 @@ public LaunchServer(Path dir, boolean testEnv, String[] args) throws IOException
|
|||
proguardConf = new ProguardConf(this);
|
||||
sessionManager = new SessionManager();
|
||||
mirrorManager = new MirrorManager();
|
||||
reloadManager = new ReloadManager();
|
||||
reconfigurableManager = new ReconfigurableManager();
|
||||
authHookManager = new AuthHookManager();
|
||||
configManager = new ConfigManager();
|
||||
|
@ -650,27 +366,18 @@ public LaunchServer(Path dir, boolean testEnv, String[] args) throws IOException
|
|||
}
|
||||
}
|
||||
}
|
||||
config.init(ReloadType.FULL);
|
||||
registerObject("launchServer", this);
|
||||
GarbageManager.registerNeedGC(sessionManager);
|
||||
reloadManager.registerReloadable("launchServer", this);
|
||||
registerObject("permissionsHandler", config.permissionsHandler);
|
||||
for (int i = 0; i < config.auth.length; ++i) {
|
||||
AuthProviderPair pair = config.auth[i];
|
||||
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);
|
||||
}
|
||||
|
||||
Arrays.stream(config.mirrors).forEach(mirrorManager::addMirror);
|
||||
|
||||
pro.gravit.launchserver.command.handler.CommandHandler.registerCommands(localCommandHandler, this);
|
||||
pro.gravit.launchserver.command.handler.CommandHandler.registerCommands(commandHandler, this);
|
||||
|
||||
// init modules
|
||||
modulesManager.initModules();
|
||||
modulesManager.invokeEvent(new LaunchServerInitPhase(this));
|
||||
if (config.components != null) {
|
||||
LogHelper.debug("Init components");
|
||||
config.components.forEach((k, v) -> {
|
||||
LogHelper.subDebug("Init component %s", k);
|
||||
registerObject("component.".concat(k), v);
|
||||
v.init(this);
|
||||
});
|
||||
LogHelper.debug("Init components successful");
|
||||
|
@ -695,7 +402,7 @@ public LaunchServer(Path dir, boolean testEnv, String[] args) throws IOException
|
|||
syncProfilesDir();
|
||||
|
||||
// post init modules
|
||||
modulesManager.postInitModules();
|
||||
modulesManager.invokeEvent(new LaunchServerPostInitPhase(this));
|
||||
if (config.components != null) {
|
||||
LogHelper.debug("PostInit components");
|
||||
config.components.forEach((k, v) -> {
|
||||
|
@ -711,11 +418,6 @@ public LaunchServer(Path dir, boolean testEnv, String[] args) throws IOException
|
|||
nettyServerSocketHandler = null;
|
||||
}
|
||||
|
||||
public static void initGson() {
|
||||
Launcher.gsonManager = new LaunchServerGsonManager();
|
||||
Launcher.gsonManager.initGson();
|
||||
}
|
||||
|
||||
private LauncherBinary binary() {
|
||||
if (launcherEXEBinaryClass != null) {
|
||||
try {
|
||||
|
@ -753,126 +455,17 @@ public void buildLauncherBinaries() throws IOException {
|
|||
launcherEXEBinary.build();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
public void close() throws Exception {
|
||||
|
||||
// Close handlers & providers
|
||||
config.close();
|
||||
modulesManager.close();
|
||||
config.close(ReloadType.FULL);
|
||||
modulesManager.invokeEvent(new ClosePhase());
|
||||
LogHelper.info("Save LaunchServer runtime config");
|
||||
try (Writer writer = IOHelper.newWriter(runtimeConfigFile)) {
|
||||
if (Launcher.gsonManager.configGson != null) {
|
||||
Launcher.gsonManager.configGson.toJson(runtime, writer);
|
||||
} else {
|
||||
LogHelper.error("Error writing LaunchServer runtime config file. Gson is null");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LogHelper.error(e);
|
||||
}
|
||||
launchServerConfigManager.writeRuntimeConfig(runtime);
|
||||
// Print last message before death :(
|
||||
LogHelper.info("LaunchServer stopped");
|
||||
}
|
||||
|
||||
private void generateConfigIfNotExists(boolean testEnv) throws IOException {
|
||||
if (IOHelper.isFile(configFile))
|
||||
return;
|
||||
|
||||
// Create new config
|
||||
LogHelper.info("Creating LaunchServer config");
|
||||
Config newConfig = new Config();
|
||||
newConfig.mirrors = new String[]{"https://mirror.gravit.pro/"};
|
||||
newConfig.launch4j = new ExeConf();
|
||||
newConfig.launch4j.enabled = true;
|
||||
newConfig.launch4j.copyright = "© GravitLauncher Team";
|
||||
newConfig.launch4j.alternative = "no";
|
||||
newConfig.launch4j.fileDesc = "GravitLauncher ".concat(Version.getVersion().getVersionString());
|
||||
newConfig.launch4j.fileVer = Version.getVersion().getVersionString().concat(".").concat(String.valueOf(Version.getVersion().patch));
|
||||
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";
|
||||
newConfig.launch4j.productName = "GravitLauncher";
|
||||
newConfig.launch4j.productVer = newConfig.launch4j.fileVer;
|
||||
newConfig.launch4j.maxVersion = "1.8.999";
|
||||
newConfig.env = LauncherConfig.LauncherEnvironment.STD;
|
||||
newConfig.startScript = JVMHelper.OS_TYPE.equals(JVMHelper.OS.MUSTDIE) ? "." + File.separator + "start.bat" : "." + File.separator + "start.sh";
|
||||
newConfig.hwidHandler = new AcceptHWIDHandler();
|
||||
newConfig.auth = new AuthProviderPair[]{new AuthProviderPair(new RejectAuthProvider("Настройте authProvider"),
|
||||
new MemoryAuthHandler(),
|
||||
new RequestTextureProvider("http://example.com/skins/%username%.png", "http://example.com/cloaks/%username%.png")
|
||||
, "std")};
|
||||
newConfig.auth[0].displayName = "Default";
|
||||
newConfig.protectHandler = new StdProtectHandler();
|
||||
if (testEnv) newConfig.permissionsHandler = new DefaultPermissionsHandler();
|
||||
else newConfig.permissionsHandler = new JsonFilePermissionsHandler();
|
||||
newConfig.binaryName = "Launcher";
|
||||
newConfig.whitelistRejectString = "Вас нет в белом списке";
|
||||
|
||||
newConfig.netty = new NettyConfig();
|
||||
newConfig.netty.fileServerEnabled = true;
|
||||
newConfig.netty.binds = new NettyBindAddress[]{new NettyBindAddress("0.0.0.0", 9274)};
|
||||
newConfig.netty.performance = new NettyPerformanceConfig();
|
||||
newConfig.netty.performance.usingEpoll = Epoll.isAvailable();
|
||||
newConfig.netty.performance.bossThread = 2;
|
||||
newConfig.netty.performance.workerThread = 8;
|
||||
|
||||
newConfig.launcher = new LauncherConf();
|
||||
newConfig.launcher.guardType = "no";
|
||||
newConfig.launcher.compress = true;
|
||||
newConfig.launcher.warningMissArchJava = true;
|
||||
newConfig.launcher.attachLibraryBeforeProGuard = false;
|
||||
newConfig.launcher.deleteTempFiles = true;
|
||||
newConfig.launcher.enabledProGuard = true;
|
||||
newConfig.launcher.stripLineNumbers = true;
|
||||
newConfig.launcher.proguardGenMappings = true;
|
||||
|
||||
newConfig.certificate = new CertificateConf();
|
||||
newConfig.certificate.enabled = false;
|
||||
|
||||
newConfig.components = new HashMap<>();
|
||||
AuthLimiterComponent authLimiterComponent = new AuthLimiterComponent();
|
||||
authLimiterComponent.rateLimit = 3;
|
||||
authLimiterComponent.rateLimitMilis = 8000;
|
||||
authLimiterComponent.message = "Превышен лимит авторизаций";
|
||||
newConfig.components.put("authLimiter", authLimiterComponent);
|
||||
RegLimiterComponent regLimiterComponent = new RegLimiterComponent();
|
||||
regLimiterComponent.rateLimit = 3;
|
||||
regLimiterComponent.rateLimitMilis = 1000 * 60 * 60 * 10; //Блок на 10 часов
|
||||
regLimiterComponent.message = "Превышен лимит регистраций";
|
||||
newConfig.components.put("regLimiter", regLimiterComponent);
|
||||
|
||||
// Set server address
|
||||
String address;
|
||||
if (testEnv) {
|
||||
address = "localhost";
|
||||
newConfig.setProjectName("test");
|
||||
} else {
|
||||
System.out.println("LaunchServer address(default: localhost): ");
|
||||
address = commandHandler.readLine();
|
||||
System.out.println("LaunchServer projectName: ");
|
||||
newConfig.setProjectName(commandHandler.readLine());
|
||||
}
|
||||
if (address == null || address.isEmpty()) {
|
||||
LogHelper.error("Address null. Using localhost");
|
||||
address = "localhost";
|
||||
}
|
||||
if (newConfig.projectName == null || newConfig.projectName.isEmpty()) {
|
||||
LogHelper.error("ProjectName null. Using MineCraft");
|
||||
newConfig.projectName = "MineCraft";
|
||||
}
|
||||
|
||||
newConfig.netty.address = "ws://" + address + ":9274/api";
|
||||
newConfig.netty.downloadURL = "http://" + address + ":9274/%dirname%/";
|
||||
newConfig.netty.launcherURL = "http://" + address + ":9274/Launcher.jar";
|
||||
newConfig.netty.launcherEXEURL = "http://" + address + ":9274/Launcher.exe";
|
||||
newConfig.netty.sendExceptionEnabled = true;
|
||||
|
||||
// Write LaunchServer config
|
||||
LogHelper.info("Writing LaunchServer config file");
|
||||
try (BufferedWriter writer = IOHelper.newWriter(configFile)) {
|
||||
Launcher.gsonManager.configGson.toJson(newConfig, writer);
|
||||
}
|
||||
}
|
||||
|
||||
public List<ClientProfile> getProfiles() {
|
||||
return profilesList;
|
||||
}
|
||||
|
@ -901,13 +494,20 @@ public void run() {
|
|||
throw new IllegalStateException("LaunchServer has been already started");
|
||||
|
||||
// Add shutdown hook, then start LaunchServer
|
||||
if (!this.testEnv) {
|
||||
JVMHelper.RUNTIME.addShutdownHook(CommonHelper.newThread(null, false, this::close));
|
||||
if (!this.env.equals(LaunchServerEnv.TEST)) {
|
||||
JVMHelper.RUNTIME.addShutdownHook(CommonHelper.newThread(null, false, () -> {
|
||||
try {
|
||||
close();
|
||||
} catch (Exception e) {
|
||||
LogHelper.error(e);
|
||||
}
|
||||
}));
|
||||
CommonHelper.newThread("Command Thread", true, commandHandler).start();
|
||||
}
|
||||
if (config.netty != null)
|
||||
rebindNettyServerSocket();
|
||||
modulesManager.finishModules();
|
||||
modulesManager.fullInitializedLaunchServer(this);
|
||||
modulesManager.invokeEvent(new LaunchServerFullInitEvent(this));
|
||||
}
|
||||
|
||||
|
||||
|
@ -987,9 +587,6 @@ public void restart() {
|
|||
}
|
||||
|
||||
public void registerObject(String name, Object object) {
|
||||
if (object instanceof Reloadable) {
|
||||
reloadManager.registerReloadable(name, (Reloadable) object);
|
||||
}
|
||||
if (object instanceof Reconfigurable) {
|
||||
reconfigurableManager.registerReconfigurable(name, (Reconfigurable) object);
|
||||
}
|
||||
|
@ -999,9 +596,6 @@ public void registerObject(String name, Object object) {
|
|||
}
|
||||
|
||||
public void unregisterObject(String name, Object object) {
|
||||
if (object instanceof Reloadable) {
|
||||
reloadManager.unregisterReloadable(name);
|
||||
}
|
||||
if (object instanceof Reconfigurable) {
|
||||
reconfigurableManager.unregisterReconfigurable(name);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
package pro.gravit.launchserver;
|
||||
|
||||
import pro.gravit.launchserver.config.LaunchServerConfig;
|
||||
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
||||
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
|
||||
import pro.gravit.utils.command.CommandHandler;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
|
||||
public class LaunchServerBuilder {
|
||||
private LaunchServerConfig config;
|
||||
private LaunchServerRuntimeConfig runtimeConfig;
|
||||
private CommandHandler commandHandler;
|
||||
private LaunchServer.LaunchServerEnv env;
|
||||
private LaunchServerModulesManager modulesManager;
|
||||
private LaunchServer.LaunchServerDirectories directories = new LaunchServer.LaunchServerDirectories();
|
||||
private RSAPublicKey publicKey;
|
||||
private RSAPrivateKey privateKey;
|
||||
private LaunchServer.LaunchServerConfigManager launchServerConfigManager;
|
||||
|
||||
public LaunchServerBuilder setConfig(LaunchServerConfig config) {
|
||||
this.config = config;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LaunchServerBuilder setEnv(LaunchServer.LaunchServerEnv env) {
|
||||
this.env = env;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LaunchServerBuilder setModulesManager(LaunchServerModulesManager modulesManager) {
|
||||
this.modulesManager = modulesManager;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LaunchServerBuilder setRuntimeConfig(LaunchServerRuntimeConfig runtimeConfig) {
|
||||
this.runtimeConfig = runtimeConfig;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LaunchServerBuilder setCommandHandler(CommandHandler commandHandler) {
|
||||
this.commandHandler = commandHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LaunchServerBuilder setDirectories(LaunchServer.LaunchServerDirectories directories) {
|
||||
this.directories = directories;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LaunchServerBuilder setDir(Path dir) {
|
||||
this.directories.dir = dir;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LaunchServerBuilder setPublicKey(RSAPublicKey publicKey) {
|
||||
this.publicKey = publicKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LaunchServerBuilder setPrivateKey(RSAPrivateKey privateKey) {
|
||||
this.privateKey = privateKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LaunchServerBuilder setLaunchServerConfigManager(LaunchServer.LaunchServerConfigManager launchServerConfigManager) {
|
||||
this.launchServerConfigManager = launchServerConfigManager;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LaunchServer build() throws Exception
|
||||
{
|
||||
//if(updatesDir == null) updatesDir = dir.resolve("updates");
|
||||
//if(profilesDir == null) profilesDir = dir.resolve("profiles");
|
||||
directories.collect();
|
||||
if(launchServerConfigManager == null)
|
||||
{
|
||||
launchServerConfigManager = new LaunchServer.LaunchServerConfigManager() {
|
||||
@Override
|
||||
public LaunchServerConfig readConfig() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LaunchServerRuntimeConfig readRuntimeConfig() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeConfig(LaunchServerConfig config) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeRuntimeConfig(LaunchServerRuntimeConfig config) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
return new LaunchServer(directories, env, config, runtimeConfig, launchServerConfigManager, modulesManager, publicKey, privateKey, commandHandler);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,235 @@
|
|||
package pro.gravit.launchserver;
|
||||
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.hwid.HWIDProvider;
|
||||
import pro.gravit.launcher.modules.events.PreConfigPhase;
|
||||
import pro.gravit.launchserver.auth.handler.AuthHandler;
|
||||
import pro.gravit.launchserver.auth.hwid.HWIDHandler;
|
||||
import pro.gravit.launchserver.auth.permissions.PermissionsHandler;
|
||||
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
||||
import pro.gravit.launchserver.auth.provider.AuthProvider;
|
||||
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
||||
import pro.gravit.launchserver.components.Component;
|
||||
import pro.gravit.launchserver.config.LaunchServerConfig;
|
||||
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
||||
import pro.gravit.launchserver.dao.provider.DaoProvider;
|
||||
import pro.gravit.launchserver.manangers.LaunchServerGsonManager;
|
||||
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
|
||||
import pro.gravit.launchserver.socket.WebSocketService;
|
||||
import pro.gravit.utils.command.CommandHandler;
|
||||
import pro.gravit.utils.command.JLineCommandHandler;
|
||||
import pro.gravit.utils.command.StdCommandHandler;
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
import pro.gravit.utils.helper.JVMHelper;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
import pro.gravit.utils.helper.SecurityHelper;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.KeyPair;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
|
||||
public class LaunchServerStarter {
|
||||
public static void main(String[] args) throws Exception {
|
||||
JVMHelper.checkStackTrace(LaunchServerStarter.class);
|
||||
JVMHelper.verifySystemProperties(LaunchServer.class, true);
|
||||
LogHelper.addOutput(IOHelper.WORKING_DIR.resolve("LaunchServer.log"));
|
||||
LogHelper.printVersion("LaunchServer");
|
||||
LogHelper.printLicense("LaunchServer");
|
||||
if (!StarterAgent.isAgentStarted()) {
|
||||
LogHelper.error("StarterAgent is not started!");
|
||||
LogHelper.error("You should add to JVM options this option: `-javaagent:LaunchServer.jar`");
|
||||
}
|
||||
|
||||
Path dir = IOHelper.WORKING_DIR;
|
||||
Path configFile, runtimeConfigFile;
|
||||
Path publicKeyFile =dir.resolve("public.key");
|
||||
Path privateKeyFile = dir.resolve("private.key");
|
||||
RSAPublicKey publicKey;
|
||||
RSAPrivateKey privateKey;
|
||||
|
||||
LaunchServerRuntimeConfig runtimeConfig;
|
||||
LaunchServerConfig config;
|
||||
LaunchServer.LaunchServerEnv env = LaunchServer.LaunchServerEnv.PRODUCTION;
|
||||
LaunchServerModulesManager modulesManager = new LaunchServerModulesManager(dir.resolve("modules"), dir.resolve("config"));
|
||||
modulesManager.autoload();
|
||||
modulesManager.initModules(null);
|
||||
registerAll();
|
||||
initGson(modulesManager);
|
||||
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");
|
||||
}
|
||||
CommandHandler localCommandHandler;
|
||||
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");
|
||||
}
|
||||
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()))
|
||||
throw new IOException("Private and public key modulus mismatch");
|
||||
} else {
|
||||
LogHelper.info("Generating RSA keypair");
|
||||
KeyPair pair = SecurityHelper.genRSAKeyPair();
|
||||
publicKey = (RSAPublicKey) pair.getPublic();
|
||||
privateKey = (RSAPrivateKey) pair.getPrivate();
|
||||
|
||||
// Write key pair list
|
||||
LogHelper.info("Writing RSA keypair list");
|
||||
IOHelper.write(publicKeyFile, publicKey.getEncoded());
|
||||
IOHelper.write(privateKeyFile, privateKey.getEncoded());
|
||||
}
|
||||
modulesManager.invokeEvent(new PreConfigPhase());
|
||||
generateConfigIfNotExists(configFile, localCommandHandler, env);
|
||||
LogHelper.info("Reading LaunchServer config file");
|
||||
try (BufferedReader reader = IOHelper.newReader(configFile)) {
|
||||
config = Launcher.gsonManager.gson.fromJson(reader, LaunchServerConfig.class);
|
||||
}
|
||||
if (!Files.exists(runtimeConfigFile)) {
|
||||
LogHelper.info("Reset LaunchServer runtime config file");
|
||||
runtimeConfig = new LaunchServerRuntimeConfig();
|
||||
runtimeConfig.reset();
|
||||
} else {
|
||||
LogHelper.info("Reading LaunchServer runtime config file");
|
||||
try (BufferedReader reader = IOHelper.newReader(runtimeConfigFile)) {
|
||||
runtimeConfig = Launcher.gsonManager.gson.fromJson(reader, LaunchServerRuntimeConfig.class);
|
||||
}
|
||||
}
|
||||
|
||||
LaunchServer.LaunchServerConfigManager launchServerConfigManager = new LaunchServer.LaunchServerConfigManager() {
|
||||
@Override
|
||||
public LaunchServerConfig readConfig() throws IOException {
|
||||
LaunchServerConfig config1;
|
||||
try (BufferedReader reader = IOHelper.newReader(configFile)) {
|
||||
config1 = Launcher.gsonManager.gson.fromJson(reader, LaunchServerConfig.class);
|
||||
}
|
||||
return config1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LaunchServerRuntimeConfig readRuntimeConfig() throws IOException {
|
||||
LaunchServerRuntimeConfig config1;
|
||||
try (BufferedReader reader = IOHelper.newReader(runtimeConfigFile)) {
|
||||
config1 = Launcher.gsonManager.gson.fromJson(reader, LaunchServerRuntimeConfig.class);
|
||||
}
|
||||
return config1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeConfig(LaunchServerConfig config) throws IOException {
|
||||
try (Writer writer = IOHelper.newWriter(configFile)) {
|
||||
if (Launcher.gsonManager.configGson != null) {
|
||||
Launcher.gsonManager.configGson.toJson(config, writer);
|
||||
} else {
|
||||
LogHelper.error("Error writing LaunchServer runtime config file. Gson is null");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeRuntimeConfig(LaunchServerRuntimeConfig config) throws IOException {
|
||||
try (Writer writer = IOHelper.newWriter(runtimeConfigFile)) {
|
||||
if (Launcher.gsonManager.configGson != null) {
|
||||
Launcher.gsonManager.configGson.toJson(config, writer);
|
||||
} else {
|
||||
LogHelper.error("Error writing LaunchServer runtime config file. Gson is null");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
LaunchServer server = new LaunchServerBuilder()
|
||||
.setDir(dir)
|
||||
.setEnv(env)
|
||||
.setCommandHandler(localCommandHandler)
|
||||
.setPrivateKey(privateKey)
|
||||
.setPublicKey(publicKey)
|
||||
.setRuntimeConfig(runtimeConfig)
|
||||
.setConfig(config)
|
||||
.setModulesManager(modulesManager)
|
||||
.setLaunchServerConfigManager(launchServerConfigManager)
|
||||
.build();
|
||||
server.run();
|
||||
}
|
||||
|
||||
public static void initGson(LaunchServerModulesManager modulesManager) {
|
||||
Launcher.gsonManager = new LaunchServerGsonManager(modulesManager);
|
||||
Launcher.gsonManager.initGson();
|
||||
}
|
||||
|
||||
public static void registerAll()
|
||||
{
|
||||
|
||||
AuthHandler.registerHandlers();
|
||||
AuthProvider.registerProviders();
|
||||
TextureProvider.registerProviders();
|
||||
HWIDHandler.registerHandlers();
|
||||
PermissionsHandler.registerHandlers();
|
||||
Component.registerComponents();
|
||||
ProtectHandler.registerHandlers();
|
||||
WebSocketService.registerResponses();
|
||||
HWIDProvider.registerHWIDs();
|
||||
DaoProvider.registerProviders();
|
||||
}
|
||||
|
||||
public static void generateConfigIfNotExists(Path configFile, CommandHandler commandHandler, LaunchServer.LaunchServerEnv env) throws IOException {
|
||||
if (IOHelper.isFile(configFile))
|
||||
return;
|
||||
|
||||
// Create new config
|
||||
LogHelper.info("Creating LaunchServer config");
|
||||
|
||||
|
||||
LaunchServerConfig newConfig = LaunchServerConfig.getDefault(env);
|
||||
// Set server address
|
||||
String address;
|
||||
if (env.equals(LaunchServer.LaunchServerEnv.TEST)) {
|
||||
address = "localhost";
|
||||
newConfig.setProjectName("test");
|
||||
} else {
|
||||
System.out.println("LaunchServer address(default: localhost): ");
|
||||
address = commandHandler.readLine();
|
||||
System.out.println("LaunchServer projectName: ");
|
||||
newConfig.setProjectName(commandHandler.readLine());
|
||||
}
|
||||
if (address == null || address.isEmpty()) {
|
||||
LogHelper.error("Address null. Using localhost");
|
||||
address = "localhost";
|
||||
}
|
||||
if (newConfig.projectName == null || newConfig.projectName.isEmpty()) {
|
||||
LogHelper.error("ProjectName null. Using MineCraft");
|
||||
newConfig.projectName = "MineCraft";
|
||||
}
|
||||
|
||||
newConfig.netty.address = "ws://" + address + ":9274/api";
|
||||
newConfig.netty.downloadURL = "http://" + address + ":9274/%dirname%/";
|
||||
newConfig.netty.launcherURL = "http://" + address + ":9274/Launcher.jar";
|
||||
newConfig.netty.launcherEXEURL = "http://" + address + ":9274/Launcher.exe";
|
||||
|
||||
// Write LaunchServer config
|
||||
LogHelper.info("Writing LaunchServer config file");
|
||||
try (BufferedWriter writer = IOHelper.newWriter(configFile)) {
|
||||
Launcher.gsonManager.configGson.toJson(newConfig, writer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,14 @@
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Allows calling commands using the config command
|
||||
*/
|
||||
public interface Reconfigurable {
|
||||
/**
|
||||
* Gets a list of commands available for this object.
|
||||
* @return Key - Command Name
|
||||
* Value is a command object
|
||||
*/
|
||||
Map<String, Command> getCommands();
|
||||
}
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
package pro.gravit.launchserver;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Reloadable {
|
||||
void reload() throws Exception;
|
||||
}
|
|
@ -33,14 +33,38 @@ public static void registerHandlers() {
|
|||
|
||||
protected transient LaunchServer srv;
|
||||
|
||||
/**
|
||||
* Returns the UUID associated with the account
|
||||
* @param authResult {@link pro.gravit.launchserver.auth.provider.AuthProvider} result
|
||||
* @return User UUID
|
||||
* @throws IOException
|
||||
* Internal Script Error
|
||||
*/
|
||||
public abstract UUID auth(AuthProviderResult authResult) throws IOException;
|
||||
|
||||
/**
|
||||
* Validates serverID
|
||||
* @param username user name
|
||||
* @param serverID serverID to check
|
||||
* @return user UUID
|
||||
* @throws IOException
|
||||
* Internal Script Error
|
||||
*/
|
||||
public abstract UUID checkServer(String username, String serverID) throws IOException;
|
||||
|
||||
@Override
|
||||
public abstract void close() throws IOException;
|
||||
|
||||
|
||||
/**
|
||||
* Checks assessToken for validity and saves serverID if successful
|
||||
* @param username user name
|
||||
* @param accessToken assessToken to check
|
||||
* @param serverID serverID to save
|
||||
* @return true - allow, false - deny
|
||||
* @throws IOException
|
||||
* Internal Script Error
|
||||
*/
|
||||
public abstract boolean joinServer(String username, String accessToken, String serverID) throws IOException;
|
||||
|
||||
|
||||
|
|
|
@ -1,18 +1,23 @@
|
|||
package pro.gravit.launchserver.auth.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.NeedGarbageCollection;
|
||||
import pro.gravit.launchserver.Reconfigurable;
|
||||
import pro.gravit.launchserver.auth.provider.AuthProviderResult;
|
||||
import pro.gravit.utils.helper.CommonHelper;
|
||||
import pro.gravit.utils.helper.SecurityHelper;
|
||||
import pro.gravit.utils.helper.VerifyHelper;
|
||||
import pro.gravit.utils.command.Command;
|
||||
import pro.gravit.utils.command.SubCommand;
|
||||
import pro.gravit.utils.helper.*;
|
||||
|
||||
public abstract class CachedAuthHandler extends AuthHandler implements NeedGarbageCollection {
|
||||
public abstract class CachedAuthHandler extends AuthHandler implements NeedGarbageCollection, Reconfigurable {
|
||||
public static final class Entry {
|
||||
|
||||
public final UUID uuid;
|
||||
|
@ -29,6 +34,63 @@ public Entry(UUID uuid, String username, String accessToken, String serverID) {
|
|||
}
|
||||
}
|
||||
|
||||
protected class EntryAndUsername {
|
||||
public Map<UUID, CachedAuthHandler.Entry> entryCache;
|
||||
public Map<String, UUID> usernameCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Command> getCommands() {
|
||||
Map<String, Command> commands = new HashMap<>();
|
||||
commands.put("clear", new SubCommand() {
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
long entryCacheSize = entryCache.size();
|
||||
long usernamesCacheSize = usernamesCache.size();
|
||||
entryCache.clear();
|
||||
usernamesCache.clear();
|
||||
LogHelper.info("Cleared cache: %d Entry %d Usernames", entryCacheSize, usernamesCacheSize);
|
||||
}
|
||||
});
|
||||
commands.put("load", new SubCommand() {
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
verifyArgs(args, 2);
|
||||
|
||||
LogHelper.info("CachedAuthHandler read from %s", args[0]);
|
||||
int size_entry;
|
||||
int size_username;
|
||||
try (Reader reader = IOHelper.newReader(Paths.get(args[1]))) {
|
||||
EntryAndUsername entryAndUsername = Launcher.gsonManager.configGson.fromJson(reader, EntryAndUsername.class);
|
||||
size_entry = entryAndUsername.entryCache.size();
|
||||
size_username = entryAndUsername.usernameCache.size();
|
||||
loadEntryCache(entryAndUsername.entryCache);
|
||||
loadUsernameCache(entryAndUsername.usernameCache);
|
||||
|
||||
}
|
||||
LogHelper.subInfo("Readed %d entryCache %d usernameCache", size_entry, size_username);
|
||||
}
|
||||
});
|
||||
commands.put("unload", new SubCommand() {
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
verifyArgs(args, 2);
|
||||
|
||||
LogHelper.info("CachedAuthHandler write to %s", args[1]);
|
||||
Map<UUID, CachedAuthHandler.Entry> entryCache = getEntryCache();
|
||||
Map<String, UUID> usernamesCache = getUsernamesCache();
|
||||
EntryAndUsername serializable = new EntryAndUsername();
|
||||
serializable.entryCache = entryCache;
|
||||
serializable.usernameCache = usernamesCache;
|
||||
try (Writer writer = IOHelper.newWriter(Paths.get(args[1]))) {
|
||||
Launcher.gsonManager.configGson.toJson(serializable, writer);
|
||||
}
|
||||
LogHelper.subInfo("Write %d entryCache, %d usernameCache", entryCache.size(), usernamesCache.size());
|
||||
}
|
||||
});
|
||||
return commands;
|
||||
}
|
||||
|
||||
private transient final Map<UUID, Entry> entryCache = new HashMap<>(1024);
|
||||
private transient final Map<String, UUID> usernamesCache = new HashMap<>(1024);
|
||||
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
package pro.gravit.launchserver.auth.hwid;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import pro.gravit.launcher.hwid.HWID;
|
||||
import pro.gravit.launchserver.Reconfigurable;
|
||||
import pro.gravit.utils.ProviderMap;
|
||||
import pro.gravit.utils.command.Command;
|
||||
import pro.gravit.utils.command.SubCommand;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
||||
public abstract class HWIDHandler implements AutoCloseable {
|
||||
public abstract class HWIDHandler implements AutoCloseable, Reconfigurable {
|
||||
public static ProviderMap<HWIDHandler> providers = new ProviderMap<>("HWIDHandler");
|
||||
private static boolean registredHandl = false;
|
||||
|
||||
|
@ -21,6 +27,40 @@ public static void registerHandlers() {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Command> getCommands() {
|
||||
Map<String, Command> commands = new HashMap<>();
|
||||
commands.put("ban", new SubCommand() {
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
List<HWID> target = getHwid(args[0]);
|
||||
ban(target);
|
||||
}
|
||||
});
|
||||
commands.put("unban", new SubCommand() {
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
List<HWID> target = getHwid(args[0]);
|
||||
unban(target);
|
||||
}
|
||||
});
|
||||
commands.put("gethwid", new SubCommand() {
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
List<HWID> target = getHwid(args[0]);
|
||||
for(HWID hwid : target)
|
||||
{
|
||||
if (hwid == null) {
|
||||
LogHelper.error("[%s] HWID: null", args[0]);
|
||||
continue;
|
||||
}
|
||||
LogHelper.info("[%s] HWID: %s", args[0], hwid.toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
return commands;
|
||||
}
|
||||
|
||||
public abstract void ban(List<HWID> hwid) throws HWIDException;
|
||||
|
||||
public void check(HWID hwid, String username) throws HWIDException {
|
||||
|
|
|
@ -14,15 +14,17 @@
|
|||
import pro.gravit.launcher.ClientPermissions;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.Reloadable;
|
||||
import pro.gravit.launchserver.Reconfigurable;
|
||||
import pro.gravit.utils.command.Command;
|
||||
import pro.gravit.utils.command.SubCommand;
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
||||
public class JsonFilePermissionsHandler extends PermissionsHandler implements Reloadable {
|
||||
public class JsonFilePermissionsHandler extends PermissionsHandler implements Reconfigurable {
|
||||
public String filename = "permissions.json";
|
||||
public static Map<String, ClientPermissions> map;
|
||||
|
||||
@Override
|
||||
|
||||
public void reload() {
|
||||
map.clear();
|
||||
Path path = Paths.get(filename);
|
||||
|
@ -40,6 +42,32 @@ public void close() {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Command> getCommands() {
|
||||
Map<String, Command> commands = new HashMap<>();
|
||||
SubCommand reload = new SubCommand() {
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
reload();
|
||||
}
|
||||
};
|
||||
commands.put("reload", reload);
|
||||
commands.put("save", new SubCommand() {
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
Path path = Paths.get(filename);
|
||||
if (!IOHelper.exists(path)) {
|
||||
try (Writer writer = IOHelper.newWriter(path)) {
|
||||
Launcher.gsonManager.gson.toJson(map, writer);
|
||||
} catch (IOException e) {
|
||||
LogHelper.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return commands;
|
||||
}
|
||||
|
||||
public static class Enity {
|
||||
public String username;
|
||||
public ClientPermissions permissions;
|
||||
|
|
|
@ -14,16 +14,18 @@
|
|||
import pro.gravit.launcher.ClientPermissions;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.Reloadable;
|
||||
import pro.gravit.launchserver.Reconfigurable;
|
||||
import pro.gravit.utils.command.Command;
|
||||
import pro.gravit.utils.command.SubCommand;
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
||||
public class JsonLongFilePermissionsHandler extends PermissionsHandler implements Reloadable {
|
||||
public class JsonLongFilePermissionsHandler extends PermissionsHandler implements Reconfigurable {
|
||||
public String filename = "permissions.json";
|
||||
public long defaultPerms = 0L;
|
||||
public static Map<String, Long> map;
|
||||
|
||||
@Override
|
||||
|
||||
public void reload() {
|
||||
map.clear();
|
||||
Path path = Paths.get(filename);
|
||||
|
@ -41,6 +43,32 @@ public void close() {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Command> getCommands() {
|
||||
Map<String, Command> commands = new HashMap<>();
|
||||
SubCommand reload = new SubCommand() {
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
reload();
|
||||
}
|
||||
};
|
||||
commands.put("reload", reload);
|
||||
commands.put("save", new SubCommand() {
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
Path path = Paths.get(filename);
|
||||
if (!IOHelper.exists(path)) {
|
||||
try (Writer writer = IOHelper.newWriter(path)) {
|
||||
Launcher.gsonManager.gson.toJson(map, writer);
|
||||
} catch (IOException e) {
|
||||
LogHelper.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return commands;
|
||||
}
|
||||
|
||||
public static class Enity {
|
||||
public String username;
|
||||
public ClientPermissions permissions;
|
||||
|
|
|
@ -29,6 +29,16 @@ public static void registerProviders() {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Verifies the username and password
|
||||
* @param login user login
|
||||
* @param password user password
|
||||
* @param ip user ip
|
||||
* @return player privileges, effective username and authorization token
|
||||
* @throws Exception
|
||||
* Throws an exception {@link AuthException} {@link pro.gravit.utils.HookException} if the verification script returned a meaningful error
|
||||
* In other cases, throwing an exception indicates a serious error
|
||||
*/
|
||||
public abstract AuthProviderResult auth(String login, String password, String ip) throws Exception;
|
||||
|
||||
public void preAuth(String login, String password, String customText, String ip) {
|
||||
|
|
|
@ -13,12 +13,12 @@
|
|||
|
||||
public class BuildContext {
|
||||
public final ZipOutputStream output;
|
||||
public final JAConfigurator config;
|
||||
public final LauncherConfigurator config;
|
||||
public final MainBuildTask data;
|
||||
public final HashSet<String> fileList;
|
||||
|
||||
|
||||
public BuildContext(ZipOutputStream output, JAConfigurator config, MainBuildTask data) {
|
||||
public BuildContext(ZipOutputStream output, LauncherConfigurator config, MainBuildTask data) {
|
||||
this.output = output;
|
||||
this.config = config;
|
||||
this.data = data;
|
||||
|
|
|
@ -1,142 +0,0 @@
|
|||
package pro.gravit.launchserver.binary;
|
||||
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.FieldInsnNode;
|
||||
import org.objectweb.asm.tree.InsnList;
|
||||
import org.objectweb.asm.tree.InsnNode;
|
||||
import org.objectweb.asm.tree.IntInsnNode;
|
||||
import org.objectweb.asm.tree.LdcInsnNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
import org.objectweb.asm.tree.TypeInsnNode;
|
||||
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import pro.gravit.launcher.AutogenConfig;
|
||||
import pro.gravit.launcher.LauncherConfig;
|
||||
import pro.gravit.launcher.modules.Module;
|
||||
import pro.gravit.launcher.modules.ModulesManager;
|
||||
import pro.gravit.launchserver.asm.ClassMetadataReader;
|
||||
import pro.gravit.launchserver.asm.SafeClassWriter;
|
||||
|
||||
public class JAConfigurator {
|
||||
private static final String modulesManagerName = Type.getInternalName(ModulesManager.class);
|
||||
private static final String registerModDesc = Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Module.class));
|
||||
private static final String autoGenConfigName = Type.getInternalName(AutogenConfig.class);
|
||||
private static final String stringName = Type.getInternalName(String.class);
|
||||
private final ClassNode configclass;
|
||||
private final MethodNode constructor;
|
||||
private final MethodNode initModuleMethod;
|
||||
|
||||
public JAConfigurator(ClassNode configclass) {
|
||||
this.configclass = configclass;
|
||||
constructor = configclass.methods.stream().filter(e -> "<init>".equals(e.name)).findFirst().get();
|
||||
constructor.instructions = new InsnList();
|
||||
initModuleMethod = configclass.methods.stream().filter(e -> "initModules".equals(e.name)).findFirst().get();
|
||||
initModuleMethod.instructions = new InsnList();
|
||||
}
|
||||
|
||||
public void addModuleClass(String fullName) {
|
||||
initModuleMethod.instructions.insert(new MethodInsnNode(Opcodes.INVOKEINTERFACE, modulesManagerName, "registerModule", registerModDesc));
|
||||
initModuleMethod.instructions.insert(new MethodInsnNode(Opcodes.INVOKESPECIAL, fullName.replace('.', '/'), "<init>", "()V"));
|
||||
initModuleMethod.instructions.insert(new TypeInsnNode(Opcodes.NEW, fullName.replace('.', '/')));
|
||||
}
|
||||
|
||||
public byte[] getBytecode(ClassMetadataReader reader) {
|
||||
ClassWriter cw = new SafeClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
|
||||
configclass.accept(cw);
|
||||
return cw.toByteArray();
|
||||
}
|
||||
|
||||
public String getZipEntryPath() {
|
||||
return configclass.name.concat(".class");
|
||||
}
|
||||
|
||||
public void setAddress(String address) {
|
||||
constructor.instructions.add(new LdcInsnNode(address));
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "address", stringName));
|
||||
}
|
||||
|
||||
public void setProjectName(String name) {
|
||||
constructor.instructions.add(new LdcInsnNode(name));
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "projectname", stringName));
|
||||
}
|
||||
|
||||
public void setSecretKey(String key) {
|
||||
constructor.instructions.add(new LdcInsnNode(key));
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "secretKeyClient", stringName));
|
||||
}
|
||||
|
||||
public void setOemUnlockKey(String key) {
|
||||
constructor.instructions.add(new LdcInsnNode(key));
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "oemUnlockKey", stringName));
|
||||
|
||||
}
|
||||
|
||||
public void setGuardType(String key) {
|
||||
constructor.instructions.add(new LdcInsnNode(key));
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "guardType", stringName));
|
||||
}
|
||||
|
||||
public void push(final int value) {
|
||||
if (value >= -1 && value <= 5)
|
||||
constructor.instructions.add(new InsnNode(Opcodes.ICONST_0 + value));
|
||||
else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE)
|
||||
constructor.instructions.add(new IntInsnNode(Opcodes.BIPUSH, value));
|
||||
else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE)
|
||||
constructor.instructions.add(new IntInsnNode(Opcodes.SIPUSH, value));
|
||||
else
|
||||
constructor.instructions.add(new LdcInsnNode(value));
|
||||
}
|
||||
|
||||
public void setEnv(LauncherConfig.LauncherEnvironment env) {
|
||||
int i = 2;
|
||||
|
||||
switch (env) {
|
||||
case DEV:
|
||||
i = 0;
|
||||
break;
|
||||
case DEBUG:
|
||||
i = 1;
|
||||
break;
|
||||
case STD:
|
||||
i = 2;
|
||||
break;
|
||||
case PROD:
|
||||
i = 3;
|
||||
break;
|
||||
}
|
||||
push(i);
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "env", Type.INT_TYPE.getInternalName()));
|
||||
}
|
||||
|
||||
public void setClientPort(int port) {
|
||||
push(port);
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "clientPort", Type.INT_TYPE.getInternalName()));
|
||||
}
|
||||
|
||||
public void setWarningMissArchJava(boolean b) {
|
||||
constructor.instructions.add(new InsnNode(b ? Opcodes.ICONST_1 : Opcodes.ICONST_0));
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "isWarningMissArchJava", Type.BOOLEAN_TYPE.getInternalName()));
|
||||
}
|
||||
|
||||
public void setGuardLicense(String name, String key, String encryptKey) {
|
||||
constructor.instructions.add(new LdcInsnNode(name));
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "guardLicenseName", stringName));
|
||||
constructor.instructions.add(new LdcInsnNode(key));
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "guardLicenseKey", stringName));
|
||||
constructor.instructions.add(new LdcInsnNode(encryptKey));
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "guardLicenseEncryptKey", stringName));
|
||||
}
|
||||
|
||||
public void nullGuardLicense() {
|
||||
constructor.instructions.add(new InsnNode(Opcodes.ACONST_NULL));
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "guardLicenseName", stringName));
|
||||
constructor.instructions.add(new InsnNode(Opcodes.ACONST_NULL));
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "guardLicenseKey", stringName));
|
||||
constructor.instructions.add(new InsnNode(Opcodes.ACONST_NULL));
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "guardLicenseEncryptKey", stringName));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
package pro.gravit.launchserver.binary;
|
||||
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.FieldInsnNode;
|
||||
import org.objectweb.asm.tree.InsnList;
|
||||
import org.objectweb.asm.tree.InsnNode;
|
||||
import org.objectweb.asm.tree.IntInsnNode;
|
||||
import org.objectweb.asm.tree.LdcInsnNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
import org.objectweb.asm.tree.TypeInsnNode;
|
||||
import org.objectweb.asm.tree.VarInsnNode;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import pro.gravit.launcher.AutogenConfig;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.LauncherConfig;
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
import pro.gravit.launcher.modules.LauncherModulesManager;
|
||||
import pro.gravit.launcher.modules.Module;
|
||||
import pro.gravit.launcher.modules.ModulesManager;
|
||||
import pro.gravit.launchserver.asm.ClassMetadataReader;
|
||||
import pro.gravit.launchserver.asm.SafeClassWriter;
|
||||
|
||||
public class LauncherConfigurator {
|
||||
private static final String modulesManagerName = "pro/gravit/launcher/modules/LauncherModulesManager";
|
||||
private static final String launcherName = "pro/gravit/launcher/LauncherEngine";
|
||||
private static final String modulesManagerDesc = "Lpro/gravit/launcher/client/ClientModuleManager;";
|
||||
private static final String registerModDesc = Type.getMethodDescriptor(Type.getType(LauncherModule.class), Type.getType(LauncherModule.class));
|
||||
private static final String autoGenConfigName = Type.getInternalName(AutogenConfig.class);
|
||||
private static final String stringDesc = Type.getDescriptor(String.class);
|
||||
private final ClassNode configclass;
|
||||
private final MethodNode constructor;
|
||||
private final MethodNode initModuleMethod;
|
||||
|
||||
public LauncherConfigurator(ClassNode configclass) {
|
||||
this.configclass = configclass;
|
||||
constructor = configclass.methods.stream().filter(e -> "<init>".equals(e.name)).findFirst().get();
|
||||
constructor.instructions = new InsnList();
|
||||
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
|
||||
constructor.instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", "()V"));
|
||||
initModuleMethod = configclass.methods.stream().filter(e -> "initModules".equals(e.name)).findFirst().get();
|
||||
initModuleMethod.instructions = new InsnList();
|
||||
}
|
||||
|
||||
public void addModuleClass(String fullName) {
|
||||
initModuleMethod.instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, launcherName, "modulesManager", modulesManagerDesc));
|
||||
initModuleMethod.instructions.add(new TypeInsnNode(Opcodes.NEW, fullName.replace('.', '/')));
|
||||
initModuleMethod.instructions.add(new InsnNode(Opcodes.DUP));
|
||||
initModuleMethod.instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, fullName.replace('.', '/'), "<init>", "()V"));
|
||||
initModuleMethod.instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE, modulesManagerName, "loadModule", registerModDesc));
|
||||
}
|
||||
|
||||
public byte[] getBytecode(ClassMetadataReader reader) {
|
||||
constructor.instructions.add(new InsnNode(Opcodes.RETURN));
|
||||
initModuleMethod.instructions.add(new InsnNode(Opcodes.RETURN));
|
||||
ClassWriter cw = new SafeClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
|
||||
configclass.accept(cw);
|
||||
return cw.toByteArray();
|
||||
}
|
||||
|
||||
public String getZipEntryPath() {
|
||||
return configclass.name.concat(".class");
|
||||
}
|
||||
|
||||
public void setAddress(String address) {
|
||||
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
|
||||
constructor.instructions.add(new LdcInsnNode(address));
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "address", stringDesc));
|
||||
}
|
||||
|
||||
public void setProjectName(String name) {
|
||||
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
|
||||
constructor.instructions.add(new LdcInsnNode(name));
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "projectname", stringDesc));
|
||||
}
|
||||
|
||||
public void setSecretKey(String key) {
|
||||
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
|
||||
constructor.instructions.add(new LdcInsnNode(key));
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "secretKeyClient", stringDesc));
|
||||
}
|
||||
|
||||
public void setOemUnlockKey(String key) {
|
||||
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
|
||||
constructor.instructions.add(new LdcInsnNode(key));
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "oemUnlockKey", stringDesc));
|
||||
}
|
||||
|
||||
public void setGuardType(String key) {
|
||||
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
|
||||
constructor.instructions.add(new LdcInsnNode(key));
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "guardType", stringDesc));
|
||||
}
|
||||
|
||||
public void push(final int value) {
|
||||
if (value >= -1 && value <= 5)
|
||||
constructor.instructions.add(new InsnNode(Opcodes.ICONST_0 + value));
|
||||
else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE)
|
||||
constructor.instructions.add(new IntInsnNode(Opcodes.BIPUSH, value));
|
||||
else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE)
|
||||
constructor.instructions.add(new IntInsnNode(Opcodes.SIPUSH, value));
|
||||
else
|
||||
constructor.instructions.add(new LdcInsnNode(value));
|
||||
}
|
||||
|
||||
public void setEnv(LauncherConfig.LauncherEnvironment env) {
|
||||
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
|
||||
int i = 2;
|
||||
|
||||
switch (env) {
|
||||
case DEV:
|
||||
i = 0;
|
||||
break;
|
||||
case DEBUG:
|
||||
i = 1;
|
||||
break;
|
||||
case STD:
|
||||
i = 2;
|
||||
break;
|
||||
case PROD:
|
||||
i = 3;
|
||||
break;
|
||||
}
|
||||
push(i);
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "env", Type.INT_TYPE.getInternalName()));
|
||||
}
|
||||
|
||||
public void setClientPort(int port) {
|
||||
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
|
||||
push(port);
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "clientPort", Type.INT_TYPE.getInternalName()));
|
||||
}
|
||||
|
||||
public void setWarningMissArchJava(boolean b) {
|
||||
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
|
||||
constructor.instructions.add(new InsnNode(b ? Opcodes.ICONST_1 : Opcodes.ICONST_0));
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "isWarningMissArchJava", Type.BOOLEAN_TYPE.getInternalName()));
|
||||
}
|
||||
|
||||
public void setGuardLicense(String name, String key, String encryptKey) {
|
||||
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
|
||||
constructor.instructions.add(new LdcInsnNode(name));
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "guardLicenseName", stringDesc));
|
||||
|
||||
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
|
||||
constructor.instructions.add(new LdcInsnNode(key));
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "guardLicenseKey", stringDesc));
|
||||
|
||||
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
|
||||
constructor.instructions.add(new LdcInsnNode(encryptKey));
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "guardLicenseEncryptKey", stringDesc));
|
||||
}
|
||||
|
||||
public void nullGuardLicense() {
|
||||
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
|
||||
constructor.instructions.add(new InsnNode(Opcodes.ACONST_NULL));
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "guardLicenseName", stringDesc));
|
||||
|
||||
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
|
||||
constructor.instructions.add(new InsnNode(Opcodes.ACONST_NULL));
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "guardLicenseKey", stringDesc));
|
||||
|
||||
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
|
||||
constructor.instructions.add(new InsnNode(Opcodes.ACONST_NULL));
|
||||
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "guardLicenseEncryptKey", stringDesc));
|
||||
}
|
||||
}
|
|
@ -26,7 +26,7 @@
|
|||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.asm.ClassMetadataReader;
|
||||
import pro.gravit.launchserver.binary.BuildContext;
|
||||
import pro.gravit.launchserver.binary.JAConfigurator;
|
||||
import pro.gravit.launchserver.binary.LauncherConfigurator;
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
import pro.gravit.utils.helper.SecurityHelper;
|
||||
|
@ -119,23 +119,23 @@ public Path process(Path inputJar) throws IOException {
|
|||
try (ZipOutputStream output = new ZipOutputStream(IOHelper.newOutput(outputJar))) {
|
||||
ClassNode cn = new ClassNode();
|
||||
new ClassReader(IOHelper.getResourceBytes(AutogenConfig.class.getName().replace('.', '/').concat(".class"))).accept(cn, 0);
|
||||
JAConfigurator jaConfigurator = new JAConfigurator(cn);
|
||||
BuildContext context = new BuildContext(output, jaConfigurator, this);
|
||||
LauncherConfigurator launcherConfigurator = new LauncherConfigurator(cn);
|
||||
BuildContext context = new BuildContext(output, launcherConfigurator, this);
|
||||
server.buildHookManager.hook(context);
|
||||
jaConfigurator.setAddress(server.config.netty.address);
|
||||
launcherConfigurator.setAddress(server.config.netty.address);
|
||||
if (server.config.guardLicense != null)
|
||||
jaConfigurator.setGuardLicense(server.config.guardLicense.name, server.config.guardLicense.key, server.config.guardLicense.encryptKey);
|
||||
launcherConfigurator.setGuardLicense(server.config.guardLicense.name, server.config.guardLicense.key, server.config.guardLicense.encryptKey);
|
||||
else
|
||||
jaConfigurator.nullGuardLicense();
|
||||
jaConfigurator.setProjectName(server.config.projectName);
|
||||
jaConfigurator.setSecretKey(SecurityHelper.randomStringAESKey());
|
||||
jaConfigurator.setClientPort(32148 + SecurityHelper.newRandom().nextInt(512));
|
||||
jaConfigurator.setGuardType(server.config.launcher.guardType);
|
||||
jaConfigurator.setWarningMissArchJava(server.config.launcher.warningMissArchJava);
|
||||
jaConfigurator.setEnv(server.config.env);
|
||||
launcherConfigurator.nullGuardLicense();
|
||||
launcherConfigurator.setProjectName(server.config.projectName);
|
||||
launcherConfigurator.setSecretKey(SecurityHelper.randomStringAESKey());
|
||||
launcherConfigurator.setClientPort(32148 + SecurityHelper.newRandom().nextInt(512));
|
||||
launcherConfigurator.setGuardType(server.config.launcher.guardType);
|
||||
launcherConfigurator.setWarningMissArchJava(server.config.launcher.warningMissArchJava);
|
||||
launcherConfigurator.setEnv(server.config.env);
|
||||
if (server.runtime.oemUnlockKey == null) server.runtime.oemUnlockKey = SecurityHelper.randomStringToken();
|
||||
jaConfigurator.setOemUnlockKey(server.runtime.oemUnlockKey);
|
||||
server.buildHookManager.registerAllClientModuleClass(jaConfigurator);
|
||||
launcherConfigurator.setOemUnlockKey(server.runtime.oemUnlockKey);
|
||||
server.buildHookManager.registerAllClientModuleClass(launcherConfigurator);
|
||||
reader.getCp().add(new JarFile(inputJar.toFile()));
|
||||
server.launcherBinary.coreLibs.forEach(e -> {
|
||||
try {
|
||||
|
@ -144,7 +144,7 @@ public Path process(Path inputJar) throws IOException {
|
|||
LogHelper.error(e1);
|
||||
}
|
||||
});
|
||||
String zPath = jaConfigurator.getZipEntryPath();
|
||||
String zPath = launcherConfigurator.getZipEntryPath();
|
||||
try (ZipInputStream input = new ZipInputStream(IOHelper.newInput(inputJar))) {
|
||||
ZipEntry e = input.getNextEntry();
|
||||
while (e != null) {
|
||||
|
@ -203,7 +203,7 @@ public Path process(Path inputJar) throws IOException {
|
|||
output.write(launcherConfigBytes);
|
||||
ZipEntry e = newZipEntry(zPath);
|
||||
output.putNextEntry(e);
|
||||
output.write(jaConfigurator.getBytecode(reader));
|
||||
output.write(launcherConfigurator.getBytecode(reader));
|
||||
}
|
||||
reader.close();
|
||||
return outputJar;
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
package pro.gravit.launchserver.command.auth;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import pro.gravit.launcher.hwid.HWID;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
|
||||
public class BanCommand extends Command {
|
||||
public BanCommand(LaunchServer server) {
|
||||
super(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgsDescription() {
|
||||
return "[username]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsageDescription() {
|
||||
return "Ban username for HWID";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
verifyArgs(args, 1);
|
||||
List<HWID> target = server.config.hwidHandler.getHwid(args[0]);
|
||||
server.config.hwidHandler.ban(target);
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
package pro.gravit.launchserver.command.auth;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import pro.gravit.launcher.hwid.HWID;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
||||
public class GetHWIDCommand extends Command {
|
||||
public GetHWIDCommand(LaunchServer server) {
|
||||
super(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgsDescription() {
|
||||
return "[username]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsageDescription() {
|
||||
return "get HWID from username";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
verifyArgs(args, 1);
|
||||
List<HWID> target = server.config.hwidHandler.getHwid(args[0]);
|
||||
for (HWID hwid : target) {
|
||||
if (hwid == null) {
|
||||
LogHelper.error("HWID %s: null", args[0]);
|
||||
continue;
|
||||
}
|
||||
LogHelper.info("HWID %s: %s", args[0], hwid.toString());
|
||||
}
|
||||
LogHelper.info("Found %d HWID", target.size());
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
package pro.gravit.launchserver.command.auth;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import pro.gravit.launcher.hwid.HWID;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
|
||||
public class UnbanCommand extends Command {
|
||||
public UnbanCommand(LaunchServer server) {
|
||||
super(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgsDescription() {
|
||||
return "[username]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsageDescription() {
|
||||
return "Unban username for HWID";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
verifyArgs(args, 1);
|
||||
List<HWID> target = server.config.hwidHandler.getHwid(args[0]);
|
||||
server.config.hwidHandler.unban(target);
|
||||
}
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
package pro.gravit.launchserver.command.dump;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.auth.AuthProviderPair;
|
||||
import pro.gravit.launchserver.auth.handler.CachedAuthHandler;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
import pro.gravit.utils.command.SubCommand;
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
||||
public class DumpEntryCacheCommand extends Command {
|
||||
public DumpEntryCacheCommand(LaunchServer server) {
|
||||
super(server);
|
||||
childCommands.put("load", new SubCommand() {
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
verifyArgs(args, 2);
|
||||
AuthProviderPair pair = server.config.getAuthProviderPair(args[0]);
|
||||
if (pair == null) throw new IllegalStateException(String.format("Auth %s not found", args[0]));
|
||||
if (!(pair.handler instanceof CachedAuthHandler))
|
||||
throw new UnsupportedOperationException("This command used only CachedAuthHandler");
|
||||
CachedAuthHandler authHandler = (CachedAuthHandler) pair.handler;
|
||||
|
||||
LogHelper.info("CachedAuthHandler read from %s", args[0]);
|
||||
int size_entry;
|
||||
int size_username;
|
||||
try (Reader reader = IOHelper.newReader(Paths.get(args[1]))) {
|
||||
EntryAndUsername entryAndUsername = Launcher.gsonManager.configGson.fromJson(reader, EntryAndUsername.class);
|
||||
size_entry = entryAndUsername.entryCache.size();
|
||||
size_username = entryAndUsername.usernameCache.size();
|
||||
authHandler.loadEntryCache(entryAndUsername.entryCache);
|
||||
authHandler.loadUsernameCache(entryAndUsername.usernameCache);
|
||||
|
||||
}
|
||||
LogHelper.subInfo("Readed %d entryCache %d usernameCache", size_entry, size_username);
|
||||
}
|
||||
});
|
||||
childCommands.put("unload", new SubCommand() {
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
verifyArgs(args, 2);
|
||||
AuthProviderPair pair = server.config.getAuthProviderPair(args[0]);
|
||||
if (pair == null) throw new IllegalStateException(String.format("Auth %s not found", args[0]));
|
||||
if (!(pair.handler instanceof CachedAuthHandler))
|
||||
throw new UnsupportedOperationException("This command used only CachedAuthHandler");
|
||||
CachedAuthHandler authHandler = (CachedAuthHandler) pair.handler;
|
||||
|
||||
LogHelper.info("CachedAuthHandler write to %s", args[1]);
|
||||
Map<UUID, CachedAuthHandler.Entry> entryCache = authHandler.getEntryCache();
|
||||
Map<String, UUID> usernamesCache = authHandler.getUsernamesCache();
|
||||
EntryAndUsername serializable = new EntryAndUsername();
|
||||
serializable.entryCache = entryCache;
|
||||
serializable.usernameCache = usernamesCache;
|
||||
try (Writer writer = IOHelper.newWriter(Paths.get(args[1]))) {
|
||||
Launcher.gsonManager.configGson.toJson(serializable, writer);
|
||||
}
|
||||
LogHelper.subInfo("Write %d entryCache, %d usernameCache", entryCache.size(), usernamesCache.size());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgsDescription() {
|
||||
return "[load/unload] [auth_id] [filename]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsageDescription() {
|
||||
return "Load or unload AuthHandler Entry cache";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
invokeSubcommands(args);
|
||||
}
|
||||
|
||||
public class EntryAndUsername {
|
||||
public Map<UUID, CachedAuthHandler.Entry> entryCache;
|
||||
public Map<String, UUID> usernameCache;
|
||||
}
|
||||
}
|
|
@ -2,10 +2,7 @@
|
|||
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.command.auth.AuthCommand;
|
||||
import pro.gravit.launchserver.command.auth.BanCommand;
|
||||
import pro.gravit.launchserver.command.auth.GetHWIDCommand;
|
||||
import pro.gravit.launchserver.command.auth.UUIDToUsernameCommand;
|
||||
import pro.gravit.launchserver.command.auth.UnbanCommand;
|
||||
import pro.gravit.launchserver.command.auth.UsernameToUUIDCommand;
|
||||
import pro.gravit.launchserver.command.basic.BuildCommand;
|
||||
import pro.gravit.launchserver.command.basic.ProguardCleanCommand;
|
||||
|
@ -19,7 +16,6 @@
|
|||
import pro.gravit.launchserver.command.dao.GetUserCommand;
|
||||
import pro.gravit.launchserver.command.dao.RegisterCommand;
|
||||
import pro.gravit.launchserver.command.dao.SetUserPasswordCommand;
|
||||
import pro.gravit.launchserver.command.dump.DumpEntryCacheCommand;
|
||||
import pro.gravit.launchserver.command.dump.DumpSessionsCommand;
|
||||
import pro.gravit.launchserver.command.hash.DownloadAssetCommand;
|
||||
import pro.gravit.launchserver.command.hash.DownloadClientCommand;
|
||||
|
@ -86,24 +82,17 @@ public static void registerCommands(pro.gravit.utils.command.CommandHandler hand
|
|||
auth.registerCommand("auth", new AuthCommand(server));
|
||||
auth.registerCommand("usernameToUUID", new UsernameToUUIDCommand(server));
|
||||
auth.registerCommand("uuidToUsername", new UUIDToUsernameCommand(server));
|
||||
auth.registerCommand("ban", new BanCommand(server));
|
||||
auth.registerCommand("unban", new UnbanCommand(server));
|
||||
auth.registerCommand("getHWID", new GetHWIDCommand(server));
|
||||
Category authCategory = new Category(auth, "auth", "User Management");
|
||||
handler.registerCategory(authCategory);
|
||||
|
||||
//Register dump commands
|
||||
BaseCommandCategory dump = new BaseCommandCategory();
|
||||
dump.registerCommand("dumpSessions", new DumpSessionsCommand(server));
|
||||
dump.registerCommand("dumpEntryCache", new DumpEntryCacheCommand(server));
|
||||
Category dumpCategory = new Category(dump, "dump", "Dump runtime data");
|
||||
handler.registerCategory(dumpCategory);
|
||||
|
||||
//Register service commands
|
||||
BaseCommandCategory service = new BaseCommandCategory();
|
||||
service.registerCommand("reload", new ReloadCommand(server));
|
||||
service.registerCommand("reloadAll", new ReloadAllCommand(server));
|
||||
service.registerCommand("reloadList", new ReloadListCommand(server));
|
||||
service.registerCommand("config", new ConfigCommand(server));
|
||||
service.registerCommand("serverStatus", new ServerStatusCommand(server));
|
||||
service.registerCommand("checkInstall", new CheckInstallCommand(server));
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package pro.gravit.launchserver.command.modules;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
|
@ -24,7 +25,7 @@ public String getUsageDescription() {
|
|||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
verifyArgs(args, 1);
|
||||
URI uri = Paths.get(args[0]).toUri();
|
||||
server.modulesManager.loadModuleFull(uri.toURL());
|
||||
Path file = Paths.get(args[0]);
|
||||
server.modulesManager.loadModule(file);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,6 @@ public String getUsageDescription() {
|
|||
|
||||
@Override
|
||||
public void invoke(String... args) {
|
||||
server.modulesManager.printModules();
|
||||
server.modulesManager.printModulesInfo();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
package pro.gravit.launchserver.command.service;
|
||||
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
||||
public class ReloadAllCommand extends Command {
|
||||
public ReloadAllCommand(LaunchServer server) {
|
||||
super(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgsDescription() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsageDescription() {
|
||||
return "Reload all provider/handler/module config";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
LogHelper.info("Reload all config");
|
||||
server.reloadManager.reloadAll();
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package pro.gravit.launchserver.command.service;
|
||||
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
||||
public class ReloadCommand extends Command {
|
||||
public ReloadCommand(LaunchServer server) {
|
||||
super(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgsDescription() {
|
||||
return "[name]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsageDescription() {
|
||||
return "Reload provider/handler/module config";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
verifyArgs(args, 1);
|
||||
LogHelper.info("Reload %s config", args[0]);
|
||||
server.reloadManager.reload(args[0]);
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
package pro.gravit.launchserver.command.service;
|
||||
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
|
||||
public class ReloadListCommand extends Command {
|
||||
public ReloadListCommand(LaunchServer server) {
|
||||
super(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgsDescription() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsageDescription() {
|
||||
return "print reloadable configs";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(String... args) {
|
||||
server.reloadManager.printReloadables();
|
||||
}
|
||||
}
|
|
@ -38,7 +38,7 @@ public void invoke(String... args) {
|
|||
for (CommandHandler.Category category : server.commandHandler.getCategories()) {
|
||||
commands += category.category.commandsMap().size();
|
||||
}
|
||||
LogHelper.info("Sessions: %d | Modules: %d | Commands: %d(%d categories)", server.sessionManager.getSessions().size(), server.modulesManager.modules.size(), commands, server.commandHandler.getCategories().size() + 1);
|
||||
LogHelper.info("Sessions: %d | Commands: %d(%d categories)", server.sessionManager.getSessions().size(), commands, server.commandHandler.getCategories().size() + 1);
|
||||
for (AuthProviderPair pair : server.config.auth) {
|
||||
if (pair.handler instanceof CachedAuthHandler) {
|
||||
LogHelper.info("AuthHandler %s: EntryCache: %d | usernameCache: %d", pair.name, ((CachedAuthHandler) pair.handler).getEntryCache().size(), ((CachedAuthHandler) pair.handler).getUsernamesCache().size());
|
||||
|
|
|
@ -1,23 +1,70 @@
|
|||
package pro.gravit.launchserver.components;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import pro.gravit.launcher.NeedGarbageCollection;
|
||||
import pro.gravit.launchserver.Reconfigurable;
|
||||
import pro.gravit.utils.command.Command;
|
||||
import pro.gravit.utils.command.SubCommand;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
||||
public class AbstractLimiter<T> implements NeedGarbageCollection {
|
||||
public final int maxTrys;
|
||||
public final int banMillis;
|
||||
public abstract class AbstractLimiter<T> extends Component implements NeedGarbageCollection, Reconfigurable {
|
||||
public int rateLimit;
|
||||
public int rateLimitMillis;
|
||||
public List<T> exclude = new ArrayList<>();
|
||||
|
||||
public AbstractLimiter(int maxTrys, int banMillis) {
|
||||
this.maxTrys = maxTrys;
|
||||
this.banMillis = banMillis;
|
||||
@Override
|
||||
public Map<String, Command> getCommands() {
|
||||
Map<String, Command> commands = new HashMap<>();
|
||||
commands.put("gc", new SubCommand() {
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
long size = map.size();
|
||||
garbageCollection();
|
||||
LogHelper.info("Cleared %d entity", size);
|
||||
}
|
||||
});
|
||||
commands.put("clear", new SubCommand() {
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
long size = map.size();
|
||||
map.clear();
|
||||
LogHelper.info("Cleared %d entity", size);
|
||||
}
|
||||
});
|
||||
commands.put("addExclude", new SubCommand() {
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
verifyArgs(args, 1);
|
||||
exclude.add(getFromString(args[0]));
|
||||
}
|
||||
});
|
||||
commands.put("rmExclude", new SubCommand() {
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
verifyArgs(args, 1);
|
||||
exclude.remove(getFromString(args[0]));
|
||||
}
|
||||
});
|
||||
commands.put("clearExclude", new SubCommand() {
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
exclude.clear();
|
||||
}
|
||||
});
|
||||
|
||||
return commands;
|
||||
}
|
||||
|
||||
protected abstract T getFromString(String str);
|
||||
|
||||
@Override
|
||||
public void garbageCollection() {
|
||||
long time = System.currentTimeMillis();
|
||||
map.entrySet().removeIf((e) -> e.getValue().time + banMillis < time);
|
||||
map.entrySet().removeIf((e) -> e.getValue().time + rateLimitMillis < time);
|
||||
}
|
||||
|
||||
class LimitEntry
|
||||
|
@ -35,9 +82,10 @@ public LimitEntry() {
|
|||
trys = 0;
|
||||
}
|
||||
}
|
||||
protected Map<T, LimitEntry> map = new HashMap<>();
|
||||
protected transient Map<T, LimitEntry> map = new HashMap<>();
|
||||
public boolean check(T address)
|
||||
{
|
||||
if(exclude.contains(address)) return true;
|
||||
LimitEntry entry = map.get(address);
|
||||
if(entry == null)
|
||||
{
|
||||
|
@ -47,13 +95,13 @@ public boolean check(T address)
|
|||
else
|
||||
{
|
||||
long time = System.currentTimeMillis();
|
||||
if(entry.trys < maxTrys)
|
||||
if(entry.trys < rateLimit)
|
||||
{
|
||||
entry.trys++;
|
||||
entry.time = time;
|
||||
return true;
|
||||
}
|
||||
if(entry.time + banMillis < time)
|
||||
if(entry.time + rateLimitMillis < time)
|
||||
{
|
||||
entry.trys = 1;
|
||||
entry.time = time;
|
||||
|
|
|
@ -9,9 +9,7 @@
|
|||
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
|
||||
import pro.gravit.utils.HookException;
|
||||
|
||||
public class AuthLimiterComponent extends Component implements NeedGarbageCollection, AutoCloseable {
|
||||
|
||||
private transient AbstractLimiter<String> limiter;
|
||||
public class AuthLimiterComponent extends IPLimiter implements NeedGarbageCollection, AutoCloseable {
|
||||
private transient LaunchServer srv;
|
||||
@Override
|
||||
public void preInit(LaunchServer launchServer) {
|
||||
|
@ -20,7 +18,6 @@ public void preInit(LaunchServer launchServer) {
|
|||
|
||||
@Override
|
||||
public void init(LaunchServer launchServer) {
|
||||
limiter = new AbstractLimiter<>(rateLimit, rateLimitMilis);
|
||||
launchServer.authHookManager.preHook.registerHook(this::preAuthHook);
|
||||
}
|
||||
|
||||
|
@ -30,22 +27,12 @@ public void postInit(LaunchServer launchServer) {
|
|||
}
|
||||
|
||||
public boolean preAuthHook(AuthResponse.AuthContext context, Client client) {
|
||||
if (!excludeIps.contains(context.ip) && !limiter.check(context.ip)) {
|
||||
if (!check(context.ip)) {
|
||||
throw new HookException(message);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int rateLimit;
|
||||
public int rateLimitMilis;
|
||||
public String message;
|
||||
public List<String> excludeIps = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void garbageCollection() {
|
||||
if(limiter != null)
|
||||
limiter.garbageCollection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
package pro.gravit.launchserver.components;
|
||||
|
||||
public abstract class IPLimiter extends AbstractLimiter<String> {
|
||||
@Override
|
||||
protected String getFromString(String str) {
|
||||
return str;
|
||||
}
|
||||
}
|
|
@ -8,19 +8,15 @@
|
|||
import pro.gravit.launchserver.manangers.hook.AuthHookManager;
|
||||
import pro.gravit.utils.HookException;
|
||||
|
||||
public class RegLimiterComponent extends Component implements NeedGarbageCollection, AutoCloseable {
|
||||
public class RegLimiterComponent extends IPLimiter implements NeedGarbageCollection, AutoCloseable {
|
||||
|
||||
private transient AbstractLimiter<String> limiter;
|
||||
public transient LaunchServer launchServer;
|
||||
public int rateLimit;
|
||||
public int rateLimitMilis;
|
||||
public String message;
|
||||
|
||||
public List<String> excludeIps = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void preInit(LaunchServer launchServer) {
|
||||
limiter = new AbstractLimiter<>(rateLimit, rateLimitMilis);
|
||||
this.launchServer = launchServer;
|
||||
}
|
||||
|
||||
|
@ -36,17 +32,12 @@ public void postInit(LaunchServer launchServer) {
|
|||
|
||||
public boolean registerHook(AuthHookManager.RegContext context)
|
||||
{
|
||||
if (!limiter.check(context.ip)) {
|
||||
if (!check(context.ip)) {
|
||||
throw new HookException(message);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void garbageCollection() {
|
||||
if(limiter != null)
|
||||
limiter.garbageCollection();
|
||||
}
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
launchServer.authHookManager.registraion.unregisterHook(this::registerHook);
|
||||
|
|
|
@ -0,0 +1,357 @@
|
|||
package pro.gravit.launchserver.config;
|
||||
|
||||
import io.netty.channel.epoll.Epoll;
|
||||
import io.netty.handler.logging.LogLevel;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.LauncherConfig;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.auth.AuthProviderPair;
|
||||
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;
|
||||
import pro.gravit.launchserver.auth.protect.StdProtectHandler;
|
||||
import pro.gravit.launchserver.auth.provider.RejectAuthProvider;
|
||||
import pro.gravit.launchserver.auth.texture.RequestTextureProvider;
|
||||
import pro.gravit.launchserver.components.AuthLimiterComponent;
|
||||
import pro.gravit.launchserver.components.Component;
|
||||
import pro.gravit.launchserver.components.RegLimiterComponent;
|
||||
import pro.gravit.launchserver.dao.provider.DaoProvider;
|
||||
import pro.gravit.utils.Version;
|
||||
import pro.gravit.utils.helper.JVMHelper;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public final class LaunchServerConfig {
|
||||
private transient LaunchServer server = null;
|
||||
|
||||
public LaunchServerConfig setLaunchServer(LaunchServer server) {
|
||||
this.server = server;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String projectName;
|
||||
|
||||
public String[] mirrors;
|
||||
|
||||
public String binaryName;
|
||||
|
||||
public boolean copyBinaries = true;
|
||||
|
||||
public LauncherConfig.LauncherEnvironment env;
|
||||
|
||||
// Handlers & Providers
|
||||
|
||||
public AuthProviderPair[] auth;
|
||||
|
||||
public DaoProvider dao;
|
||||
|
||||
private transient AuthProviderPair authDefault;
|
||||
|
||||
public AuthProviderPair getAuthProviderPair(String name) {
|
||||
for (AuthProviderPair pair : auth) {
|
||||
if (pair.name.equals(name)) return pair;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ProtectHandler protectHandler;
|
||||
|
||||
public PermissionsHandler permissionsHandler;
|
||||
|
||||
public AuthProviderPair getAuthProviderPair() {
|
||||
if (authDefault != null) return authDefault;
|
||||
for (AuthProviderPair pair : auth) {
|
||||
if (pair.isDefault) {
|
||||
authDefault = pair;
|
||||
return pair;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public HWIDHandler hwidHandler;
|
||||
|
||||
public Map<String, Component> components;
|
||||
|
||||
public ExeConf launch4j;
|
||||
public NettyConfig netty;
|
||||
public GuardLicenseConf guardLicense;
|
||||
|
||||
public String whitelistRejectString;
|
||||
public LauncherConf launcher;
|
||||
public CertificateConf certificate;
|
||||
|
||||
public String startScript;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
public void verify() {
|
||||
if (auth == null || auth[0] == null) {
|
||||
throw new NullPointerException("AuthHandler must not be null");
|
||||
}
|
||||
boolean isOneDefault = false;
|
||||
for (AuthProviderPair pair : auth) {
|
||||
if (pair.isDefault) {
|
||||
isOneDefault = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (protectHandler == null) {
|
||||
throw new NullPointerException("ProtectHandler must not be null");
|
||||
}
|
||||
if (!isOneDefault) {
|
||||
throw new IllegalStateException("No auth pairs declared by default.");
|
||||
}
|
||||
if (permissionsHandler == null) {
|
||||
throw new NullPointerException("PermissionsHandler must not be null");
|
||||
}
|
||||
if (env == null) {
|
||||
throw new NullPointerException("Env must not be null");
|
||||
}
|
||||
if (netty == null) {
|
||||
throw new NullPointerException("Netty must not be null");
|
||||
}
|
||||
}
|
||||
|
||||
public void init(LaunchServer.ReloadType type) {
|
||||
Launcher.applyLauncherEnv(env);
|
||||
for (AuthProviderPair provider : auth) {
|
||||
provider.init(server);
|
||||
}
|
||||
permissionsHandler.init(server);
|
||||
hwidHandler.init();
|
||||
if(dao != null)
|
||||
dao.init(server);
|
||||
if (protectHandler != null) {
|
||||
protectHandler.checkLaunchServerLicense();
|
||||
}
|
||||
if(components != null)
|
||||
{
|
||||
components.forEach((k,v) -> {
|
||||
server.registerObject("component.".concat(k), v);
|
||||
});
|
||||
}
|
||||
server.registerObject("permissionsHandler", permissionsHandler);
|
||||
server.registerObject("hwidHandler", hwidHandler);
|
||||
if(!type.equals(LaunchServer.ReloadType.NO_AUTH))
|
||||
{
|
||||
for (int i = 0; i < auth.length; ++i) {
|
||||
AuthProviderPair pair = auth[i];
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Arrays.stream(mirrors).forEach(server.mirrorManager::addMirror);
|
||||
}
|
||||
|
||||
public void close(LaunchServer.ReloadType type) {
|
||||
try {
|
||||
server.unregisterObject("permissionsHandler", permissionsHandler);
|
||||
server.unregisterObject("hwidHandler", hwidHandler);
|
||||
if(!type.equals(LaunchServer.ReloadType.NO_AUTH))
|
||||
{
|
||||
for (AuthProviderPair pair : auth) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
if(type.equals(LaunchServer.ReloadType.FULL))
|
||||
{
|
||||
components.forEach((k, component) -> {
|
||||
server.unregisterObject("component.".concat(k), component);
|
||||
if(component instanceof AutoCloseable)
|
||||
{
|
||||
try {
|
||||
((AutoCloseable) component).close();
|
||||
} catch (Exception e) {
|
||||
LogHelper.error(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogHelper.error(e);
|
||||
}
|
||||
try {
|
||||
for (AuthProviderPair p : auth) p.close();
|
||||
} catch (IOException e) {
|
||||
LogHelper.error(e);
|
||||
}
|
||||
try {
|
||||
hwidHandler.close();
|
||||
} catch (Exception e) {
|
||||
LogHelper.error(e);
|
||||
}
|
||||
try {
|
||||
permissionsHandler.close();
|
||||
} catch (Exception e) {
|
||||
LogHelper.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ExeConf {
|
||||
public boolean enabled;
|
||||
public String alternative;
|
||||
public boolean setMaxVersion;
|
||||
public String maxVersion;
|
||||
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;
|
||||
}
|
||||
|
||||
public static class CertificateConf
|
||||
{
|
||||
public boolean enabled;
|
||||
}
|
||||
|
||||
public static class NettyUpdatesBind {
|
||||
public String url;
|
||||
public boolean zip;
|
||||
}
|
||||
public static class LauncherConf {
|
||||
public String guardType;
|
||||
public boolean attachLibraryBeforeProGuard;
|
||||
public boolean compress;
|
||||
public boolean warningMissArchJava;
|
||||
public boolean enabledProGuard;
|
||||
public boolean stripLineNumbers;
|
||||
public boolean deleteTempFiles;
|
||||
public boolean proguardGenMappings;
|
||||
}
|
||||
|
||||
public static class NettyConfig {
|
||||
public boolean fileServerEnabled;
|
||||
public boolean sendExceptionEnabled;
|
||||
public boolean ipForwarding;
|
||||
public boolean showHiddenFiles;
|
||||
public String launcherURL;
|
||||
public String downloadURL;
|
||||
public String launcherEXEURL;
|
||||
public String address;
|
||||
public Map<String, LaunchServerConfig.NettyUpdatesBind> bindings = new HashMap<>();
|
||||
public NettyPerformanceConfig performance;
|
||||
public NettyBindAddress[] binds;
|
||||
public LogLevel logLevel = LogLevel.DEBUG;
|
||||
}
|
||||
|
||||
public static class NettyPerformanceConfig {
|
||||
public boolean usingEpoll;
|
||||
public int bossThread;
|
||||
public int workerThread;
|
||||
}
|
||||
|
||||
public static class NettyBindAddress {
|
||||
public String address;
|
||||
public int port;
|
||||
|
||||
public NettyBindAddress(String address, int port) {
|
||||
this.address = address;
|
||||
this.port = port;
|
||||
}
|
||||
}
|
||||
|
||||
public static class GuardLicenseConf {
|
||||
public String name;
|
||||
public String key;
|
||||
public String encryptKey;
|
||||
}
|
||||
public static LaunchServerConfig getDefault(LaunchServer.LaunchServerEnv env)
|
||||
{
|
||||
LaunchServerConfig newConfig = new LaunchServerConfig();
|
||||
newConfig.mirrors = new String[]{"https://mirror.gravit.pro/"};
|
||||
newConfig.launch4j = new LaunchServerConfig.ExeConf();
|
||||
newConfig.launch4j.enabled = true;
|
||||
newConfig.launch4j.copyright = "© GravitLauncher Team";
|
||||
newConfig.launch4j.alternative = "no";
|
||||
newConfig.launch4j.fileDesc = "GravitLauncher ".concat(Version.getVersion().getVersionString());
|
||||
newConfig.launch4j.fileVer = Version.getVersion().getVersionString().concat(".").concat(String.valueOf(Version.getVersion().patch));
|
||||
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";
|
||||
newConfig.launch4j.productName = "GravitLauncher";
|
||||
newConfig.launch4j.productVer = newConfig.launch4j.fileVer;
|
||||
newConfig.launch4j.maxVersion = "1.8.999";
|
||||
newConfig.env = LauncherConfig.LauncherEnvironment.STD;
|
||||
newConfig.startScript = JVMHelper.OS_TYPE.equals(JVMHelper.OS.MUSTDIE) ? "." + File.separator + "start.bat" : "." + File.separator + "start.sh";
|
||||
newConfig.hwidHandler = new AcceptHWIDHandler();
|
||||
newConfig.auth = new AuthProviderPair[]{new AuthProviderPair(new RejectAuthProvider("Настройте authProvider"),
|
||||
new MemoryAuthHandler(),
|
||||
new RequestTextureProvider("http://example.com/skins/%username%.png", "http://example.com/cloaks/%username%.png")
|
||||
, "std")};
|
||||
newConfig.auth[0].displayName = "Default";
|
||||
newConfig.protectHandler = new StdProtectHandler();
|
||||
if(env.equals(LaunchServer.LaunchServerEnv.TEST))
|
||||
newConfig.permissionsHandler = new DefaultPermissionsHandler();
|
||||
else
|
||||
newConfig.permissionsHandler = new JsonFilePermissionsHandler();
|
||||
newConfig.binaryName = "Launcher";
|
||||
newConfig.whitelistRejectString = "Вас нет в белом списке";
|
||||
|
||||
newConfig.netty = new NettyConfig();
|
||||
newConfig.netty.fileServerEnabled = true;
|
||||
newConfig.netty.binds = new NettyBindAddress[]{new NettyBindAddress("0.0.0.0", 9274)};
|
||||
newConfig.netty.performance = new NettyPerformanceConfig();
|
||||
newConfig.netty.performance.usingEpoll = Epoll.isAvailable();
|
||||
newConfig.netty.performance.bossThread = 2;
|
||||
newConfig.netty.performance.workerThread = 8;
|
||||
|
||||
newConfig.launcher = new LauncherConf();
|
||||
newConfig.launcher.guardType = "no";
|
||||
newConfig.launcher.compress = true;
|
||||
newConfig.launcher.warningMissArchJava = true;
|
||||
newConfig.launcher.attachLibraryBeforeProGuard = false;
|
||||
newConfig.launcher.deleteTempFiles = true;
|
||||
newConfig.launcher.enabledProGuard = true;
|
||||
newConfig.launcher.stripLineNumbers = true;
|
||||
newConfig.launcher.proguardGenMappings = true;
|
||||
|
||||
newConfig.certificate = new LaunchServerConfig.CertificateConf();
|
||||
newConfig.certificate.enabled = false;
|
||||
|
||||
newConfig.components = new HashMap<>();
|
||||
AuthLimiterComponent authLimiterComponent = new AuthLimiterComponent();
|
||||
authLimiterComponent.rateLimit = 3;
|
||||
authLimiterComponent.rateLimitMillis = 8000;
|
||||
authLimiterComponent.message = "Превышен лимит авторизаций";
|
||||
newConfig.components.put("authLimiter", authLimiterComponent);
|
||||
RegLimiterComponent regLimiterComponent = new RegLimiterComponent();
|
||||
regLimiterComponent.rateLimit = 3;
|
||||
regLimiterComponent.rateLimitMillis = 1000 * 60 * 60 * 10; //Блок на 10 часов
|
||||
regLimiterComponent.message = "Превышен лимит регистраций";
|
||||
newConfig.components.put("regLimiter", regLimiterComponent);
|
||||
newConfig.netty.sendExceptionEnabled = true;
|
||||
return newConfig;
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
import pro.gravit.launcher.hwid.HWID;
|
||||
import pro.gravit.launcher.hwid.HWIDProvider;
|
||||
import pro.gravit.launcher.managers.GsonManager;
|
||||
import pro.gravit.launcher.modules.events.PreGsonPhase;
|
||||
import pro.gravit.launcher.request.JsonResultSerializeAdapter;
|
||||
import pro.gravit.launcher.request.WebSocketEvent;
|
||||
import pro.gravit.launchserver.auth.handler.AuthHandler;
|
||||
|
@ -15,11 +16,18 @@
|
|||
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
||||
import pro.gravit.launchserver.components.Component;
|
||||
import pro.gravit.launchserver.dao.provider.DaoProvider;
|
||||
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
|
||||
import pro.gravit.launchserver.socket.WebSocketService;
|
||||
import pro.gravit.launchserver.socket.response.WebSocketServerResponse;
|
||||
import pro.gravit.utils.UniversalJsonAdapter;
|
||||
|
||||
public class LaunchServerGsonManager extends GsonManager {
|
||||
private final LaunchServerModulesManager modulesManager;
|
||||
|
||||
public LaunchServerGsonManager(LaunchServerModulesManager modulesManager) {
|
||||
this.modulesManager = modulesManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerAdapters(GsonBuilder builder) {
|
||||
super.registerAdapters(builder);
|
||||
|
@ -34,6 +42,7 @@ public void registerAdapters(GsonBuilder builder) {
|
|||
builder.registerTypeAdapter(HWID.class, new UniversalJsonAdapter<>(HWIDProvider.hwids));
|
||||
builder.registerTypeAdapter(WebSocketServerResponse.class, new UniversalJsonAdapter<>(WebSocketService.providers));
|
||||
builder.registerTypeAdapter(WebSocketEvent.class, new JsonResultSerializeAdapter());
|
||||
modulesManager.invokeEvent(new PreGsonPhase(builder));
|
||||
//ClientWebSocketService.appendTypeAdapters(builder);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
package pro.gravit.launchserver.manangers;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import pro.gravit.launcher.managers.SimpleModuleManager;
|
||||
import pro.gravit.launcher.managers.SimpleModulesConfigManager;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.modules.CoreModule;
|
||||
import pro.gravit.launchserver.modules.LaunchServerModuleContext;
|
||||
import pro.gravit.utils.PublicURLClassLoader;
|
||||
|
||||
public class ModulesManager extends SimpleModuleManager {
|
||||
public SimpleModulesConfigManager configManager;
|
||||
|
||||
public ModulesManager(LaunchServer lsrv) {
|
||||
modules = new ArrayList<>(1);
|
||||
configManager = new SimpleModulesConfigManager(lsrv.dir.resolve("config"));
|
||||
classloader = new PublicURLClassLoader(new URL[0], ClassLoader.getSystemClassLoader());
|
||||
context = new LaunchServerModuleContext(lsrv, classloader, configManager);
|
||||
registerCoreModule();
|
||||
}
|
||||
|
||||
private void registerCoreModule() {
|
||||
load(new CoreModule());
|
||||
}
|
||||
}
|
|
@ -34,11 +34,11 @@ public void invoke(String... args) throws Exception {
|
|||
|
||||
public void registerReconfigurable(String name, Reconfigurable reconfigurable) {
|
||||
VerifyHelper.putIfAbsent(RECONFIGURABLE, name.toLowerCase(), new ReconfigurableVirtualCommand(reconfigurable.getCommands()),
|
||||
String.format("Reloadable has been already registered: '%s'", name));
|
||||
String.format("Reconfigurable has been already registered: '%s'", name));
|
||||
}
|
||||
|
||||
public void unregisterReconfigurable(String name) {
|
||||
RECONFIGURABLE.remove(name);
|
||||
RECONFIGURABLE.remove(name.toLowerCase());
|
||||
}
|
||||
|
||||
public void call(String name, String action, String[] args) throws Exception
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
package pro.gravit.launchserver.manangers;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
|
||||
import pro.gravit.launchserver.Reloadable;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
import pro.gravit.utils.helper.VerifyHelper;
|
||||
|
||||
public class ReloadManager {
|
||||
private final HashMap<String, Reloadable> RELOADABLES = new HashMap<>();
|
||||
|
||||
public void registerReloadable(String name, Reloadable reloadable) {
|
||||
VerifyHelper.putIfAbsent(RELOADABLES, name.toLowerCase(), Objects.requireNonNull(reloadable, "adapter"),
|
||||
String.format("Reloadable has been already registered: '%s'", name.toLowerCase()));
|
||||
}
|
||||
|
||||
public Reloadable unregisterReloadable(String name) {
|
||||
return RELOADABLES.remove(name);
|
||||
}
|
||||
|
||||
public void reloadAll() {
|
||||
RELOADABLES.forEach((k, v) -> {
|
||||
try {
|
||||
v.reload();
|
||||
} catch (Exception e) {
|
||||
LogHelper.error(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void reload(String name) throws Exception {
|
||||
RELOADABLES.get(name.toLowerCase()).reload();
|
||||
}
|
||||
|
||||
public void printReloadables() {
|
||||
LogHelper.info("Print reloadables");
|
||||
RELOADABLES.forEach((k, v) -> LogHelper.subInfo(k));
|
||||
LogHelper.info("Found %d reloadables", RELOADABLES.size());
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import pro.gravit.launcher.AutogenConfig;
|
||||
import pro.gravit.launchserver.binary.BuildContext;
|
||||
import pro.gravit.launchserver.binary.JAConfigurator;
|
||||
import pro.gravit.launchserver.binary.LauncherConfigurator;
|
||||
import pro.gravit.launchserver.binary.tasks.MainBuildTask;
|
||||
|
||||
public class BuildHookManager {
|
||||
|
@ -75,7 +75,7 @@ public void hook(BuildContext context) {
|
|||
for (BuildHook hook : HOOKS) hook.build(context);
|
||||
}
|
||||
|
||||
public void registerAllClientModuleClass(JAConfigurator cfg) {
|
||||
public void registerAllClientModuleClass(LauncherConfigurator cfg) {
|
||||
for (String clazz : MODULE_CLASS) cfg.addModuleClass(clazz);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ public Type getType() {
|
|||
|
||||
@Override
|
||||
public ModulesManager getModulesManager() {
|
||||
return launchServer.modulesManager;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package pro.gravit.launchserver.modules.events;
|
||||
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
|
||||
public class LaunchServerFullInitEvent extends LauncherModule.Event {
|
||||
public final LaunchServer server;
|
||||
|
||||
public LaunchServerFullInitEvent(LaunchServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package pro.gravit.launchserver.modules.events;
|
||||
|
||||
import pro.gravit.launcher.modules.events.InitPhase;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
|
||||
public class LaunchServerInitPhase extends InitPhase {
|
||||
public final LaunchServer server;
|
||||
|
||||
public LaunchServerInitPhase(LaunchServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package pro.gravit.launchserver.modules.events;
|
||||
|
||||
import pro.gravit.launcher.modules.events.InitPhase;
|
||||
import pro.gravit.launcher.modules.events.PostInitPhase;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
|
||||
public class LaunchServerPostInitPhase extends PostInitPhase {
|
||||
public final LaunchServer server;
|
||||
|
||||
public LaunchServerPostInitPhase(LaunchServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package pro.gravit.launchserver.modules.events;
|
||||
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
|
||||
public class NewLaunchServerInstanceEvent extends LauncherModule.Event {
|
||||
public final LaunchServer launchServer;
|
||||
|
||||
public NewLaunchServerInstanceEvent(LaunchServer launchServer) {
|
||||
this.launchServer = launchServer;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package pro.gravit.launchserver.modules.impl;
|
||||
|
||||
import pro.gravit.launcher.modules.LauncherInitContext;
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
import pro.gravit.launcher.modules.LauncherModuleInfo;
|
||||
import pro.gravit.launcher.modules.events.InitPhase;
|
||||
import pro.gravit.utils.Version;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
||||
public class LaunchServerCoreModule extends LauncherModule {
|
||||
public LaunchServerCoreModule() {
|
||||
super(new LauncherModuleInfo("LaunchServerCore", Version.getVersion()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(LauncherInitContext initContext) {
|
||||
registerEvent(this::testEvent, InitPhase.class);
|
||||
}
|
||||
|
||||
public void testEvent(InitPhase event)
|
||||
{
|
||||
//LogHelper.debug("[LaunchServerCore] Event LaunchServerInitPhase passed");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package pro.gravit.launchserver.modules.impl;
|
||||
|
||||
import pro.gravit.launcher.modules.LauncherInitContext;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
|
||||
public class LaunchServerInitContext implements LauncherInitContext {
|
||||
public final LaunchServer server;
|
||||
|
||||
public LaunchServerInitContext(LaunchServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package pro.gravit.launchserver.modules.impl;
|
||||
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
import pro.gravit.launcher.modules.LauncherModuleInfo;
|
||||
import pro.gravit.launcher.modules.impl.SimpleModuleManager;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class LaunchServerModulesManager extends SimpleModuleManager {
|
||||
public LaunchServerCoreModule coreModule;
|
||||
public LaunchServerModulesManager(Path modulesDir, Path configDir) {
|
||||
super(modulesDir, configDir);
|
||||
coreModule = new LaunchServerCoreModule();
|
||||
modules.add(coreModule);
|
||||
}
|
||||
public void fullInitializedLaunchServer(LaunchServer server)
|
||||
{
|
||||
initContext = new LaunchServerInitContext(server);
|
||||
}
|
||||
public void printModulesInfo()
|
||||
{
|
||||
for(LauncherModule module : modules)
|
||||
{
|
||||
LauncherModuleInfo info = module.getModuleInfo();
|
||||
LogHelper.info("[MODULE] %s v: %s p: %d deps: %s", info.name, info.version.getVersionString(), info.priority, Arrays.toString(info.dependencies));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LauncherModule getCoreModule() {
|
||||
return coreModule;
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
import io.netty.handler.logging.LoggingHandler;
|
||||
import io.netty.util.concurrent.GlobalEventExecutor;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.config.LaunchServerConfig;
|
||||
import pro.gravit.launchserver.socket.handlers.NettyIpForwardHandler;
|
||||
import pro.gravit.launchserver.socket.handlers.WebSocketFrameHandler;
|
||||
import pro.gravit.launchserver.socket.handlers.fileserver.FileServerHandler;
|
||||
|
@ -32,7 +33,7 @@ public class LauncherNettyServer implements AutoCloseable {
|
|||
private static final String WEBSOCKET_PATH = "/api";
|
||||
|
||||
public LauncherNettyServer(LaunchServer server) {
|
||||
LaunchServer.NettyConfig config = server.config.netty;
|
||||
LaunchServerConfig.NettyConfig config = server.config.netty;
|
||||
NettyObjectFactory.setUsingEpoll(config.performance.usingEpoll);
|
||||
if(config.performance.usingEpoll)
|
||||
{
|
||||
|
@ -62,7 +63,7 @@ public void initChannel(SocketChannel ch) {
|
|||
pipeline.addLast(new WebSocketServerCompressionHandler());
|
||||
pipeline.addLast(new WebSocketServerProtocolHandler(WEBSOCKET_PATH, null, true));
|
||||
if (server.config.netty.fileServerEnabled)
|
||||
pipeline.addLast(new FileServerHandler(server.updatesDir, true));
|
||||
pipeline.addLast(new FileServerHandler(server.updatesDir, true, config.showHiddenFiles));
|
||||
pipeline.addLast(new WebSocketFrameHandler(context, server, service));
|
||||
pipelineHook.hook(context, ch);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
import pro.gravit.launcher.ssl.LauncherKeyStore;
|
||||
import pro.gravit.launcher.ssl.LauncherTrustManager;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.config.LaunchServerConfig;
|
||||
import pro.gravit.launchserver.socket.LauncherNettyServer;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
||||
|
@ -90,7 +91,7 @@ public void run() {
|
|||
//SSLEngine engine = sc.createSSLEngine();
|
||||
//engine.setUseClientMode(false);
|
||||
nettyServer = new LauncherNettyServer(server);
|
||||
for (LaunchServer.NettyBindAddress address : server.config.netty.binds) {
|
||||
for (LaunchServerConfig.NettyBindAddress address : server.config.netty.binds) {
|
||||
nettyServer.bind(new InetSocketAddress(address.address, address.port));
|
||||
}
|
||||
/*
|
||||
|
|
|
@ -58,10 +58,12 @@ public class FileServerHandler extends SimpleChannelInboundHandler<FullHttpReque
|
|||
private static final boolean OLD_ALGO = Boolean.parseBoolean(System.getProperty("launcher.fileserver.oldalgo", "true"));
|
||||
private final Path base;
|
||||
private final boolean fullOut;
|
||||
private final boolean showHiddenFiles;
|
||||
|
||||
public FileServerHandler(Path base, boolean fullOut) {
|
||||
public FileServerHandler(Path base, boolean fullOut, boolean showHiddenFiles) {
|
||||
this.base = base;
|
||||
this.fullOut = fullOut;
|
||||
this.showHiddenFiles = showHiddenFiles;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -92,7 +94,7 @@ public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) thr
|
|||
}
|
||||
|
||||
File file = base.resolve(path).toFile();
|
||||
if (file.isHidden() || !file.exists()) {
|
||||
if ((file.isHidden() && !showHiddenFiles) || !file.exists()) {
|
||||
sendError(ctx, NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
@ -100,7 +102,7 @@ public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) thr
|
|||
if (file.isDirectory()) {
|
||||
if (fullOut) {
|
||||
if (uri.endsWith("/")) {
|
||||
sendListing(ctx, file, uri);
|
||||
sendListing(ctx, file, uri, showHiddenFiles);
|
||||
} else {
|
||||
sendRedirect(ctx, uri + '/');
|
||||
}
|
||||
|
@ -182,7 +184,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
|||
|
||||
private static final Pattern ALLOWED_FILE_NAME = Pattern.compile("[^-\\._]?[^<>&\\\"]*");
|
||||
|
||||
private static void sendListing(ChannelHandlerContext ctx, File dir, String dirPath) {
|
||||
private static void sendListing(ChannelHandlerContext ctx, File dir, String dirPath, boolean showHidden) {
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK);
|
||||
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8");
|
||||
|
||||
|
@ -201,7 +203,7 @@ private static void sendListing(ChannelHandlerContext ctx, File dir, String dirP
|
|||
.append("<li><a href=\"../\">..</a></li>\r\n");
|
||||
|
||||
for (File f : dir.listFiles()) {
|
||||
if (f.isHidden() || !f.canRead()) {
|
||||
if (( f.isHidden() && !showHidden) || !f.canRead()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
import pro.gravit.launcher.events.request.UpdateRequestEvent;
|
||||
import pro.gravit.launcher.hasher.HashedDir;
|
||||
import pro.gravit.launcher.profiles.ClientProfile;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.config.LaunchServerConfig;
|
||||
import pro.gravit.launchserver.socket.Client;
|
||||
import pro.gravit.launchserver.socket.response.SimpleResponse;
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
|
@ -41,7 +41,7 @@ public void execute(ChannelHandlerContext ctx, Client client) {
|
|||
String url = server.config.netty.downloadURL.replace("%dirname%", IOHelper.urlEncode(dirName));
|
||||
boolean zip = false;
|
||||
if (server.config.netty.bindings.get(dirName) != null) {
|
||||
LaunchServer.NettyUpdatesBind bind = server.config.netty.bindings.get(dirName);
|
||||
LaunchServerConfig.NettyUpdatesBind bind = server.config.netty.bindings.get(dirName);
|
||||
url = bind.url;
|
||||
zip = bind.zip;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
package pro.gravit.launchserver;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.managers.SimpleModulesConfigManager;
|
||||
import pro.gravit.launchserver.config.LaunchServerConfig;
|
||||
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
||||
import pro.gravit.launchserver.manangers.LaunchServerGsonManager;
|
||||
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
|
||||
import pro.gravit.utils.command.StdCommandHandler;
|
||||
import pro.gravit.utils.helper.SecurityHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.security.KeyPair;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
|
||||
public class StartLaunchServerTest {
|
||||
@TempDir
|
||||
public static Path modulesDir;
|
||||
@TempDir
|
||||
public static Path configDir;
|
||||
@TempDir
|
||||
public static Path dir;
|
||||
public static LaunchServer launchServer;
|
||||
@BeforeAll
|
||||
public static void prepare() throws Exception
|
||||
{
|
||||
LaunchServerModulesManager modulesManager = new LaunchServerModulesManager(modulesDir, configDir);
|
||||
SimpleModulesConfigManager configManager = new SimpleModulesConfigManager(configDir);
|
||||
LaunchServerConfig config = LaunchServerConfig.getDefault(LaunchServer.LaunchServerEnv.TEST);
|
||||
Launcher.gsonManager = new LaunchServerGsonManager(modulesManager);
|
||||
Launcher.gsonManager.initGson();
|
||||
LaunchServerRuntimeConfig runtimeConfig = new LaunchServerRuntimeConfig();
|
||||
LaunchServerBuilder builder = new LaunchServerBuilder();
|
||||
KeyPair pair = SecurityHelper.genRSAKeyPair();
|
||||
RSAPublicKey publicKey = (RSAPublicKey) pair.getPublic();
|
||||
RSAPrivateKey privateKey = (RSAPrivateKey) pair.getPrivate();
|
||||
builder.setDir(dir)
|
||||
.setEnv(LaunchServer.LaunchServerEnv.TEST)
|
||||
.setConfig(config)
|
||||
.setRuntimeConfig(runtimeConfig)
|
||||
.setPublicKey(publicKey)
|
||||
.setPrivateKey(privateKey)
|
||||
.setLaunchServerConfigManager(new LaunchServer.LaunchServerConfigManager() {
|
||||
@Override
|
||||
public LaunchServerConfig readConfig() throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LaunchServerRuntimeConfig readRuntimeConfig() throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeConfig(LaunchServerConfig config) throws IOException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeRuntimeConfig(LaunchServerRuntimeConfig config) throws IOException {
|
||||
|
||||
}
|
||||
})
|
||||
.setModulesManager(modulesManager)
|
||||
.setCommandHandler(new StdCommandHandler(false));
|
||||
launchServer = builder.build();
|
||||
}
|
||||
@Test
|
||||
public void start() throws Exception
|
||||
{
|
||||
launchServer.run();
|
||||
}
|
||||
}
|
|
@ -28,6 +28,16 @@
|
|||
"Multi-Release-Jar": "true")
|
||||
}
|
||||
|
||||
task sourcesJar(type: Jar) {
|
||||
from sourceSets.main.allJava
|
||||
archiveClassifier = 'sources'
|
||||
}
|
||||
|
||||
task javadocJar(type: Jar) {
|
||||
from javadoc
|
||||
archiveClassifier = 'javadoc'
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
classifier = null
|
||||
relocate 'org.objectweb.asm', 'pro.gravit.repackage.org.objectweb.asm'
|
||||
|
@ -62,7 +72,11 @@ task dumpLibs(type: Copy) {
|
|||
publications {
|
||||
launcherclientapi(MavenPublication) {
|
||||
artifactId = 'launcher-client-api'
|
||||
artifact jar
|
||||
artifact(jar) {
|
||||
classifier ""
|
||||
}
|
||||
artifact sourcesJar
|
||||
artifact javadocJar
|
||||
pom {
|
||||
name = 'GravitLauncher Client API'
|
||||
description = 'GravitLauncher Client Module API'
|
||||
|
@ -73,6 +87,18 @@ task dumpLibs(type: Copy) {
|
|||
url = 'https://www.gnu.org/licenses/gpl-3.0.html'
|
||||
}
|
||||
}
|
||||
developers {
|
||||
developer {
|
||||
id = 'gravit'
|
||||
name = 'Gravit'
|
||||
email = 'gravit.min@ya.ru'
|
||||
}
|
||||
developer {
|
||||
id = 'zaxar163'
|
||||
name = 'Zaxar163'
|
||||
email = 'zahar.vcherachny@yandex.ru'
|
||||
}
|
||||
}
|
||||
scm {
|
||||
connection = 'scm:git:https://github.com/GravitLauncher/Launcher.git'
|
||||
developerConnection = 'scm:git:ssh://git@github.com:GravitLauncher/Launcher.git'
|
||||
|
|
|
@ -4,9 +4,11 @@
|
|||
import static org.objectweb.asm.Opcodes.ARETURN;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
@ -31,7 +33,12 @@ public final class LauncherAgent {
|
|||
|
||||
public static void addJVMClassPath(String path) throws IOException {
|
||||
LogHelper.debug("Launcher Agent addJVMClassPath");
|
||||
inst.appendToSystemClassLoaderSearch(new JarFile(path));
|
||||
inst.appendToSystemClassLoaderSearch(new JarFile(new File(path)));
|
||||
}
|
||||
|
||||
public static void addJVMClassPath(Path path) throws IOException {
|
||||
LogHelper.debug("Launcher Agent addJVMClassPath");
|
||||
inst.appendToSystemClassLoaderSearch(new JarFile(path.toFile()));
|
||||
}
|
||||
|
||||
public boolean isAgentStarted() {
|
||||
|
|
|
@ -7,12 +7,18 @@
|
|||
import pro.gravit.launcher.client.DirBridge;
|
||||
import pro.gravit.launcher.client.FunctionalBridge;
|
||||
import pro.gravit.launcher.client.LauncherUpdateController;
|
||||
import pro.gravit.launcher.client.events.ClientEngineInitPhase;
|
||||
import pro.gravit.launcher.client.events.ClientPreGuiPhase;
|
||||
import pro.gravit.launcher.guard.LauncherGuardManager;
|
||||
import pro.gravit.launcher.gui.JSRuntimeProvider;
|
||||
import pro.gravit.launcher.gui.RuntimeProvider;
|
||||
import pro.gravit.launcher.hwid.HWIDProvider;
|
||||
import pro.gravit.launcher.managers.ClientGsonManager;
|
||||
import pro.gravit.launcher.managers.ClientHookManager;
|
||||
import pro.gravit.launcher.managers.ConsoleManager;
|
||||
import pro.gravit.launcher.modules.LauncherModulesManager;
|
||||
import pro.gravit.launcher.modules.events.PreConfigPhase;
|
||||
import pro.gravit.launcher.modules.impl.SimpleModuleManager;
|
||||
import pro.gravit.launcher.request.Request;
|
||||
import pro.gravit.launcher.request.RequestException;
|
||||
import pro.gravit.launcher.request.auth.RestoreSessionRequest;
|
||||
|
@ -32,10 +38,15 @@ public static void main(String... args) throws Throwable {
|
|||
//if(!LauncherAgent.isStarted()) throw new SecurityException("JavaAgent not set");
|
||||
LogHelper.printVersion("Launcher");
|
||||
LogHelper.printLicense("Launcher");
|
||||
|
||||
LauncherEngine.modulesManager = new ClientModuleManager();
|
||||
LauncherConfig.getAutogenConfig().initModules();
|
||||
LauncherEngine.modulesManager.initModules(null);
|
||||
// Start Launcher
|
||||
initGson();
|
||||
initGson(LauncherEngine.modulesManager);
|
||||
ConsoleManager.initConsole();
|
||||
HWIDProvider.registerHWIDs();
|
||||
LauncherEngine.modulesManager.invokeEvent(new PreConfigPhase());
|
||||
LauncherConfig config = Launcher.getConfig();
|
||||
if (config.environment.equals(LauncherConfig.LauncherEnvironment.PROD)) {
|
||||
if (!LauncherAgent.isStarted()) throw new SecurityException("LauncherAgent must started");
|
||||
|
@ -54,8 +65,8 @@ public static void main(String... args) throws Throwable {
|
|||
System.exit(0);
|
||||
}
|
||||
|
||||
public static void initGson() {
|
||||
Launcher.gsonManager = new ClientGsonManager();
|
||||
public static void initGson(ClientModuleManager modulesManager) {
|
||||
Launcher.gsonManager = new ClientGsonManager(modulesManager);
|
||||
Launcher.gsonManager.initGson();
|
||||
}
|
||||
|
||||
|
@ -63,6 +74,8 @@ public static void initGson() {
|
|||
private final AtomicBoolean started = new AtomicBoolean(false);
|
||||
public RuntimeProvider runtimeProvider;
|
||||
|
||||
public static ClientModuleManager modulesManager;
|
||||
|
||||
private LauncherEngine() {
|
||||
|
||||
}
|
||||
|
@ -70,12 +83,14 @@ private LauncherEngine() {
|
|||
|
||||
@LauncherAPI
|
||||
public void start(String... args) throws Throwable {
|
||||
Launcher.modulesManager = new ClientModuleManager(this);
|
||||
LauncherConfig.getAutogenConfig().initModules();
|
||||
Launcher.modulesManager.preInitModules();
|
||||
//Launcher.modulesManager = new ClientModuleManager(this);
|
||||
ClientPreGuiPhase event = new ClientPreGuiPhase(null);
|
||||
LauncherEngine.modulesManager.invokeEvent(event);
|
||||
runtimeProvider = event.runtimeProvider;
|
||||
if (runtimeProvider == null) runtimeProvider = new JSRuntimeProvider();
|
||||
ClientHookManager.initGuiHook.hook(runtimeProvider);
|
||||
runtimeProvider.init(false);
|
||||
runtimeProvider.preLoad();
|
||||
//runtimeProvider.preLoad();
|
||||
if (Request.service == null) {
|
||||
String address = Launcher.getConfig().address;
|
||||
LogHelper.debug("Start async connection to %s", address);
|
||||
|
@ -99,11 +114,11 @@ public void start(String... args) throws Throwable {
|
|||
};
|
||||
}
|
||||
LauncherGuardManager.initGuard(false);
|
||||
UpdateRequest.setController(new LauncherUpdateController());
|
||||
if(UpdateRequest.getController() == null) UpdateRequest.setController(new LauncherUpdateController());
|
||||
Objects.requireNonNull(args, "args");
|
||||
if (started.getAndSet(true))
|
||||
throw new IllegalStateException("Launcher has been already started");
|
||||
Launcher.modulesManager.initModules();
|
||||
LauncherEngine.modulesManager.invokeEvent(new ClientEngineInitPhase(this));
|
||||
runtimeProvider.preLoad();
|
||||
FunctionalBridge.getHWID = CommonHelper.newThread("GetHWID Thread", true, FunctionalBridge::getHWID);
|
||||
FunctionalBridge.getHWID.start();
|
||||
|
|
|
@ -32,12 +32,16 @@
|
|||
import pro.gravit.launcher.LauncherAgent;
|
||||
import pro.gravit.launcher.LauncherConfig;
|
||||
import pro.gravit.launcher.LauncherEngine;
|
||||
import pro.gravit.launcher.client.events.ClientLauncherInitPhase;
|
||||
import pro.gravit.launcher.guard.LauncherGuardManager;
|
||||
import pro.gravit.launcher.gui.JSRuntimeProvider;
|
||||
import pro.gravit.launcher.hasher.FileNameMatcher;
|
||||
import pro.gravit.launcher.hasher.HashedDir;
|
||||
import pro.gravit.launcher.hwid.HWIDProvider;
|
||||
import pro.gravit.launcher.managers.ClientGsonManager;
|
||||
import pro.gravit.launcher.managers.ClientHookManager;
|
||||
import pro.gravit.launcher.modules.events.PostInitPhase;
|
||||
import pro.gravit.launcher.modules.events.PreConfigPhase;
|
||||
import pro.gravit.launcher.profiles.ClientProfile;
|
||||
import pro.gravit.launcher.profiles.PlayerProfile;
|
||||
import pro.gravit.launcher.request.Request;
|
||||
|
@ -341,6 +345,7 @@ public static Process launch(
|
|||
output.writeString(Launcher.gsonManager.gson.toJson(profile), 0);
|
||||
assetHDir.write(output);
|
||||
clientHDir.write(output);
|
||||
ClientHookManager.paramsOutputHook.hook(output);
|
||||
}
|
||||
clientStarted = true;
|
||||
}
|
||||
|
@ -383,8 +388,10 @@ public static Process launch(
|
|||
profile.pushOptionalJvmArgs(context.args);
|
||||
Collections.addAll(context.args, "-Djava.library.path=".concat(params.clientDir.resolve(NATIVES_DIR).toString())); // Add Native Path
|
||||
Collections.addAll(context.args, "-javaagent:".concat(pathLauncher));
|
||||
ClientHookManager.clientLaunchHook.hook(context);
|
||||
LauncherGuardManager.guard.addCustomParams(context);
|
||||
Collections.addAll(context.args, ClientLauncher.class.getName());
|
||||
ClientHookManager.clientLaunchFinallyHook.hook(context);
|
||||
|
||||
// Print commandline debug message
|
||||
LogHelper.debug("Commandline: " + context.args);
|
||||
|
@ -404,7 +411,9 @@ public static Process launch(
|
|||
builder.redirectOutput(Redirect.PIPE);
|
||||
}
|
||||
// Let's rock!
|
||||
ClientHookManager.preStartHook.hook(context, builder);
|
||||
process = builder.start();
|
||||
if(ClientHookManager.postStartHook.hook(context, builder)) return process;
|
||||
if (!pipeOutput) {
|
||||
for (int i = 0; i < 50; ++i) {
|
||||
if (!process.isAlive()) {
|
||||
|
@ -429,10 +438,13 @@ public static Process launch(
|
|||
@LauncherAPI
|
||||
public static void main(String... args) throws Throwable {
|
||||
LauncherEngine engine = LauncherEngine.clientInstance();
|
||||
Launcher.modulesManager = new ClientModuleManager(engine);
|
||||
//Launcher.modulesManager = new ClientModuleManager(engine);
|
||||
LauncherEngine.modulesManager = new ClientModuleManager();
|
||||
LauncherConfig.getAutogenConfig().initModules(); //INIT
|
||||
initGson();
|
||||
Launcher.modulesManager.preInitModules();
|
||||
LauncherEngine.modulesManager.initModules(null);
|
||||
initGson(LauncherEngine.modulesManager);
|
||||
//Launcher.modulesManager.preInitModules();
|
||||
LauncherEngine.modulesManager.invokeEvent(new PreConfigPhase());
|
||||
JVMHelper.verifySystemProperties(ClientLauncher.class, true);
|
||||
EnvHelper.checkDangerousParams();
|
||||
JVMHelper.checkStackTrace(ClientLauncher.class);
|
||||
|
@ -454,6 +466,7 @@ public static void main(String... args) throws Throwable {
|
|||
profile = Launcher.gsonManager.gson.fromJson(input.readString(0), ClientProfile.class);
|
||||
assetHDir = new HashedDir(input);
|
||||
clientHDir = new HashedDir(input);
|
||||
ClientHookManager.paramsInputHook.hook(input);
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
|
@ -465,17 +478,17 @@ public static void main(String... args) throws Throwable {
|
|||
playerProfile = params.pp;
|
||||
Request.setSession(params.session);
|
||||
checkJVMBitsAndVersion();
|
||||
Launcher.modulesManager.initModules();
|
||||
LauncherEngine.modulesManager.invokeEvent(new ClientLauncherInitPhase());
|
||||
// Verify ClientLauncher sign and classpath
|
||||
LogHelper.debug("Verifying ClientLauncher sign and classpath");
|
||||
LinkedList<Path> classPath = resolveClassPathList(params.clientDir, profile.getClassPath());
|
||||
for (Path classpathURL : classPath) {
|
||||
LauncherAgent.addJVMClassPath(classpathURL.toAbsolutePath().toString());
|
||||
LauncherAgent.addJVMClassPath(classpathURL.normalize().toAbsolutePath());
|
||||
}
|
||||
profile.pushOptionalClassPath(cp -> {
|
||||
LinkedList<Path> optionalClassPath = resolveClassPathList(params.clientDir, cp);
|
||||
for (Path classpathURL : optionalClassPath) {
|
||||
LauncherAgent.addJVMClassPath(classpathURL.toAbsolutePath().toString());
|
||||
LauncherAgent.addJVMClassPath(classpathURL.normalize().toAbsolutePath());
|
||||
}
|
||||
});
|
||||
URL[] classpathurls = resolveClassPath(params.clientDir, profile.getClassPath());
|
||||
|
@ -517,7 +530,7 @@ public static void main(String... args) throws Throwable {
|
|||
// else hdir.removeR(s.file);
|
||||
//}
|
||||
Launcher.profile.pushOptionalFile(clientHDir, false);
|
||||
Launcher.modulesManager.postInitModules();
|
||||
LauncherEngine.modulesManager.invokeEvent(new PostInitPhase());
|
||||
// Start WatchService, and only then client
|
||||
CommonHelper.newThread("Asset Directory Watcher", true, assetWatcher).start();
|
||||
CommonHelper.newThread("Client Directory Watcher", true, clientWatcher).start();
|
||||
|
@ -548,8 +561,8 @@ private static Stream<Path> resolveClassPathStream(Path clientDir, String... cla
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
private static void initGson() {
|
||||
Launcher.gsonManager = new ClientGsonManager();
|
||||
private static void initGson(ClientModuleManager moduleManager) {
|
||||
Launcher.gsonManager = new ClientGsonManager(moduleManager);
|
||||
Launcher.gsonManager.initGson();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
package pro.gravit.launcher.client;
|
||||
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.LauncherEngine;
|
||||
import pro.gravit.launcher.modules.ModuleContext;
|
||||
import pro.gravit.launcher.modules.ModulesConfigManager;
|
||||
import pro.gravit.launcher.modules.ModulesManager;
|
||||
|
||||
public class ClientModuleContext implements ModuleContext {
|
||||
public final LauncherEngine engine;
|
||||
|
||||
ClientModuleContext(LauncherEngine engine) {
|
||||
this.engine = engine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return Type.CLIENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModulesManager getModulesManager() {
|
||||
return Launcher.modulesManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModulesConfigManager getModulesConfigManager() {
|
||||
return null; // ClientModuleContext не поддерживает modulesConfigManager
|
||||
}
|
||||
}
|
|
@ -1,25 +1,28 @@
|
|||
package pro.gravit.launcher.client;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
import pro.gravit.launcher.modules.impl.SimpleModuleManager;
|
||||
|
||||
import pro.gravit.launcher.LauncherEngine;
|
||||
import pro.gravit.launcher.managers.SimpleModuleManager;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class ClientModuleManager extends SimpleModuleManager {
|
||||
|
||||
public ClientModuleManager(LauncherEngine engine) {
|
||||
context = new ClientModuleContext(engine);
|
||||
modules = new ArrayList<>();
|
||||
public ClientModuleManager() {
|
||||
super(null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadModule(URL jarpath, String classname) {
|
||||
throw new SecurityException("Custom JAR's load not allowed here");
|
||||
public void autoload() throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadModuleFull(URL jarpath) {
|
||||
throw new SecurityException("Custom JAR's load not allowed here");
|
||||
public void autoload(Path dir) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LauncherModule loadModule(Path file) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ public class FunctionalBridge {
|
|||
@LauncherAPI
|
||||
public static ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(0);
|
||||
@LauncherAPI
|
||||
public static OshiHWIDProvider hwidProvider = new OshiHWIDProvider();
|
||||
public static OshiHWIDProvider hwidProvider;
|
||||
@LauncherAPI
|
||||
public static AtomicReference<HWID> hwid = new AtomicReference<>();
|
||||
@LauncherAPI
|
||||
|
@ -51,14 +51,18 @@ public static void startTask(Runnable task) {
|
|||
@LauncherAPI
|
||||
public static HWID getHWID() {
|
||||
HWID hhwid = hwid.get();
|
||||
if (hhwid == null) hwid.set(hwidProvider.getHWID());
|
||||
if (hhwid == null) {
|
||||
if(hwidProvider == null) hwidProvider = new OshiHWIDProvider();
|
||||
hwid.set(hwidProvider.getHWID());
|
||||
}
|
||||
return hhwid;
|
||||
}
|
||||
|
||||
@LauncherAPI
|
||||
public static int getTotalMemory() {
|
||||
if (cachedMemorySize > 0) return (int) cachedMemorySize;
|
||||
return (int) (cachedMemorySize = hwidProvider.getTotalMemory() >> 20);
|
||||
public static long getTotalMemory() {
|
||||
if (cachedMemorySize > 0) return cachedMemorySize;
|
||||
if(hwidProvider == null) hwidProvider = new OshiHWIDProvider();
|
||||
return (cachedMemorySize = hwidProvider.getTotalMemory() >> 20);
|
||||
}
|
||||
|
||||
@LauncherAPI
|
||||
|
@ -67,7 +71,7 @@ public static int getClientJVMBits() {
|
|||
}
|
||||
|
||||
@LauncherAPI
|
||||
public static int getJVMTotalMemory() {
|
||||
public static long getJVMTotalMemory() {
|
||||
if (getClientJVMBits() == 32) {
|
||||
return Math.min(getTotalMemory(), 1536);
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package pro.gravit.launcher.client.events;
|
||||
|
||||
import pro.gravit.launcher.LauncherEngine;
|
||||
import pro.gravit.launcher.modules.events.InitPhase;
|
||||
|
||||
public class ClientEngineInitPhase extends InitPhase {
|
||||
public final LauncherEngine engine;
|
||||
|
||||
public ClientEngineInitPhase(LauncherEngine engine) {
|
||||
this.engine = engine;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package pro.gravit.launcher.client.events;
|
||||
|
||||
import pro.gravit.launcher.gui.RuntimeProvider;
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
|
||||
public class ClientGuiPhase extends LauncherModule.Event {
|
||||
public final RuntimeProvider runtimeProvider;
|
||||
|
||||
public ClientGuiPhase(RuntimeProvider runtimeProvider) {
|
||||
this.runtimeProvider = runtimeProvider;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package pro.gravit.launcher.client.events;
|
||||
|
||||
import pro.gravit.launcher.modules.events.InitPhase;
|
||||
|
||||
public class ClientLauncherInitPhase extends InitPhase {
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package pro.gravit.launcher.client.events;
|
||||
|
||||
import pro.gravit.launcher.gui.RuntimeProvider;
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
|
||||
public class ClientPreGuiPhase extends LauncherModule.Event {
|
||||
public RuntimeProvider runtimeProvider;
|
||||
|
||||
public ClientPreGuiPhase(RuntimeProvider runtimeProvider) {
|
||||
this.runtimeProvider = runtimeProvider;
|
||||
}
|
||||
}
|
|
@ -11,16 +11,13 @@
|
|||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
import pro.gravit.launcher.JSApplication;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.LauncherAPI;
|
||||
import pro.gravit.launcher.LauncherConfig;
|
||||
import pro.gravit.launcher.NewLauncherSettings;
|
||||
import pro.gravit.launcher.*;
|
||||
import pro.gravit.launcher.client.ClientLauncher;
|
||||
import pro.gravit.launcher.client.DirBridge;
|
||||
import pro.gravit.launcher.client.FunctionalBridge;
|
||||
import pro.gravit.launcher.client.ServerPinger;
|
||||
import pro.gravit.launcher.client.UserSettings;
|
||||
import pro.gravit.launcher.client.events.ClientGuiPhase;
|
||||
import pro.gravit.launcher.hasher.FileNameMatcher;
|
||||
import pro.gravit.launcher.hasher.HashedDir;
|
||||
import pro.gravit.launcher.hasher.HashedEntry;
|
||||
|
@ -28,6 +25,7 @@
|
|||
import pro.gravit.launcher.hwid.NoHWID;
|
||||
import pro.gravit.launcher.hwid.OshiHWID;
|
||||
import pro.gravit.launcher.managers.SettingsManager;
|
||||
import pro.gravit.launcher.modules.events.ClosePhase;
|
||||
import pro.gravit.launcher.profiles.ClientProfile;
|
||||
import pro.gravit.launcher.profiles.PlayerProfile;
|
||||
import pro.gravit.launcher.profiles.Texture;
|
||||
|
@ -163,9 +161,9 @@ public void run(String[] args) throws ScriptException, NoSuchMethodException, IO
|
|||
preLoad();
|
||||
loadScript(Launcher.INIT_SCRIPT_FILE);
|
||||
LogHelper.info("Invoking start() function");
|
||||
Launcher.modulesManager.postInitModules();
|
||||
LauncherEngine.modulesManager.invokeEvent(new ClientGuiPhase(this));
|
||||
((Invocable) engine).invokeFunction("start", (Object) args);
|
||||
Launcher.modulesManager.finishModules();
|
||||
LauncherEngine.modulesManager.invokeEvent(new ClosePhase());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -2,18 +2,27 @@
|
|||
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
import pro.gravit.launcher.client.ClientModuleManager;
|
||||
import pro.gravit.launcher.client.UserSettings;
|
||||
import pro.gravit.launcher.hwid.HWID;
|
||||
import pro.gravit.launcher.hwid.HWIDProvider;
|
||||
import pro.gravit.launcher.modules.events.PreGsonPhase;
|
||||
import pro.gravit.launcher.request.websockets.ClientWebSocketService;
|
||||
import pro.gravit.utils.UniversalJsonAdapter;
|
||||
|
||||
public class ClientGsonManager extends GsonManager {
|
||||
private final ClientModuleManager moduleManager;
|
||||
|
||||
public ClientGsonManager(ClientModuleManager moduleManager) {
|
||||
this.moduleManager = moduleManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerAdapters(GsonBuilder builder) {
|
||||
super.registerAdapters(builder);
|
||||
builder.registerTypeAdapter(UserSettings.class, new UniversalJsonAdapter<>(UserSettings.providers));
|
||||
builder.registerTypeAdapter(HWID.class, new UniversalJsonAdapter<>(HWIDProvider.hwids));
|
||||
ClientWebSocketService.appendTypeAdapters(builder);
|
||||
moduleManager.invokeEvent(new PreGsonPhase(builder));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package pro.gravit.launcher.managers;
|
||||
|
||||
import pro.gravit.launcher.client.ClientLauncherContext;
|
||||
import pro.gravit.launcher.gui.RuntimeProvider;
|
||||
import pro.gravit.launcher.serialize.HInput;
|
||||
import pro.gravit.launcher.serialize.HOutput;
|
||||
import pro.gravit.utils.BiHookSet;
|
||||
import pro.gravit.utils.HookSet;
|
||||
|
||||
public class ClientHookManager {
|
||||
public static HookSet<RuntimeProvider> initGuiHook = new HookSet<>();
|
||||
public static HookSet<HInput> paramsInputHook = new HookSet<>();
|
||||
public static HookSet<HOutput> paramsOutputHook = new HookSet<>();
|
||||
|
||||
public static HookSet<ClientLauncherContext> clientLaunchHook = new HookSet<>();
|
||||
public static HookSet<ClientLauncherContext> clientLaunchFinallyHook = new HookSet<>();
|
||||
|
||||
public static BiHookSet<ClientLauncherContext, ProcessBuilder> preStartHook = new BiHookSet<>();
|
||||
public static BiHookSet<ClientLauncherContext, ProcessBuilder> postStartHook = new BiHookSet<>();
|
||||
}
|
|
@ -5,17 +5,39 @@
|
|||
compile project(':LauncherCore')
|
||||
compileOnly 'org.apache.httpcomponents:httpclient:4.5.7'
|
||||
compileOnly 'io.netty:netty-codec-http:4.1.36.Final'
|
||||
testCompile 'org.junit.jupiter:junit-jupiter:5.4.1'
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
testLogging {
|
||||
events "passed", "skipped", "failed"
|
||||
}
|
||||
}
|
||||
|
||||
jar {
|
||||
classifier = 'clean'
|
||||
}
|
||||
|
||||
task sourcesJar(type: Jar) {
|
||||
from sourceSets.main.allJava
|
||||
archiveClassifier = 'sources'
|
||||
}
|
||||
|
||||
task javadocJar(type: Jar) {
|
||||
from javadoc
|
||||
archiveClassifier = 'javadoc'
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
launcherwsapi(MavenPublication) {
|
||||
artifactId = 'launcher-ws-api'
|
||||
artifact jar
|
||||
artifact(jar) {
|
||||
classifier ""
|
||||
}
|
||||
artifact sourcesJar
|
||||
artifact javadocJar
|
||||
pom {
|
||||
name = 'GravitLauncher WebSocket API'
|
||||
description = 'GravitLauncher WebSocket Module API'
|
||||
|
@ -26,6 +48,18 @@ compile project(':LauncherCore')
|
|||
url = 'https://www.gnu.org/licenses/gpl-3.0.html'
|
||||
}
|
||||
}
|
||||
developers {
|
||||
developer {
|
||||
id = 'gravit'
|
||||
name = 'Gravit'
|
||||
email = 'gravit.min@ya.ru'
|
||||
}
|
||||
developer {
|
||||
id = 'zaxar163'
|
||||
name = 'Zaxar163'
|
||||
email = 'zahar.vcherachny@yandex.ru'
|
||||
}
|
||||
}
|
||||
scm {
|
||||
connection = 'scm:git:https://github.com/GravitLauncher/Launcher.git'
|
||||
developerConnection = 'scm:git:ssh://git@github.com:GravitLauncher/Launcher.git'
|
||||
|
|
|
@ -34,8 +34,6 @@ public final class Launcher {
|
|||
|
||||
private static final AtomicReference<LauncherConfig> CONFIG = new AtomicReference<>();
|
||||
@LauncherAPI
|
||||
public static ModulesManager modulesManager = null;
|
||||
@LauncherAPI
|
||||
public static final int PROTOCOL_MAGIC_LEGACY = 0x724724_00 + 24;
|
||||
@LauncherAPI
|
||||
public static final int PROTOCOL_MAGIC = 0xA205B064; // e = 2.718281828
|
||||
|
|
|
@ -1,158 +0,0 @@
|
|||
package pro.gravit.launcher.managers;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
import pro.gravit.launcher.modules.Module;
|
||||
import pro.gravit.launcher.modules.ModuleContext;
|
||||
import pro.gravit.launcher.modules.ModulesManager;
|
||||
import pro.gravit.utils.PublicURLClassLoader;
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
||||
public class SimpleModuleManager implements ModulesManager {
|
||||
protected final class ModulesVisitor extends SimpleFileVisitor<Path> {
|
||||
private ModulesVisitor() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
if (file.toFile().getName().endsWith(".jar"))
|
||||
try (JarFile f = new JarFile(file.toFile())) {
|
||||
String mainclass = f.getManifest().getMainAttributes().getValue("Main-Class");
|
||||
if(mainclass == null)
|
||||
{
|
||||
LogHelper.error("In module %s Main-Class not found", file.toString());
|
||||
return super.visitFile(file, attrs);
|
||||
}
|
||||
loadModule(file.toUri().toURL(), mainclass);
|
||||
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
|
||||
LogHelper.error(e);
|
||||
}
|
||||
return super.visitFile(file, attrs);
|
||||
}
|
||||
}
|
||||
|
||||
public ArrayList<Module> modules;
|
||||
public PublicURLClassLoader classloader;
|
||||
protected ModuleContext context;
|
||||
|
||||
|
||||
public void autoload(Path dir) throws IOException {
|
||||
LogHelper.info("Load modules");
|
||||
if (Files.notExists(dir)) Files.createDirectory(dir);
|
||||
else {
|
||||
IOHelper.walk(dir, new ModulesVisitor(), true);
|
||||
}
|
||||
sort();
|
||||
LogHelper.info("Loaded %d modules", modules.size());
|
||||
}
|
||||
|
||||
public void sort() {
|
||||
modules.sort((m1, m2) -> {
|
||||
int p1 = m1.getPriority();
|
||||
int p2 = m2.getPriority();
|
||||
return Integer.compare(p2, p1);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
for (Module m : modules)
|
||||
try {
|
||||
m.close();
|
||||
} catch (Throwable t) {
|
||||
if (m.getName() != null) LogHelper.error("Error in stopping module: %s", m.getName());
|
||||
else LogHelper.error("Error in stopping one of modules");
|
||||
LogHelper.error(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initModules() {
|
||||
for (Module m : modules) {
|
||||
m.init(context);
|
||||
LogHelper.info("Module %s version: %s init", m.getName(), m.getVersion());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Module module) {
|
||||
modules.add(module);
|
||||
}
|
||||
|
||||
public void loadModuleFull(URL jarpath) throws ClassNotFoundException, IllegalAccessException, InstantiationException, URISyntaxException, IOException {
|
||||
try (JarFile f = new JarFile(Paths.get(jarpath.toURI()).toFile())) {
|
||||
classloader.addURL(jarpath);
|
||||
Module module = (Module) Class.forName(f.getManifest().getMainAttributes().getValue("Main-Class"), true, classloader).newInstance();
|
||||
modules.add(module);
|
||||
module.preInit(context);
|
||||
module.init(context);
|
||||
module.postInit(context);
|
||||
module.finish(context);
|
||||
LogHelper.info("Module %s version: %s loaded", module.getName(), module.getVersion());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadModule(URL jarpath) throws Exception {
|
||||
try (JarFile f = new JarFile(Paths.get(jarpath.toURI()).toFile())) {
|
||||
loadModule(jarpath, f.getManifest().getMainAttributes().getValue("Main-Class"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadModule(URL jarpath, String classname) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
|
||||
classloader.addURL(jarpath);
|
||||
Module module = (Module) Class.forName(classname, true, classloader).newInstance();
|
||||
modules.add(module);
|
||||
LogHelper.info("Module %s version: %s loaded", module.getName(), module.getVersion());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInitModules() {
|
||||
for (Module m : modules) {
|
||||
m.postInit(context);
|
||||
LogHelper.info("Module %s version: %s post-init", m.getName(), m.getVersion());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void preInitModules() {
|
||||
for (Module m : modules) {
|
||||
m.preInit(context);
|
||||
LogHelper.info("Module %s version: %s pre-init", m.getName(), m.getVersion());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printModules() {
|
||||
for (Module m : modules)
|
||||
LogHelper.info("Module %s version: %s", m.getName(), m.getVersion());
|
||||
LogHelper.info("Loaded %d modules", modules.size());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerModule(Module module) {
|
||||
modules.add(module);
|
||||
LogHelper.info("Module %s version: %s registered", module.getName(), module.getVersion());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishModules() {
|
||||
for (Module m : modules) {
|
||||
m.finish(context);
|
||||
LogHelper.info("Module %s version: %s finished initialization", m.getName(), m.getVersion());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,14 +16,12 @@ public SimpleModulesConfigManager(Path configDir) {
|
|||
}
|
||||
|
||||
public Path getModuleConfig(String moduleName) {
|
||||
if (!IOHelper.isDir(configDir)) {
|
||||
try {
|
||||
Files.createDirectories(configDir);
|
||||
} catch (IOException e) {
|
||||
LogHelper.error(e);
|
||||
}
|
||||
}
|
||||
return configDir.resolve(moduleName.concat("Config.json"));
|
||||
return getModuleConfig(moduleName, "Config");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getModuleConfig(String moduleName, String configName) {
|
||||
return getModuleConfigDir(moduleName).resolve(moduleName.concat(configName.concat(".json")));
|
||||
}
|
||||
|
||||
public Path getModuleConfigDir(String moduleName) {
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
package pro.gravit.launcher.modules;
|
||||
|
||||
public interface LauncherInitContext {
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
package pro.gravit.launcher.modules;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class LauncherModule {
|
||||
private LauncherModulesContext context;
|
||||
|
||||
private Map<Class<? extends Event>, EventHandler> eventMap = new HashMap<>();
|
||||
protected LauncherModulesManager modulesManager;
|
||||
protected final LauncherModuleInfo moduleInfo;
|
||||
protected ModulesConfigManager modulesConfigManager;
|
||||
protected InitStatus initStatus = InitStatus.CREATED;
|
||||
|
||||
protected LauncherModule() {
|
||||
moduleInfo = new LauncherModuleInfo("UnknownModule");
|
||||
}
|
||||
|
||||
protected LauncherModule(LauncherModuleInfo info) {
|
||||
moduleInfo = info;
|
||||
}
|
||||
|
||||
public LauncherModuleInfo getModuleInfo() {
|
||||
return moduleInfo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Module initialization status at the current time
|
||||
* CREATED - Module status immediately after loading
|
||||
* INIT - The state of the module during the execution of the method init()
|
||||
* FINISH - Status of the module after initialization
|
||||
*/
|
||||
public enum InitStatus
|
||||
{
|
||||
CREATED(false),
|
||||
PRE_INIT_WAIT(true),
|
||||
PRE_INIT(false),
|
||||
INIT_WAIT(true),
|
||||
INIT(false),
|
||||
FINISH(true);
|
||||
|
||||
InitStatus(boolean b) {
|
||||
isAvailable = b;
|
||||
}
|
||||
|
||||
public boolean isAvailable() {
|
||||
return isAvailable;
|
||||
}
|
||||
|
||||
private final boolean isAvailable;
|
||||
}
|
||||
@FunctionalInterface
|
||||
public interface EventHandler<T extends Event>
|
||||
{
|
||||
void event(T e);
|
||||
}
|
||||
public static class Event
|
||||
{
|
||||
public boolean isCancel() {
|
||||
return cancel;
|
||||
}
|
||||
|
||||
public Event cancel() {
|
||||
this.cancel = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected boolean cancel = false;
|
||||
}
|
||||
|
||||
public InitStatus getInitStatus() {
|
||||
return initStatus;
|
||||
}
|
||||
|
||||
public LauncherModule setInitStatus(InitStatus initStatus) {
|
||||
this.initStatus = initStatus;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The internal method used by the ModuleManager
|
||||
* DO NOT TOUCH
|
||||
* @param context Private context
|
||||
*/
|
||||
public void setContext(LauncherModulesContext context)
|
||||
{
|
||||
if(this.context != null) throw new IllegalStateException("Module already set context");
|
||||
this.context = context;
|
||||
this.modulesManager = context.getModulesManager();
|
||||
this.modulesConfigManager = context.getModulesConfigManager();
|
||||
this.setInitStatus(InitStatus.PRE_INIT_WAIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called before initializing all modules and resolving dependencies.
|
||||
* <b>You can</b>:
|
||||
* Use to Module Manager
|
||||
* Add custom modules not described in the manifest
|
||||
* Change information about your module or modules you control
|
||||
* <b>You can not</b>:
|
||||
* Use your dependencies
|
||||
* Use API Launcher, LaunchServer, ServerWrapper
|
||||
* Change the names of any modules
|
||||
*/
|
||||
public void preInitAction() {
|
||||
//NOP
|
||||
}
|
||||
public LauncherModule preInit()
|
||||
{
|
||||
if(!initStatus.equals(InitStatus.PRE_INIT_WAIT)) throw new IllegalStateException("PreInit not allowed in current state");
|
||||
initStatus = InitStatus.PRE_INIT;
|
||||
preInitAction();
|
||||
initStatus = InitStatus.INIT_WAIT;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic module initialization method
|
||||
* <b>You can</b>:
|
||||
* Subscribe to events
|
||||
* Use your dependencies
|
||||
* Use provided initContext
|
||||
* Receive modules and access the module’s internal methods
|
||||
* <b>You can not</b>:
|
||||
* Modify module description, dependencies
|
||||
* Add modules
|
||||
* Read configuration
|
||||
* @param initContext <b>null</b> on module initialization during boot or startup
|
||||
* Not <b>null</b> during module initialization while running
|
||||
*/
|
||||
public abstract void init(LauncherInitContext initContext);
|
||||
|
||||
|
||||
/**
|
||||
* Registers an event handler for the current module
|
||||
* @param handle your event handler
|
||||
* @param tClass event class
|
||||
* @param <T> event type
|
||||
* @return true if adding a handler was successful
|
||||
*/
|
||||
protected <T extends Event> boolean registerEvent(EventHandler<T> handle, Class<T> tClass)
|
||||
{
|
||||
eventMap.put(tClass, handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the handler of the current module
|
||||
* @param event event handled
|
||||
* @param <T> event type
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public final <T extends Event> void callEvent(T event)
|
||||
{
|
||||
Class<? extends Event> tClass = event.getClass();
|
||||
for(Map.Entry<Class<? extends Event>, EventHandler> e : eventMap.entrySet())
|
||||
{
|
||||
|
||||
if(e.getKey().isAssignableFrom(tClass))
|
||||
{
|
||||
e.getValue().event(event);
|
||||
if(event.isCancel()) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package pro.gravit.launcher.modules;
|
||||
|
||||
import pro.gravit.utils.Version;
|
||||
|
||||
public class LauncherModuleInfo {
|
||||
public final String name;
|
||||
public final Version version;
|
||||
public final int priority;
|
||||
public final String[] dependencies;
|
||||
public final String[] providers;
|
||||
|
||||
public LauncherModuleInfo(String name, Version version) {
|
||||
this.name = name;
|
||||
this.version = version;
|
||||
this.priority = 0;
|
||||
this.dependencies = new String[]{};
|
||||
providers = new String[0];
|
||||
}
|
||||
|
||||
public LauncherModuleInfo(String name) {
|
||||
this.name = name;
|
||||
this.version = new Version(1,0,0);
|
||||
this.priority = 0;
|
||||
this.dependencies = new String[]{};
|
||||
providers = new String[0];
|
||||
}
|
||||
|
||||
public LauncherModuleInfo(String name, Version version, String[] dependencies) {
|
||||
this.name = name;
|
||||
this.version = version;
|
||||
this.priority = 0;
|
||||
this.dependencies = dependencies;
|
||||
providers = new String[0];
|
||||
}
|
||||
|
||||
public LauncherModuleInfo(String name, Version version, int priority, String[] dependencies) {
|
||||
this.name = name;
|
||||
this.version = version;
|
||||
this.priority = priority;
|
||||
this.dependencies = dependencies;
|
||||
providers = new String[0];
|
||||
}
|
||||
|
||||
public LauncherModuleInfo(String name, Version version, int priority, String[] dependencies, String[] providers) {
|
||||
this.name = name;
|
||||
this.version = version;
|
||||
this.priority = priority;
|
||||
this.dependencies = dependencies;
|
||||
this.providers = providers;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package pro.gravit.launcher.modules;
|
||||
|
||||
public interface LauncherModulesContext {
|
||||
LauncherModulesManager getModulesManager();
|
||||
ModulesConfigManager getModulesConfigManager();
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package pro.gravit.launcher.modules;
|
||||
|
||||
import pro.gravit.utils.Version;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public interface LauncherModulesManager {
|
||||
|
||||
LauncherModule loadModule(LauncherModule module);
|
||||
LauncherModule loadModule(Path file) throws IOException;
|
||||
LauncherModule getModule(String name);
|
||||
LauncherModule getCoreModule();
|
||||
default boolean containsModule(String name)
|
||||
{
|
||||
return getModule(name) != null;
|
||||
}
|
||||
|
||||
default <T extends LauncherModule> boolean containsModule(Class<? extends T> clazz)
|
||||
{
|
||||
return getModule(clazz) != null;
|
||||
}
|
||||
ClassLoader getModuleClassLoader();
|
||||
<T extends LauncherModule> T getModule(Class<? extends T> clazz);
|
||||
<T> T getModuleByInterface(Class<T> clazz);
|
||||
<T> List<T> getModulesByInterface(Class<T> clazz);
|
||||
<T extends LauncherModule> T findModule(Class<? extends T> clazz, Predicate<Version> versionPredicate);
|
||||
|
||||
/**
|
||||
* Invoke event processing for all modules.
|
||||
* Event processing is carried out in the order of the modules in the list (sorted by priority)
|
||||
* @param event event handled
|
||||
* @param <T> event type
|
||||
*/
|
||||
<T extends LauncherModule.Event> void invokeEvent(T event);
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package pro.gravit.launcher.modules;
|
||||
|
||||
import pro.gravit.utils.Version;
|
||||
|
||||
@Deprecated
|
||||
public interface Module extends AutoCloseable {
|
||||
|
||||
String getName();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
package pro.gravit.launcher.modules;
|
||||
|
||||
@Deprecated
|
||||
public interface ModuleContext {
|
||||
enum Type {
|
||||
SERVER, CLIENT, LAUNCHSERVER
|
||||
|
|
|
@ -5,5 +5,7 @@
|
|||
public interface ModulesConfigManager {
|
||||
Path getModuleConfig(String moduleName);
|
||||
|
||||
Path getModuleConfig(String moduleName, String configName);
|
||||
|
||||
Path getModuleConfigDir(String moduleName);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package pro.gravit.launcher.modules;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
@Deprecated
|
||||
public interface ModulesManager extends AutoCloseable {
|
||||
void initModules();
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package pro.gravit.launcher.modules.events;
|
||||
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
|
||||
public class ClosePhase extends LauncherModule.Event {
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package pro.gravit.launcher.modules.events;
|
||||
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
|
||||
public class InitPhase extends LauncherModule.Event {
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package pro.gravit.launcher.modules.events;
|
||||
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
|
||||
public class PostInitPhase extends LauncherModule.Event {
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package pro.gravit.launcher.modules.events;
|
||||
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
|
||||
public class PreConfigPhase extends LauncherModule.Event {
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package pro.gravit.launcher.modules.events;
|
||||
|
||||
import com.google.gson.GsonBuilder;
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
|
||||
public class PreGsonPhase extends LauncherModule.Event {
|
||||
public GsonBuilder gsonBuilder;
|
||||
|
||||
public PreGsonPhase(GsonBuilder gsonBuilder) {
|
||||
this.gsonBuilder = gsonBuilder;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package pro.gravit.launcher.modules.impl;
|
||||
|
||||
import pro.gravit.launcher.modules.LauncherModulesContext;
|
||||
import pro.gravit.launcher.modules.LauncherModulesManager;
|
||||
import pro.gravit.launcher.modules.ModulesConfigManager;
|
||||
|
||||
public class SimpleModuleContext implements LauncherModulesContext {
|
||||
public final LauncherModulesManager modulesManager;
|
||||
public final ModulesConfigManager configManager;
|
||||
@Override
|
||||
public LauncherModulesManager getModulesManager() {
|
||||
return modulesManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModulesConfigManager getModulesConfigManager() {
|
||||
return configManager;
|
||||
}
|
||||
|
||||
public SimpleModuleContext(LauncherModulesManager modulesManager, ModulesConfigManager configManager) {
|
||||
this.modulesManager = modulesManager;
|
||||
this.configManager = configManager;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,222 @@
|
|||
package pro.gravit.launcher.modules.impl;
|
||||
|
||||
import pro.gravit.launcher.managers.SimpleModulesConfigManager;
|
||||
import pro.gravit.launcher.modules.*;
|
||||
import pro.gravit.utils.PublicURLClassLoader;
|
||||
import pro.gravit.utils.Version;
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
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;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
public class SimpleModuleManager implements LauncherModulesManager {
|
||||
protected final List<LauncherModule> modules = new ArrayList<>();
|
||||
protected final List<String> moduleNames = new ArrayList<>();
|
||||
protected final SimpleModuleContext context;
|
||||
protected final ModulesConfigManager modulesConfigManager;
|
||||
protected final Path modulesDir;
|
||||
protected LauncherInitContext initContext;
|
||||
|
||||
protected PublicURLClassLoader classLoader = new PublicURLClassLoader(new URL[]{});
|
||||
|
||||
protected final class ModulesVisitor extends SimpleFileVisitor<Path> {
|
||||
private ModulesVisitor() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
if (file.toFile().getName().endsWith(".jar"))
|
||||
loadModule(file);
|
||||
return super.visitFile(file, attrs);
|
||||
}
|
||||
}
|
||||
|
||||
public void autoload() throws IOException {
|
||||
autoload(modulesDir);
|
||||
}
|
||||
|
||||
public void autoload(Path dir) throws IOException {
|
||||
if (Files.notExists(dir)) Files.createDirectory(dir);
|
||||
else {
|
||||
IOHelper.walk(dir, new ModulesVisitor(), true);
|
||||
}
|
||||
}
|
||||
|
||||
public void initModules(LauncherInitContext initContext) {
|
||||
boolean isAnyModuleLoad = true;
|
||||
modules.sort((m1, m2) -> {
|
||||
int priority1 = m1.getModuleInfo().priority;
|
||||
int priority2 = m2.getModuleInfo().priority;
|
||||
return Integer.compare(priority1, priority2);
|
||||
});
|
||||
while(isAnyModuleLoad)
|
||||
{
|
||||
isAnyModuleLoad = false;
|
||||
for(LauncherModule module : modules)
|
||||
{
|
||||
if(!module.getInitStatus().equals(LauncherModule.InitStatus.INIT_WAIT)) continue;
|
||||
if(checkDepend(module))
|
||||
{
|
||||
isAnyModuleLoad = true;
|
||||
module.setInitStatus(LauncherModule.InitStatus.INIT);
|
||||
module.init(initContext);
|
||||
module.setInitStatus(LauncherModule.InitStatus.FINISH);
|
||||
}
|
||||
}
|
||||
}
|
||||
for(LauncherModule module : modules)
|
||||
{
|
||||
if(module.getInitStatus().equals(LauncherModule.InitStatus.INIT_WAIT))
|
||||
{
|
||||
LauncherModuleInfo info = module.getModuleInfo();
|
||||
LogHelper.warning("Module %s required %s. Cyclic dependencies?", info.name, Arrays.toString(info.dependencies));
|
||||
module.setInitStatus(LauncherModule.InitStatus.INIT);
|
||||
module.init(initContext);
|
||||
module.setInitStatus(LauncherModule.InitStatus.FINISH);
|
||||
}
|
||||
else if(module.getInitStatus().equals(LauncherModule.InitStatus.PRE_INIT_WAIT))
|
||||
{
|
||||
LauncherModuleInfo info = module.getModuleInfo();
|
||||
LogHelper.error("Module %s skip pre-init phase. This module NOT finish loading", info.name, Arrays.toString(info.dependencies));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkDepend(LauncherModule module)
|
||||
{
|
||||
LauncherModuleInfo info = module.getModuleInfo();
|
||||
for(String dep : info.dependencies)
|
||||
{
|
||||
LauncherModule depModule = getModule(dep);
|
||||
if(depModule == null) throw new RuntimeException(String.format("Module %s required %s. %s not found", info.name, dep, dep));
|
||||
if(!depModule.getInitStatus().equals(LauncherModule.InitStatus.FINISH)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public SimpleModuleManager(Path modulesDir, Path configDir) {
|
||||
modulesConfigManager = new SimpleModulesConfigManager(configDir);
|
||||
context = new SimpleModuleContext(this, modulesConfigManager);
|
||||
this.modulesDir = modulesDir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LauncherModule loadModule(LauncherModule module) {
|
||||
if(modules.contains(module)) return module;
|
||||
modules.add(module);
|
||||
LauncherModuleInfo info = module.getModuleInfo();
|
||||
moduleNames.add(info.name);
|
||||
module.setContext(context);
|
||||
module.preInit();
|
||||
if(initContext != null)
|
||||
{
|
||||
module.setInitStatus(LauncherModule.InitStatus.INIT);
|
||||
module.init(initContext);
|
||||
module.setInitStatus(LauncherModule.InitStatus.FINISH);
|
||||
}
|
||||
return module;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LauncherModule loadModule(Path file) throws IOException {
|
||||
try (JarFile f = new JarFile(file.toFile())) {
|
||||
String moduleClass = f.getManifest().getMainAttributes().getValue("Module-Main-Class");
|
||||
if(moduleClass == null)
|
||||
{
|
||||
LogHelper.error("In module %s Module-Main-Class not found", file.toString());
|
||||
return null;
|
||||
}
|
||||
classLoader.addURL(file.toUri().toURL());
|
||||
LauncherModule module = (LauncherModule) Class.forName(moduleClass, true, classLoader).newInstance();
|
||||
loadModule(module);
|
||||
return module;
|
||||
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
|
||||
LogHelper.error(e);
|
||||
LogHelper.error("In module %s Module-Main-Class incorrect", file.toString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LauncherModule getModule(String name) {
|
||||
for(LauncherModule module : modules)
|
||||
{
|
||||
LauncherModuleInfo info = module.getModuleInfo();
|
||||
if(info.name.equals(name) || ( info.providers.length > 0 && Arrays.asList(info.providers).contains(name))) return module;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LauncherModule getCoreModule() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader getModuleClassLoader() {
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends LauncherModule> T getModule(Class<? extends T> clazz) {
|
||||
for(LauncherModule module : modules)
|
||||
{
|
||||
if(clazz.isAssignableFrom(module.getClass())) return (T) module;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getModuleByInterface(Class<T> clazz) {
|
||||
for(LauncherModule module : modules)
|
||||
{
|
||||
if(clazz.isAssignableFrom(module.getClass())) return (T) module;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> List<T> getModulesByInterface(Class<T> clazz) {
|
||||
List<T> list = new ArrayList<>();
|
||||
for(LauncherModule module : modules)
|
||||
{
|
||||
if(clazz.isAssignableFrom(module.getClass())) list.add((T) module);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends LauncherModule> T findModule(Class<? extends T> clazz, Predicate<Version> versionPredicate) {
|
||||
for(LauncherModule module : modules)
|
||||
{
|
||||
LauncherModuleInfo info = module.getModuleInfo();
|
||||
if(!versionPredicate.test(info.version)) continue;
|
||||
if(clazz.isAssignableFrom(module.getClass())) return (T) module;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends LauncherModule.Event> void invokeEvent(T event) {
|
||||
for(LauncherModule module : modules)
|
||||
{
|
||||
module.callEvent(event);
|
||||
if(event.isCancel()) return;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -46,6 +46,10 @@ public interface UpdateController {
|
|||
public static void setController(UpdateController controller) {
|
||||
UpdateRequest.controller = controller;
|
||||
}
|
||||
public static UpdateController getController()
|
||||
{
|
||||
return controller;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
package pro.gravit.launcher;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import pro.gravit.launcher.impl.*;
|
||||
import pro.gravit.launcher.impl.event.CancelEvent;
|
||||
import pro.gravit.launcher.impl.event.NormalEvent;
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
import pro.gravit.launcher.modules.impl.SimpleModuleManager;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class ModulesTest {
|
||||
@TempDir
|
||||
public static Path configDir;
|
||||
@TempDir
|
||||
public static Path modulesDir;
|
||||
public static SimpleModuleManager moduleManager;
|
||||
public static int dependInt = 0;
|
||||
public static void add(int a)
|
||||
{
|
||||
if(dependInt != a) throw new IllegalStateException(String.valueOf(a));
|
||||
dependInt++;
|
||||
}
|
||||
@BeforeAll
|
||||
public static void prepare()
|
||||
{
|
||||
moduleManager = new SimpleModuleManager(modulesDir, configDir);
|
||||
}
|
||||
@Test
|
||||
public void baseModule()
|
||||
{
|
||||
moduleManager.loadModule(new TestModule());
|
||||
moduleManager.initModules(null);
|
||||
NormalEvent e = new NormalEvent();
|
||||
moduleManager.invokeEvent(e);
|
||||
Assertions.assertTrue(e.passed);
|
||||
CancelEvent e1 = new CancelEvent();
|
||||
moduleManager.invokeEvent(e1);
|
||||
Assertions.assertTrue(e1.isCancel());
|
||||
}
|
||||
@Test
|
||||
public void dependenciesTest()
|
||||
{
|
||||
moduleManager.loadModule(new Depend1Module());
|
||||
moduleManager.loadModule(new Depend2Module());
|
||||
moduleManager.loadModule(new Depend3Module());
|
||||
moduleManager.loadModule(new MainModule());
|
||||
moduleManager.initModules(null);
|
||||
Assertions.assertEquals(moduleManager.getModule("depend1").getInitStatus(), LauncherModule.InitStatus.FINISH);
|
||||
Assertions.assertEquals(moduleManager.getModule("depend2").getInitStatus(), LauncherModule.InitStatus.FINISH);
|
||||
Assertions.assertEquals(moduleManager.getModule("depend3").getInitStatus(), LauncherModule.InitStatus.FINISH);
|
||||
Assertions.assertEquals(moduleManager.getModule("internal").getInitStatus(), LauncherModule.InitStatus.FINISH);
|
||||
Assertions.assertEquals(moduleManager.getModule("virtual").getInitStatus(), LauncherModule.InitStatus.FINISH);
|
||||
Assertions.assertEquals(moduleManager.getModule("main").getInitStatus(), LauncherModule.InitStatus.FINISH);
|
||||
}
|
||||
@Test
|
||||
public void cyclicTest()
|
||||
{
|
||||
moduleManager.loadModule(new CyclicDependModule());
|
||||
moduleManager.loadModule(new Cyclic2DependModule());
|
||||
moduleManager.initModules(null);
|
||||
Assertions.assertEquals(moduleManager.getModule("cyclic1").getInitStatus(), LauncherModule.InitStatus.FINISH);
|
||||
Assertions.assertEquals(moduleManager.getModule("cyclic2").getInitStatus(), LauncherModule.InitStatus.FINISH);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package pro.gravit.launcher.impl;
|
||||
|
||||
import pro.gravit.launcher.modules.LauncherInitContext;
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
import pro.gravit.launcher.modules.LauncherModuleInfo;
|
||||
import pro.gravit.utils.Version;
|
||||
|
||||
public class Cyclic2DependModule extends LauncherModule {
|
||||
public Cyclic2DependModule() {
|
||||
super(new LauncherModuleInfo("cyclic2",
|
||||
new Version(1,0,0),
|
||||
2, new String[]{"cyclic1"}));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(LauncherInitContext initContext) {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package pro.gravit.launcher.impl;
|
||||
|
||||
import pro.gravit.launcher.modules.LauncherInitContext;
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
import pro.gravit.launcher.modules.LauncherModuleInfo;
|
||||
import pro.gravit.utils.Version;
|
||||
|
||||
public class CyclicDependModule extends LauncherModule {
|
||||
public CyclicDependModule() {
|
||||
super(new LauncherModuleInfo("cyclic1",
|
||||
new Version(1,0,0),
|
||||
2, new String[]{"cyclic2"}));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(LauncherInitContext initContext) {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package pro.gravit.launcher.impl;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import pro.gravit.launcher.modules.LauncherInitContext;
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
import pro.gravit.launcher.modules.LauncherModuleInfo;
|
||||
import pro.gravit.utils.Version;
|
||||
|
||||
public class Depend1Module extends LauncherModule {
|
||||
public Depend1Module() {
|
||||
super(new LauncherModuleInfo("depend1", new Version(1,0,0),
|
||||
0,
|
||||
new String[]{"depend3", "internal", "virtual"}));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(LauncherInitContext initContext) {
|
||||
InternalModule module = modulesManager.getModule(InternalModule.class);
|
||||
Assertions.assertEquals(module.getInitStatus(), InitStatus.FINISH);
|
||||
Depend3Module module1 = modulesManager.getModule(Depend3Module.class);
|
||||
Assertions.assertEquals(module1.getInitStatus(), InitStatus.FINISH);
|
||||
VirtualInterface virtualInterface = modulesManager.getModuleByInterface(VirtualInterface.class);
|
||||
Assertions.assertEquals(((LauncherModule) virtualInterface).getInitStatus(), InitStatus.FINISH);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package pro.gravit.launcher.impl;
|
||||
|
||||
import pro.gravit.launcher.modules.LauncherInitContext;
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
import pro.gravit.launcher.modules.LauncherModuleInfo;
|
||||
|
||||
public class Depend2Module extends LauncherModule {
|
||||
public Depend2Module() {
|
||||
super(new LauncherModuleInfo("depend2"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preInitAction() {
|
||||
modulesManager.loadModule(new InternalModule());
|
||||
modulesManager.loadModule(new ProvidedModule());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(LauncherInitContext initContext) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package pro.gravit.launcher.impl;
|
||||
|
||||
import pro.gravit.launcher.ModulesTest;
|
||||
import pro.gravit.launcher.modules.LauncherInitContext;
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
import pro.gravit.launcher.modules.LauncherModuleInfo;
|
||||
|
||||
public class Depend3Module extends LauncherModule {
|
||||
public Depend3Module() {
|
||||
super(new LauncherModuleInfo("depend3"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(LauncherInitContext initContext) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package pro.gravit.launcher.impl;
|
||||
|
||||
import pro.gravit.launcher.ModulesTest;
|
||||
import pro.gravit.launcher.modules.LauncherInitContext;
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
import pro.gravit.launcher.modules.LauncherModuleInfo;
|
||||
|
||||
public class InternalModule extends LauncherModule {
|
||||
public InternalModule() {
|
||||
super(new LauncherModuleInfo("internal"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(LauncherInitContext initContext) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package pro.gravit.launcher.impl;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import pro.gravit.launcher.ModulesTest;
|
||||
import pro.gravit.launcher.modules.LauncherInitContext;
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
import pro.gravit.launcher.modules.LauncherModuleInfo;
|
||||
import pro.gravit.utils.Version;
|
||||
|
||||
public class MainModule extends LauncherModule {
|
||||
|
||||
public MainModule() {
|
||||
super(new LauncherModuleInfo("main",
|
||||
new Version(1,0,0),
|
||||
0, new String[]{"depend1", "depend2"}));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(LauncherInitContext initContext) {
|
||||
Depend1Module module = modulesManager.getModule(Depend1Module.class);
|
||||
Assertions.assertEquals(module.getInitStatus(), InitStatus.FINISH);
|
||||
Depend2Module module2 = modulesManager.getModule(Depend2Module.class);
|
||||
Assertions.assertEquals(module2.getInitStatus(), InitStatus.FINISH);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package pro.gravit.launcher.impl;
|
||||
|
||||
import pro.gravit.launcher.modules.LauncherInitContext;
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
import pro.gravit.launcher.modules.LauncherModuleInfo;
|
||||
import pro.gravit.utils.Version;
|
||||
|
||||
public class ProvidedModule extends LauncherModule implements VirtualInterface {
|
||||
public ProvidedModule() {
|
||||
super(new LauncherModuleInfo("provided", new Version(1,0,0),
|
||||
0, new String[]{}, new String[]{"virtual"}));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(LauncherInitContext initContext) {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package pro.gravit.launcher.impl;
|
||||
|
||||
import pro.gravit.launcher.impl.event.CancelEvent;
|
||||
import pro.gravit.launcher.impl.event.NormalEvent;
|
||||
import pro.gravit.launcher.modules.LauncherInitContext;
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
import pro.gravit.launcher.modules.LauncherModuleInfo;
|
||||
|
||||
public class TestModule extends LauncherModule {
|
||||
|
||||
public TestModule() {
|
||||
super(new LauncherModuleInfo("testModule"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(LauncherInitContext initContext) {
|
||||
registerEvent(this::testevent, NormalEvent.class);
|
||||
registerEvent(this::testevent2, CancelEvent.class);
|
||||
}
|
||||
|
||||
public void testevent(NormalEvent event)
|
||||
{
|
||||
event.passed = true;
|
||||
}
|
||||
|
||||
public void testevent2(CancelEvent cancelEvent)
|
||||
{
|
||||
cancelEvent.cancel();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
package pro.gravit.launcher.impl;
|
||||
|
||||
public interface VirtualInterface {
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package pro.gravit.launcher.impl.event;
|
||||
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
|
||||
public class CancelEvent extends LauncherModule.Event {
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package pro.gravit.launcher.impl.event;
|
||||
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
|
||||
public class NormalEvent extends LauncherModule.Event {
|
||||
public boolean passed;
|
||||
}
|
|
@ -7,17 +7,39 @@
|
|||
compileOnly 'org.jline:jline-reader:3.11.0'
|
||||
compileOnly 'org.jline:jline-terminal:3.11.0'
|
||||
compile 'com.google.code.gson:gson:2.8.5'
|
||||
testCompile 'org.junit.jupiter:junit-jupiter:5.4.1'
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
testLogging {
|
||||
events "passed", "skipped", "failed"
|
||||
}
|
||||
}
|
||||
|
||||
jar {
|
||||
classifier = 'clean'
|
||||
}
|
||||
|
||||
task sourcesJar(type: Jar) {
|
||||
from sourceSets.main.allJava
|
||||
archiveClassifier = 'sources'
|
||||
}
|
||||
|
||||
task javadocJar(type: Jar) {
|
||||
from javadoc
|
||||
archiveClassifier = 'javadoc'
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
launchercore(MavenPublication) {
|
||||
artifactId = 'launcher-core'
|
||||
artifact jar
|
||||
artifact(jar) {
|
||||
classifier ""
|
||||
}
|
||||
artifact sourcesJar
|
||||
artifact javadocJar
|
||||
pom {
|
||||
name = 'GravitLauncher Core Utils'
|
||||
description = 'GravitLauncher Core Utils'
|
||||
|
@ -28,6 +50,18 @@
|
|||
url = 'https://www.gnu.org/licenses/gpl-3.0.html'
|
||||
}
|
||||
}
|
||||
developers {
|
||||
developer {
|
||||
id = 'gravit'
|
||||
name = 'Gravit'
|
||||
email = 'gravit.min@ya.ru'
|
||||
}
|
||||
developer {
|
||||
id = 'zaxar163'
|
||||
name = 'Zaxar163'
|
||||
email = 'zahar.vcherachny@yandex.ru'
|
||||
}
|
||||
}
|
||||
scm {
|
||||
connection = 'scm:git:https://github.com/GravitLauncher/Launcher.git'
|
||||
developerConnection = 'scm:git:ssh://git@github.com:GravitLauncher/Launcher.git'
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue