Merge branch 'release/5.0.7'

This commit is contained in:
Gravit 2019-08-31 22:36:54 +07:00
commit da6313e1cc
No known key found for this signature in database
GPG key ID: 061981E1E85D3216
134 changed files with 3124 additions and 1548 deletions

View file

@ -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"

View file

@ -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'

View file

@ -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);
}

View file

@ -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);
}
}

View file

@ -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);
}
}
}

View file

@ -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();
}

View file

@ -1,6 +0,0 @@
package pro.gravit.launchserver;
@FunctionalInterface
public interface Reloadable {
void reload() throws Exception;
}

View file

@ -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;

View file

@ -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);

View file

@ -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 {

View file

@ -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;

View file

@ -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;

View file

@ -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) {

View file

@ -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;

View file

@ -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));
}
}

View file

@ -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));
}
}

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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());
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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));

View file

@ -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);
}
}

View file

@ -20,6 +20,6 @@ public String getUsageDescription() {
@Override
public void invoke(String... args) {
server.modulesManager.printModules();
server.modulesManager.printModulesInfo();
}
}

View file

@ -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();
}
}

View file

@ -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]);
}
}

View file

@ -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();
}
}

View file

@ -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());

View file

@ -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;

View file

@ -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 {

View file

@ -0,0 +1,8 @@
package pro.gravit.launchserver.components;
public abstract class IPLimiter extends AbstractLimiter<String> {
@Override
protected String getFromString(String str) {
return str;
}
}

View file

@ -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);

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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());
}
}

View file

@ -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

View file

@ -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());
}
}

View file

@ -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);
}

View file

@ -25,7 +25,7 @@ public Type getType() {
@Override
public ModulesManager getModulesManager() {
return launchServer.modulesManager;
return null;
}
@Override

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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");
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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);
}

View file

@ -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));
}
/*

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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();
}
}

View file

@ -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'

View file

@ -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() {

View file

@ -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();

View file

@ -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();
}

View file

@ -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
}
}

View file

@ -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();
}
}

View file

@ -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 {

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -0,0 +1,6 @@
package pro.gravit.launcher.client.events;
import pro.gravit.launcher.modules.events.InitPhase;
public class ClientLauncherInitPhase extends InitPhase {
}

View file

@ -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;
}
}

View file

@ -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

View file

@ -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));
}
}

View file

@ -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<>();
}

View file

@ -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'

View file

@ -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

View file

@ -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());
}
}
}

View file

@ -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) {

View file

@ -0,0 +1,4 @@
package pro.gravit.launcher.modules;
public interface LauncherInitContext {
}

View file

@ -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 modules 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;
}
}
}
}

View file

@ -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;
}
}

View file

@ -0,0 +1,6 @@
package pro.gravit.launcher.modules;
public interface LauncherModulesContext {
LauncherModulesManager getModulesManager();
ModulesConfigManager getModulesConfigManager();
}

View file

@ -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);
}

View file

@ -1,7 +1,7 @@
package pro.gravit.launcher.modules;
import pro.gravit.utils.Version;
@Deprecated
public interface Module extends AutoCloseable {
String getName();

View file

@ -1,5 +1,5 @@
package pro.gravit.launcher.modules;
@Deprecated
public interface ModuleContext {
enum Type {
SERVER, CLIENT, LAUNCHSERVER

View file

@ -5,5 +5,7 @@
public interface ModulesConfigManager {
Path getModuleConfig(String moduleName);
Path getModuleConfig(String moduleName, String configName);
Path getModuleConfigDir(String moduleName);
}

View file

@ -1,7 +1,7 @@
package pro.gravit.launcher.modules;
import java.net.URL;
@Deprecated
public interface ModulesManager extends AutoCloseable {
void initModules();

View file

@ -0,0 +1,6 @@
package pro.gravit.launcher.modules.events;
import pro.gravit.launcher.modules.LauncherModule;
public class ClosePhase extends LauncherModule.Event {
}

View file

@ -0,0 +1,6 @@
package pro.gravit.launcher.modules.events;
import pro.gravit.launcher.modules.LauncherModule;
public class InitPhase extends LauncherModule.Event {
}

View file

@ -0,0 +1,6 @@
package pro.gravit.launcher.modules.events;
import pro.gravit.launcher.modules.LauncherModule;
public class PostInitPhase extends LauncherModule.Event {
}

View file

@ -0,0 +1,6 @@
package pro.gravit.launcher.modules.events;
import pro.gravit.launcher.modules.LauncherModule;
public class PreConfigPhase extends LauncherModule.Event {
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}
}

View file

@ -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() {

View file

@ -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);
}
}

View file

@ -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) {
}
}

View file

@ -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) {
}
}

View file

@ -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);
}
}

View file

@ -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) {
}
}

View file

@ -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) {
}
}

View file

@ -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) {
}
}

View file

@ -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);
}
}

View file

@ -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) {
}
}

View file

@ -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();
}
}

View file

@ -0,0 +1,4 @@
package pro.gravit.launcher.impl;
public interface VirtualInterface {
}

View file

@ -0,0 +1,6 @@
package pro.gravit.launcher.impl.event;
import pro.gravit.launcher.modules.LauncherModule;
public class CancelEvent extends LauncherModule.Event {
}

View file

@ -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;
}

View file

@ -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