mirror of
https://github.com/GravitLauncher/Launcher
synced 2025-02-08 23:39:38 +03:00
[FEATURE] Add ControlFile and proxy command handlers
This commit is contained in:
parent
4671dfe49d
commit
0111b2ca2b
4 changed files with 157 additions and 3 deletions
|
@ -21,6 +21,7 @@
|
|||
import pro.gravit.launchserver.modules.events.*;
|
||||
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
|
||||
import pro.gravit.launchserver.socket.Client;
|
||||
import pro.gravit.launchserver.socket.SocketCommandServer;
|
||||
import pro.gravit.launchserver.socket.handlers.NettyServerSocketHandler;
|
||||
import pro.gravit.launchserver.socket.response.auth.ProfilesResponse;
|
||||
import pro.gravit.launchserver.socket.response.auth.RestoreResponse;
|
||||
|
@ -85,6 +86,7 @@ public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurab
|
|||
public final Path modulesDir;
|
||||
public final Path launcherModulesDir;
|
||||
public final Path librariesDir;
|
||||
public final Path controlFile;
|
||||
/**
|
||||
* This object contains runtime configuration
|
||||
*/
|
||||
|
@ -113,6 +115,7 @@ public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurab
|
|||
// Server
|
||||
public final CommandHandler commandHandler;
|
||||
public final NettyServerSocketHandler nettyServerSocketHandler;
|
||||
public final SocketCommandServer socketCommandServer;
|
||||
public final ScheduledExecutorService service;
|
||||
public final AtomicBoolean started = new AtomicBoolean(false);
|
||||
public final LauncherModuleLoader launcherModuleLoader;
|
||||
|
@ -139,6 +142,7 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
|
|||
modulesDir = directories.modules;
|
||||
launcherModulesDir = directories.launcherModules;
|
||||
librariesDir = directories.librariesDir;
|
||||
controlFile = directories.controlFile;
|
||||
this.shardId = shardId;
|
||||
if(!Files.isDirectory(launcherPack)) {
|
||||
Files.createDirectories(launcherPack);
|
||||
|
@ -190,6 +194,7 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
|
|||
}
|
||||
launcherModuleLoader.init();
|
||||
nettyServerSocketHandler = new NettyServerSocketHandler(this);
|
||||
socketCommandServer = new SocketCommandServer(commandHandler, controlFile);
|
||||
if(config.sign.checkCertificateExpired) {
|
||||
checkCertificateExpired();
|
||||
service.scheduleAtFixedRate(this::checkCertificateExpired, 24, 24, TimeUnit.HOURS);
|
||||
|
@ -353,6 +358,7 @@ public void run() {
|
|||
}
|
||||
}));
|
||||
CommonHelper.newThread("Command Thread", true, commandHandler).start();
|
||||
CommonHelper.newThread("Socket Command Thread", true, socketCommandServer).start();
|
||||
// Sync updates dir
|
||||
CommonHelper.newThread("Profiles and updates sync", true, () -> {
|
||||
try {
|
||||
|
@ -461,7 +467,7 @@ public interface LaunchServerConfigManager {
|
|||
public static class LaunchServerDirectories {
|
||||
public static final String UPDATES_NAME = "updates",
|
||||
TRUSTSTORE_NAME = "truststore", LAUNCHERLIBRARIES_NAME = "launcher-libraries",
|
||||
LAUNCHERLIBRARIESCOMPILE_NAME = "launcher-libraries-compile", LAUNCHERPACK_NAME = "launcher-pack", KEY_NAME = ".keys", MODULES = "modules", LAUNCHER_MODULES = "launcher-modules", LIBRARIES = "libraries";
|
||||
LAUNCHERLIBRARIESCOMPILE_NAME = "launcher-libraries-compile", LAUNCHERPACK_NAME = "launcher-pack", KEY_NAME = ".keys", MODULES = "modules", LAUNCHER_MODULES = "launcher-modules", LIBRARIES = "libraries", CONTROL_FILE = "control-file";
|
||||
public Path updatesDir;
|
||||
public Path librariesDir;
|
||||
public Path launcherLibrariesDir;
|
||||
|
@ -473,6 +479,7 @@ public static class LaunchServerDirectories {
|
|||
public Path tmpDir;
|
||||
public Path modules;
|
||||
public Path launcherModules;
|
||||
public Path controlFile;
|
||||
|
||||
public void collect() {
|
||||
if (updatesDir == null) updatesDir = getPath(UPDATES_NAME);
|
||||
|
@ -486,6 +493,7 @@ public void collect() {
|
|||
if (modules == null) modules = getPath(MODULES);
|
||||
if (launcherModules == null) launcherModules = getPath(LAUNCHER_MODULES);
|
||||
if (librariesDir == null) librariesDir = getPath(LIBRARIES);
|
||||
if (controlFile == null) controlFile = getPath(CONTROL_FILE);
|
||||
if (tmpDir == null)
|
||||
tmpDir = Paths.get(System.getProperty("java.io.tmpdir")).resolve("launchserver-%s".formatted(SecurityHelper.randomStringToken()));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
package pro.gravit.launchserver.socket;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launchserver.config.log4j.LogAppender;
|
||||
import pro.gravit.utils.command.CommandHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.StandardProtocolFamily;
|
||||
import java.net.UnixDomainSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class SocketCommandServer implements Runnable {
|
||||
private final Logger logger = LogManager.getLogger(SocketCommandServer.class);
|
||||
private ServerSocketChannel channel;
|
||||
private Path path;
|
||||
private UnixDomainSocketAddress address;
|
||||
private ServerSocketChannel serverChannel;
|
||||
private CommandHandler commandHandler;
|
||||
private transient SocketChannel clientChannel;
|
||||
|
||||
public SocketCommandServer(CommandHandler commandHandler, Path path) {
|
||||
this.commandHandler = commandHandler;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
private void runCommand(SocketChannel channel, String command) {
|
||||
logger.info("Command '{}' from socket", command);
|
||||
clientChannel = channel;
|
||||
try {
|
||||
commandHandler.evalNative(command, false);
|
||||
} catch (Throwable e) {
|
||||
logger.error("Error when execute command", e);
|
||||
} finally {
|
||||
clientChannel = null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Files.deleteIfExists(path);
|
||||
this.address = UnixDomainSocketAddress.of(path);
|
||||
serverChannel = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
|
||||
serverChannel.configureBlocking(true);
|
||||
serverChannel.bind(address);
|
||||
LogAppender.getInstance().addListener((logEvent -> {
|
||||
if(clientChannel != null && clientChannel.isOpen()) {
|
||||
try {
|
||||
String s = logEvent.getMessage().getFormattedMessage()+"\n";
|
||||
byte[] bytes = s.getBytes(StandardCharsets.UTF_8);
|
||||
ByteBuffer buffer = ByteBuffer.wrap(bytes);
|
||||
clientChannel.write(buffer);
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
}));
|
||||
ByteBuffer buffer = ByteBuffer.allocate(1024);
|
||||
while (true) {
|
||||
SocketChannel channel = serverChannel.accept();
|
||||
channel.configureBlocking(true);
|
||||
String command = null;
|
||||
try {
|
||||
mark:
|
||||
while (true) {
|
||||
int bytesRead = channel.read(buffer);
|
||||
if (bytesRead < 0) {
|
||||
break;
|
||||
}
|
||||
logger.info("DEBUG: readed {}", new String(buffer.array(), 0, buffer.limit()));
|
||||
for (var i=0;i<buffer.limit();i++) {
|
||||
if(buffer.get(i) == '\n') {
|
||||
command = new String(buffer.array(), 0, i);
|
||||
break mark;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if(command != null) {
|
||||
runCommand(channel, command);
|
||||
}
|
||||
} finally {
|
||||
buffer.clear();
|
||||
channel.close();
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
logger.error("Unix command socket server error", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,8 +10,18 @@
|
|||
import java.util.Map;
|
||||
|
||||
public abstract class CommandHandler implements Runnable {
|
||||
private final List<Category> categories = new ArrayList<>();
|
||||
private final CommandCategory baseCategory = new BaseCommandCategory();
|
||||
protected final List<Category> categories;
|
||||
protected final CommandCategory baseCategory;
|
||||
|
||||
public CommandHandler() {
|
||||
this.categories = new ArrayList<>();
|
||||
this.baseCategory = new BaseCommandCategory();
|
||||
}
|
||||
|
||||
protected CommandHandler(List<Category> categories, CommandCategory baseCategory) {
|
||||
this.categories = categories;
|
||||
this.baseCategory = baseCategory;
|
||||
}
|
||||
|
||||
public void eval(String line, boolean bell) {
|
||||
LogHelper.info("Command '%s'", line);
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
public class StdCommandHandler extends CommandHandler {
|
||||
private final BufferedReader reader;
|
||||
|
@ -14,6 +16,31 @@ public StdCommandHandler(boolean readCommands) {
|
|||
reader = readCommands ? IOHelper.newReader(System.in) : null;
|
||||
}
|
||||
|
||||
public StdCommandHandler(InputStream stream) {
|
||||
super();
|
||||
this.reader = IOHelper.newReader(stream);
|
||||
}
|
||||
|
||||
public StdCommandHandler(BufferedReader reader) {
|
||||
super();
|
||||
this.reader = reader;
|
||||
}
|
||||
|
||||
protected StdCommandHandler(List<Category> categories, CommandCategory baseCategory, boolean readCommands) {
|
||||
super(categories, baseCategory);
|
||||
this.reader = readCommands ? IOHelper.newReader(System.in) : null;
|
||||
}
|
||||
|
||||
protected StdCommandHandler(List<Category> categories, CommandCategory baseCategory, InputStream stream) {
|
||||
super(categories, baseCategory);
|
||||
this.reader = IOHelper.newReader(stream);
|
||||
}
|
||||
|
||||
protected StdCommandHandler(List<Category> categories, CommandCategory baseCategory, BufferedReader reader) {
|
||||
super(categories, baseCategory);
|
||||
this.reader = reader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bell() {
|
||||
}
|
||||
|
@ -37,4 +64,16 @@ public void clear() throws IOException {
|
|||
public String readLine() throws IOException {
|
||||
return reader == null ? null : reader.readLine();
|
||||
}
|
||||
|
||||
public StdCommandHandler ofHandler(CommandHandler commandHandler, boolean readCommands) {
|
||||
return new StdCommandHandler(commandHandler.categories, commandHandler.baseCategory, readCommands);
|
||||
}
|
||||
|
||||
public StdCommandHandler ofHandler(CommandHandler commandHandler, InputStream stream) {
|
||||
return new StdCommandHandler(commandHandler.categories, commandHandler.baseCategory, stream);
|
||||
}
|
||||
|
||||
public StdCommandHandler ofHandler(CommandHandler commandHandler, BufferedReader reader) {
|
||||
return new StdCommandHandler(commandHandler.categories, commandHandler.baseCategory, reader);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue