mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-11-15 03:31:15 +03:00
[FEATURE] LauncherAgent переделан. (#213)
* [REFACTOR] Рефакторинг. * [FEATURE] LauncherAgent переделан. * [FIX] Подача нужных агенту аргументов. * [FEATURE] Вы можете поставить листы ClientProfile модулем. * [FIX] Скрипты gradle, для работы LauncherTest. * [FEATURE] Система тестов - начало. * [FIX] Perms handler для тестовю
This commit is contained in:
parent
f747ef55d1
commit
0094c3b613
17 changed files with 296 additions and 98 deletions
|
@ -15,6 +15,7 @@
|
||||||
import ru.gravit.launchserver.auth.handler.MemoryAuthHandler;
|
import ru.gravit.launchserver.auth.handler.MemoryAuthHandler;
|
||||||
import ru.gravit.launchserver.auth.hwid.AcceptHWIDHandler;
|
import ru.gravit.launchserver.auth.hwid.AcceptHWIDHandler;
|
||||||
import ru.gravit.launchserver.auth.hwid.HWIDHandler;
|
import ru.gravit.launchserver.auth.hwid.HWIDHandler;
|
||||||
|
import ru.gravit.launchserver.auth.permissions.DefaultPermissionsHandler;
|
||||||
import ru.gravit.launchserver.auth.permissions.JsonFilePermissionsHandler;
|
import ru.gravit.launchserver.auth.permissions.JsonFilePermissionsHandler;
|
||||||
import ru.gravit.launchserver.auth.permissions.PermissionsHandler;
|
import ru.gravit.launchserver.auth.permissions.PermissionsHandler;
|
||||||
import ru.gravit.launchserver.auth.protect.NoProtectHandler;
|
import ru.gravit.launchserver.auth.protect.NoProtectHandler;
|
||||||
|
@ -45,6 +46,7 @@
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.ProcessBuilder.Redirect;
|
import java.lang.ProcessBuilder.Redirect;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
|
@ -308,7 +310,7 @@ public static void main(String... args) throws Throwable {
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
try {
|
try {
|
||||||
@SuppressWarnings("resource")
|
@SuppressWarnings("resource")
|
||||||
LaunchServer launchserver = new LaunchServer(IOHelper.WORKING_DIR, args);
|
LaunchServer launchserver = new LaunchServer(IOHelper.WORKING_DIR, false, args);
|
||||||
if (args.length == 0) launchserver.run();
|
if (args.length == 0) launchserver.run();
|
||||||
else { //Обработка команды
|
else { //Обработка команды
|
||||||
launchserver.commandHandler.eval(args, false);
|
launchserver.commandHandler.eval(args, false);
|
||||||
|
@ -325,6 +327,8 @@ public static void main(String... args) throws Throwable {
|
||||||
|
|
||||||
public final Path dir;
|
public final Path dir;
|
||||||
|
|
||||||
|
public final boolean testEnv;
|
||||||
|
|
||||||
public final Path launcherLibraries;
|
public final Path launcherLibraries;
|
||||||
|
|
||||||
public final Path launcherLibrariesCompile;
|
public final Path launcherLibrariesCompile;
|
||||||
|
@ -354,6 +358,8 @@ public static void main(String... args) throws Throwable {
|
||||||
|
|
||||||
public final JARLauncherBinary launcherBinary;
|
public final JARLauncherBinary launcherBinary;
|
||||||
|
|
||||||
|
public Class<? extends LauncherBinary> launcherEXEBinaryClass;
|
||||||
|
|
||||||
public final LauncherBinary launcherEXEBinary;
|
public final LauncherBinary launcherEXEBinary;
|
||||||
// HWID ban + anti-brutforce
|
// HWID ban + anti-brutforce
|
||||||
|
|
||||||
|
@ -397,8 +403,11 @@ public static void main(String... args) throws Throwable {
|
||||||
public static Gson gson;
|
public static Gson gson;
|
||||||
public static GsonBuilder gsonBuilder;
|
public static GsonBuilder gsonBuilder;
|
||||||
|
|
||||||
public LaunchServer(Path dir, String[] args) throws IOException, InvalidKeySpecException {
|
public static Class<? extends LauncherBinary> defaultLauncherEXEBinaryClass = null;
|
||||||
|
|
||||||
|
public LaunchServer(Path dir, boolean testEnv, String[] args) throws IOException, InvalidKeySpecException {
|
||||||
this.dir = dir;
|
this.dir = dir;
|
||||||
|
this.testEnv = testEnv;
|
||||||
taskPool = new Timer("Timered task worker thread", true);
|
taskPool = new Timer("Timered task worker thread", true);
|
||||||
launcherLibraries = dir.resolve("launcher-libraries");
|
launcherLibraries = dir.resolve("launcher-libraries");
|
||||||
launcherLibrariesCompile = dir.resolve("launcher-libraries-compile");
|
launcherLibrariesCompile = dir.resolve("launcher-libraries-compile");
|
||||||
|
@ -422,6 +431,9 @@ public LaunchServer(Path dir, String[] args) throws IOException, InvalidKeySpecE
|
||||||
|
|
||||||
// Set command handler
|
// Set command handler
|
||||||
CommandHandler localCommandHandler;
|
CommandHandler localCommandHandler;
|
||||||
|
if (testEnv)
|
||||||
|
localCommandHandler = new StdCommandHandler(false);
|
||||||
|
else
|
||||||
try {
|
try {
|
||||||
Class.forName("jline.Terminal");
|
Class.forName("jline.Terminal");
|
||||||
|
|
||||||
|
@ -459,6 +471,9 @@ public LaunchServer(Path dir, String[] args) throws IOException, InvalidKeySpecE
|
||||||
crc.update(publicKey.getModulus().toByteArray()); // IDEA говорит, что это Java 9 API. WTF?
|
crc.update(publicKey.getModulus().toByteArray()); // IDEA говорит, что это Java 9 API. WTF?
|
||||||
LogHelper.subInfo("Modulus CRC32: 0x%08x", crc.getValue());
|
LogHelper.subInfo("Modulus CRC32: 0x%08x", crc.getValue());
|
||||||
|
|
||||||
|
// Load class bindings.
|
||||||
|
launcherEXEBinaryClass = defaultLauncherEXEBinaryClass;
|
||||||
|
|
||||||
// pre init modules
|
// pre init modules
|
||||||
modulesManager = new ModulesManager(this);
|
modulesManager = new ModulesManager(this);
|
||||||
modulesManager.autoload(dir.resolve("modules"));
|
modulesManager.autoload(dir.resolve("modules"));
|
||||||
|
@ -466,7 +481,7 @@ public LaunchServer(Path dir, String[] args) throws IOException, InvalidKeySpecE
|
||||||
initGson();
|
initGson();
|
||||||
|
|
||||||
// Read LaunchServer config
|
// Read LaunchServer config
|
||||||
generateConfigIfNotExists();
|
generateConfigIfNotExists(testEnv);
|
||||||
LogHelper.info("Reading LaunchServer config file");
|
LogHelper.info("Reading LaunchServer config file");
|
||||||
try (BufferedReader reader = IOHelper.newReader(configFile)) {
|
try (BufferedReader reader = IOHelper.newReader(configFile)) {
|
||||||
config = Launcher.gson.fromJson(reader, Config.class);
|
config = Launcher.gson.fromJson(reader, Config.class);
|
||||||
|
@ -589,6 +604,14 @@ public static void initGson() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private LauncherBinary binary() {
|
private LauncherBinary binary() {
|
||||||
|
if (launcherEXEBinaryClass != null) {
|
||||||
|
try {
|
||||||
|
return (LauncherBinary)launcherEXEBinaryClass.getConstructor(LaunchServer.class).newInstance(this);
|
||||||
|
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
|
||||||
|
| InvocationTargetException | NoSuchMethodException | SecurityException e) {
|
||||||
|
LogHelper.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
Class.forName("net.sf.launch4j.Builder");
|
Class.forName("net.sf.launch4j.Builder");
|
||||||
if (config.launch4j.enabled) return new EXEL4JLauncherBinary(this);
|
if (config.launch4j.enabled) return new EXEL4JLauncherBinary(this);
|
||||||
|
@ -614,7 +637,7 @@ public void close() {
|
||||||
LogHelper.info("LaunchServer stopped");
|
LogHelper.info("LaunchServer stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateConfigIfNotExists() throws IOException {
|
private void generateConfigIfNotExists(boolean testEnv) throws IOException {
|
||||||
if (IOHelper.isFile(configFile))
|
if (IOHelper.isFile(configFile))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -640,7 +663,8 @@ private void generateConfigIfNotExists() throws IOException {
|
||||||
new RequestTextureProvider("http://example.com/skins/%username%.png", "http://example.com/cloaks/%username%.png")
|
new RequestTextureProvider("http://example.com/skins/%username%.png", "http://example.com/cloaks/%username%.png")
|
||||||
, "std")};
|
, "std")};
|
||||||
newConfig.protectHandler = new NoProtectHandler();
|
newConfig.protectHandler = new NoProtectHandler();
|
||||||
newConfig.permissionsHandler = new JsonFilePermissionsHandler();
|
if (testEnv) newConfig.permissionsHandler = new DefaultPermissionsHandler();
|
||||||
|
else newConfig.permissionsHandler = new JsonFilePermissionsHandler();
|
||||||
newConfig.legacyPort = 7240;
|
newConfig.legacyPort = 7240;
|
||||||
newConfig.legacyBindAddress = "0.0.0.0";
|
newConfig.legacyBindAddress = "0.0.0.0";
|
||||||
newConfig.binaryName = "Launcher";
|
newConfig.binaryName = "Launcher";
|
||||||
|
@ -674,10 +698,15 @@ private void generateConfigIfNotExists() throws IOException {
|
||||||
newConfig.components.put("authLimiter", authLimiterComponent);
|
newConfig.components.put("authLimiter", authLimiterComponent);
|
||||||
|
|
||||||
// Set server address
|
// Set server address
|
||||||
|
if (testEnv) {
|
||||||
|
newConfig.setLegacyAddress("localhost");
|
||||||
|
newConfig.setProjectName("test");
|
||||||
|
} else {
|
||||||
System.out.println("LaunchServer address: ");
|
System.out.println("LaunchServer address: ");
|
||||||
newConfig.setLegacyAddress(commandHandler.readLine());
|
newConfig.setLegacyAddress(commandHandler.readLine());
|
||||||
System.out.println("LaunchServer projectName: ");
|
System.out.println("LaunchServer projectName: ");
|
||||||
newConfig.setProjectName(commandHandler.readLine());
|
newConfig.setProjectName(commandHandler.readLine());
|
||||||
|
}
|
||||||
|
|
||||||
// Write LaunchServer config
|
// Write LaunchServer config
|
||||||
LogHelper.info("Writing LaunchServer config file");
|
LogHelper.info("Writing LaunchServer config file");
|
||||||
|
@ -686,10 +715,13 @@ private void generateConfigIfNotExists() throws IOException {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<ClientProfile> getProfiles() {
|
public List<ClientProfile> getProfiles() {
|
||||||
return profilesList;
|
return profilesList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setProfiles(List<ClientProfile> profilesList) {
|
||||||
|
this.profilesList = Collections.unmodifiableList(profilesList);
|
||||||
|
}
|
||||||
|
|
||||||
public SignedObjectHolder<HashedDir> getUpdateDir(String name) {
|
public SignedObjectHolder<HashedDir> getUpdateDir(String name) {
|
||||||
return updatesDirMap.get(name);
|
return updatesDirMap.get(name);
|
||||||
|
@ -717,8 +749,10 @@ public void run() {
|
||||||
throw new IllegalStateException("LaunchServer has been already started");
|
throw new IllegalStateException("LaunchServer has been already started");
|
||||||
|
|
||||||
// Add shutdown hook, then start LaunchServer
|
// Add shutdown hook, then start LaunchServer
|
||||||
|
if (!this.testEnv) {
|
||||||
JVMHelper.RUNTIME.addShutdownHook(CommonHelper.newThread(null, false, this::close));
|
JVMHelper.RUNTIME.addShutdownHook(CommonHelper.newThread(null, false, this::close));
|
||||||
CommonHelper.newThread("Command Thread", true, commandHandler).start();
|
CommonHelper.newThread("Command Thread", true, commandHandler).start();
|
||||||
|
}
|
||||||
rebindServerSocket();
|
rebindServerSocket();
|
||||||
if (config.netty != null)
|
if (config.netty != null)
|
||||||
rebindNettyServerSocket();
|
rebindNettyServerSocket();
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
dependencies {
|
dependencies {
|
||||||
pack project(':LauncherAPI') // Not error on obf.
|
pack project(':LauncherAPI') // Not error on obf.
|
||||||
bundle 'com.github.oshi:oshi-core:3.13.0'
|
bundle 'com.github.oshi:oshi-core:3.13.0'
|
||||||
|
bundle 'org.ow2.asm:asm-tree:7.1'
|
||||||
}
|
}
|
||||||
|
|
||||||
task genRuntimeJS(type: Zip) {
|
task genRuntimeJS(type: Zip) {
|
||||||
|
|
|
@ -40,7 +40,7 @@ public static void main(String[] arguments) throws IOException, InterruptedExcep
|
||||||
JVMHelper.addSystemPropertyToArgs(args, DirBridge.USE_OPTDIR_PROPERTY);
|
JVMHelper.addSystemPropertyToArgs(args, DirBridge.USE_OPTDIR_PROPERTY);
|
||||||
Collections.addAll(args, MAGIC_ARG);
|
Collections.addAll(args, MAGIC_ARG);
|
||||||
Collections.addAll(args, "-XX:+DisableAttachMechanism");
|
Collections.addAll(args, "-XX:+DisableAttachMechanism");
|
||||||
Collections.addAll(args, "-javaagent:".concat(pathLauncher));
|
Collections.addAll(args, "-javaagent:".concat(pathLauncher).concat("=pr"));
|
||||||
Collections.addAll(args, "-cp");
|
Collections.addAll(args, "-cp");
|
||||||
Collections.addAll(args, pathLauncher);
|
Collections.addAll(args, pathLauncher);
|
||||||
Collections.addAll(args, LauncherEngine.class.getName());
|
Collections.addAll(args, LauncherEngine.class.getName());
|
||||||
|
|
159
Launcher/src/main/java/ru/gravit/launcher/LauncherAgent.java
Normal file
159
Launcher/src/main/java/ru/gravit/launcher/LauncherAgent.java
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
package ru.gravit.launcher;
|
||||||
|
|
||||||
|
import ru.gravit.utils.helper.LogHelper;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.lang.instrument.Instrumentation;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
|
|
||||||
|
import org.objectweb.asm.ClassReader;
|
||||||
|
import org.objectweb.asm.ClassWriter;
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
import org.objectweb.asm.tree.InsnNode;
|
||||||
|
import org.objectweb.asm.tree.MethodNode;
|
||||||
|
|
||||||
|
import static org.objectweb.asm.Opcodes.*;
|
||||||
|
|
||||||
|
@LauncherAPI
|
||||||
|
public final class LauncherAgent {
|
||||||
|
private static boolean isAgentStarted = false;
|
||||||
|
public static Instrumentation inst;
|
||||||
|
|
||||||
|
public static void addJVMClassPath(String path) throws IOException {
|
||||||
|
LogHelper.debug("Launcher Agent addJVMClassPath");
|
||||||
|
inst.appendToSystemClassLoaderSearch(new JarFile(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAgentStarted() {
|
||||||
|
return isAgentStarted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void premain(String agentArgument, Instrumentation instrumentation) {
|
||||||
|
System.out.println("Launcher Agent");
|
||||||
|
inst = instrumentation;
|
||||||
|
isAgentStarted = true;
|
||||||
|
boolean pb = true;
|
||||||
|
boolean rt = true;
|
||||||
|
if (agentArgument != null) {
|
||||||
|
String trimmedArg = agentArgument.trim();
|
||||||
|
if (!trimmedArg.isEmpty()) {
|
||||||
|
if (trimmedArg.contains("p")) pb = false;
|
||||||
|
if (trimmedArg.contains("r")) rt = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
replaceClasses(pb, rt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isStarted() {
|
||||||
|
return isAgentStarted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author https://github.com/Konloch/JVM-Sandbox
|
||||||
|
* Replaces the Runtime class via instrumentation, transforms the class via ASM
|
||||||
|
*/
|
||||||
|
public static void replaceClasses(boolean pb, boolean rt) {
|
||||||
|
for(Class<?> c : inst.getAllLoadedClasses()) {
|
||||||
|
if(rt && c.getName().equals("java.lang.Runtime")) {
|
||||||
|
try {
|
||||||
|
inst.redefineClasses(new java.lang.instrument.ClassDefinition(java.lang.Runtime.class, transformClass(c.getName(), getClassFile(c))));
|
||||||
|
} catch(Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(pb && c.getName().equals("java.lang.ProcessBuilder")) {
|
||||||
|
try {
|
||||||
|
inst.redefineClasses(new java.lang.instrument.ClassDefinition(java.lang.ProcessBuilder.class, transformClass(c.getName(), getClassFile(c))));
|
||||||
|
} catch(Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(c.getName().equals("java.awt.Robot")) {
|
||||||
|
try {
|
||||||
|
inst.redefineClasses(new java.lang.instrument.ClassDefinition(java.lang.ProcessBuilder.class, transformClass(c.getName(), getClassFile(c))));
|
||||||
|
} catch(Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author https://github.com/Konloch/JVM-Sandbox
|
||||||
|
* Use ASM to modify the byte array
|
||||||
|
*/
|
||||||
|
public static byte[] transformClass(String className, byte[] classBytes) {
|
||||||
|
if (className.equals("java.lang.Runtime")) {
|
||||||
|
ClassReader cr=new ClassReader(classBytes);
|
||||||
|
ClassNode cn=new ClassNode();
|
||||||
|
cr.accept(cn,ClassReader.EXPAND_FRAMES);
|
||||||
|
|
||||||
|
for (Object o : cn.methods.toArray()) {
|
||||||
|
MethodNode m = (MethodNode) o;
|
||||||
|
if(m.name.equals("exec")) {
|
||||||
|
m.instructions.insert(new InsnNode(ARETURN));
|
||||||
|
m.instructions.insert(new InsnNode(ACONST_NULL));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ClassWriter cw=new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||||
|
cn.accept(cw);
|
||||||
|
return cw.toByteArray();
|
||||||
|
} else if (className.equals("java.lang.ProcessBuilder")) {
|
||||||
|
ClassReader cr=new ClassReader(classBytes);
|
||||||
|
ClassNode cn=new ClassNode();
|
||||||
|
cr.accept(cn,ClassReader.EXPAND_FRAMES);
|
||||||
|
|
||||||
|
for (Object o : cn.methods.toArray()) {
|
||||||
|
MethodNode m = (MethodNode) o;
|
||||||
|
if(m.name.equals("start")) {
|
||||||
|
m.instructions.insert(new InsnNode(ARETURN));
|
||||||
|
m.instructions.insert(new InsnNode(ACONST_NULL));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ClassWriter cw=new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||||
|
cn.accept(cw);
|
||||||
|
return cw.toByteArray();
|
||||||
|
} else if (className.equals("java.awt.Robot")) {
|
||||||
|
ClassReader cr=new ClassReader(classBytes);
|
||||||
|
ClassNode cn=new ClassNode();
|
||||||
|
cr.accept(cn,ClassReader.EXPAND_FRAMES);
|
||||||
|
|
||||||
|
for (Object o : cn.methods.toArray()) {
|
||||||
|
MethodNode m = (MethodNode) o;
|
||||||
|
if( m.name.equals("createScreenCapture") || m.name.equals("getPixelColor") ||
|
||||||
|
m.name.equals("keyPress") || m.name.equals("keyRelease") ||
|
||||||
|
m.name.equals("mouseMove") || m.name.equals("mousePress") ||
|
||||||
|
m.name.equals("mouseWheel"))
|
||||||
|
{
|
||||||
|
m.instructions.insert(new InsnNode(ARETURN));
|
||||||
|
m.instructions.insert(new InsnNode(ACONST_NULL));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ClassWriter cw=new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||||
|
cn.accept(cw);
|
||||||
|
return cw.toByteArray();
|
||||||
|
}
|
||||||
|
return classBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author https://github.com/Konloch/JVM-Sandbox
|
||||||
|
* Do not remove this method. Do not to cause classloading!
|
||||||
|
* Grab the byte array from the loaded Class object
|
||||||
|
* @param clazz
|
||||||
|
* @return array, respending this class in bytecode.
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static byte[] getClassFile(Class<?> clazz) throws IOException {
|
||||||
|
InputStream is = clazz.getResourceAsStream( "/" + clazz.getName().replace('.', '/') + ".class");
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
int r = 0;
|
||||||
|
byte[] buffer = new byte[8192];
|
||||||
|
while((r=is.read(buffer))>=0) {
|
||||||
|
baos.write(buffer, 0, r);
|
||||||
|
}
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,7 +14,6 @@
|
||||||
import ru.gravit.launcher.request.websockets.RequestInterface;
|
import ru.gravit.launcher.request.websockets.RequestInterface;
|
||||||
import ru.gravit.launcher.serialize.signed.SignedObjectHolder;
|
import ru.gravit.launcher.serialize.signed.SignedObjectHolder;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
|
@ -8,12 +8,10 @@
|
||||||
import ru.gravit.launcher.request.websockets.RequestInterface;
|
import ru.gravit.launcher.request.websockets.RequestInterface;
|
||||||
|
|
||||||
public class SetProfileRequest extends Request<SetProfileRequestEvent> implements RequestInterface {
|
public class SetProfileRequest extends Request<SetProfileRequestEvent> implements RequestInterface {
|
||||||
private transient ClientProfile profile;
|
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
public String client;
|
public String client;
|
||||||
|
|
||||||
public SetProfileRequest(ClientProfile profile) {
|
public SetProfileRequest(ClientProfile profile) {
|
||||||
this.profile = profile;
|
|
||||||
this.client = profile.getTitle();
|
this.client = profile.getTitle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
import ru.gravit.launcher.hasher.HashedEntry;
|
import ru.gravit.launcher.hasher.HashedEntry;
|
||||||
import ru.gravit.launcher.hasher.HashedFile;
|
import ru.gravit.launcher.hasher.HashedFile;
|
||||||
import ru.gravit.launcher.request.Request;
|
import ru.gravit.launcher.request.Request;
|
||||||
import ru.gravit.launcher.request.UpdateAction;
|
|
||||||
import ru.gravit.launcher.request.update.UpdateRequest.State.Callback;
|
import ru.gravit.launcher.request.update.UpdateRequest.State.Callback;
|
||||||
import ru.gravit.launcher.request.websockets.LegacyRequestBridge;
|
import ru.gravit.launcher.request.websockets.LegacyRequestBridge;
|
||||||
import ru.gravit.launcher.request.websockets.RequestInterface;
|
import ru.gravit.launcher.request.websockets.RequestInterface;
|
||||||
|
@ -26,7 +25,6 @@
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Queue;
|
|
||||||
|
|
||||||
public final class UpdateRequest extends Request<UpdateRequestEvent> implements RequestInterface {
|
public final class UpdateRequest extends Request<UpdateRequestEvent> implements RequestInterface {
|
||||||
|
|
||||||
|
@ -168,26 +166,6 @@ public double getTotalSizeMiB() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void fillActionsQueue(Queue<UpdateAction> queue, HashedDir mismatch) {
|
|
||||||
for (Entry<String, HashedEntry> mapEntry : mismatch.map().entrySet()) {
|
|
||||||
String name = mapEntry.getKey();
|
|
||||||
HashedEntry entry = mapEntry.getValue();
|
|
||||||
HashedEntry.Type entryType = entry.getType();
|
|
||||||
switch (entryType) {
|
|
||||||
case DIR: // cd - get - cd ..
|
|
||||||
queue.add(new UpdateAction(UpdateAction.Type.CD, name, entry));
|
|
||||||
fillActionsQueue(queue, (HashedDir) entry);
|
|
||||||
queue.add(UpdateAction.CD_BACK);
|
|
||||||
break;
|
|
||||||
case FILE: // get
|
|
||||||
queue.add(new UpdateAction(UpdateAction.Type.GET, name, entry));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new AssertionError("Unsupported hashed entry type: " + entryType.name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UpdateRequestEvent requestDo() throws Exception {
|
public UpdateRequestEvent requestDo() throws Exception {
|
||||||
LogHelper.debug("Start update request");
|
LogHelper.debug("Start update request");
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
package ru.gravit.launcher.test.utils;
|
||||||
|
|
||||||
|
import ru.gravit.launchserver.LaunchServer;
|
||||||
|
import ru.gravit.launchserver.binary.LauncherBinary;
|
||||||
|
import ru.gravit.utils.helper.IOHelper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
|
||||||
|
public class EXENonWarningLauncherBinary extends LauncherBinary {
|
||||||
|
|
||||||
|
public EXENonWarningLauncherBinary(LaunchServer server) {
|
||||||
|
super(server, server.dir.resolve(server.config.binaryName + ".exe"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void build() throws IOException {
|
||||||
|
if (IOHelper.isFile(syncBinaryFile)) {
|
||||||
|
Files.delete(syncBinaryFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
36
LauncherTest/src/test/java/ru/gravit/launcher/StartTest.java
Normal file
36
LauncherTest/src/test/java/ru/gravit/launcher/StartTest.java
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
package ru.gravit.launcher;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.security.spec.InvalidKeySpecException;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.io.TempDir;
|
||||||
|
|
||||||
|
import ru.gravit.launcher.test.utils.EXENonWarningLauncherBinary;
|
||||||
|
import ru.gravit.launchserver.LaunchServer;
|
||||||
|
import ru.gravit.utils.helper.LogHelper;
|
||||||
|
|
||||||
|
public class StartTest {
|
||||||
|
@TempDir
|
||||||
|
public Path dir;
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
public static void prepare() {
|
||||||
|
LogHelper.removeStdOutput();
|
||||||
|
LaunchServer.defaultLauncherEXEBinaryClass = EXENonWarningLauncherBinary.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkLaunchServerStarts() {
|
||||||
|
try {
|
||||||
|
LaunchServer srv = new LaunchServer(dir, true, new String[] { "checkInstall" });
|
||||||
|
srv.run();
|
||||||
|
srv.commandHandler.eval(new String[] { "checkInstall" }, false);
|
||||||
|
srv.close();
|
||||||
|
} catch (InvalidKeySpecException | IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
Radon
2
Radon
|
@ -1 +1 @@
|
||||||
Subproject commit e1f7548f97132fa29b01f68bd57ffab32de7b6e7
|
Subproject commit e6974532efc7228a8b826a8cd9e1f1f7b609659f
|
|
@ -37,7 +37,7 @@ public class ServerWrapper extends JsonConfigurable<ServerWrapper.Config> {
|
||||||
public ClassLoader loader;
|
public ClassLoader loader;
|
||||||
public ClientPermissions permissions;
|
public ClientPermissions permissions;
|
||||||
public static ServerWrapper wrapper;
|
public static ServerWrapper wrapper;
|
||||||
private static Gson gson;
|
public static Gson gson;
|
||||||
private static GsonBuilder gsonBuiler;
|
private static GsonBuilder gsonBuiler;
|
||||||
|
|
||||||
public static Path modulesDir = Paths.get(System.getProperty("serverwrapper.modulesDir", "modules"));
|
public static Path modulesDir = Paths.get(System.getProperty("serverwrapper.modulesDir", "modules"));
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package ru.gravit.launcher.server.setup;
|
package ru.gravit.launcher.server.setup;
|
||||||
|
|
||||||
import ru.gravit.launcher.LauncherConfig;
|
|
||||||
import ru.gravit.launcher.server.ServerWrapper;
|
import ru.gravit.launcher.server.ServerWrapper;
|
||||||
import ru.gravit.utils.PublicURLClassLoader;
|
import ru.gravit.utils.PublicURLClassLoader;
|
||||||
import ru.gravit.utils.helper.IOHelper;
|
import ru.gravit.utils.helper.IOHelper;
|
||||||
|
@ -24,21 +23,23 @@ public void run() throws IOException {
|
||||||
System.out.println("Print jar filename:");
|
System.out.println("Print jar filename:");
|
||||||
String jarName = commands.commandHandler.readLine();
|
String jarName = commands.commandHandler.readLine();
|
||||||
Path jarPath = Paths.get(jarName);
|
Path jarPath = Paths.get(jarName);
|
||||||
JarFile file = new JarFile(jarPath.toFile());
|
String mainClassName = null;
|
||||||
|
try (JarFile file = new JarFile(jarPath.toFile())) {
|
||||||
URL jarURL = jarPath.toUri().toURL();
|
URL jarURL = jarPath.toUri().toURL();
|
||||||
urlClassLoader = new PublicURLClassLoader(new URL[]{jarURL});
|
urlClassLoader = new PublicURLClassLoader(new URL[]{jarURL});
|
||||||
LogHelper.info("Check jar MainClass");
|
LogHelper.info("Check jar MainClass");
|
||||||
String mainClassName = file.getManifest().getMainAttributes().getValue("Main-Class");
|
mainClassName = file.getManifest().getMainAttributes().getValue("Main-Class");
|
||||||
if (mainClassName == null) {
|
if (mainClassName == null) {
|
||||||
LogHelper.error("Main-Class not found in MANIFEST");
|
LogHelper.error("Main-Class not found in MANIFEST");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Class mainClass = Class.forName(mainClassName, false, urlClassLoader);
|
Class.forName(mainClassName, false, urlClassLoader);
|
||||||
} catch (ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
LogHelper.error(e);
|
LogHelper.error(e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
LogHelper.info("Found MainClass %s", mainClassName);
|
LogHelper.info("Found MainClass %s", mainClassName);
|
||||||
System.out.println("Print launchserver websocket host:");
|
System.out.println("Print launchserver websocket host:");
|
||||||
String address = commands.commandHandler.readLine();
|
String address = commands.commandHandler.readLine();
|
||||||
|
@ -66,7 +67,6 @@ public void run() throws IOException {
|
||||||
wrapper.config.password = password;
|
wrapper.config.password = password;
|
||||||
wrapper.config.title = title;
|
wrapper.config.title = title;
|
||||||
wrapper.config.stopOnError = false;
|
wrapper.config.stopOnError = false;
|
||||||
LauncherConfig cfg = null;
|
|
||||||
|
|
||||||
if (wrapper.auth()) {
|
if (wrapper.auth()) {
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
package ru.gravit.launcher;
|
|
||||||
|
|
||||||
import ru.gravit.utils.helper.LogHelper;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.instrument.Instrumentation;
|
|
||||||
import java.util.jar.JarFile;
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public final class LauncherAgent {
|
|
||||||
private static boolean isAgentStarted = false;
|
|
||||||
public static Instrumentation inst;
|
|
||||||
|
|
||||||
public static void addJVMClassPath(String path) throws IOException {
|
|
||||||
LogHelper.debug("Launcher Agent addJVMClassPath");
|
|
||||||
inst.appendToSystemClassLoaderSearch(new JarFile(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAgentStarted() {
|
|
||||||
return isAgentStarted;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void premain(String agentArgument, Instrumentation instrumentation) {
|
|
||||||
System.out.println("Launcher Agent");
|
|
||||||
inst = instrumentation;
|
|
||||||
isAgentStarted = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isStarted() {
|
|
||||||
return isAgentStarted;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -9,6 +9,7 @@
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
public class ConfigManager {
|
public class ConfigManager {
|
||||||
private final HashMap<String, JsonConfigurable> CONFIGURABLE = new HashMap<>();
|
private final HashMap<String, JsonConfigurable> CONFIGURABLE = new HashMap<>();
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
include 'ServerWrapper'
|
include 'ServerWrapper'
|
||||||
include 'LaunchServer'
|
include 'LaunchServer'
|
||||||
include 'LaunchServerConsole'
|
include 'LaunchServerConsole'
|
||||||
|
include 'LauncherTest'
|
||||||
include 'modules'
|
include 'modules'
|
||||||
file('modules').eachDir { sub ->
|
file('modules').eachDir { sub ->
|
||||||
if (sub.name.endsWith('_module')) include 'modules:' + sub.name
|
if (sub.name.endsWith('_module')) include 'modules:' + sub.name
|
||||||
|
|
Loading…
Reference in a new issue