mirror of
https://github.com/GravitLauncher/Launcher
synced 2025-01-21 06:44:26 +03:00
Merge branch 'release/5.6.9'
This commit is contained in:
commit
92ada65079
14 changed files with 190 additions and 17 deletions
|
@ -13,6 +13,13 @@
|
||||||
maven {
|
maven {
|
||||||
url "https://jitpack.io/"
|
url "https://jitpack.io/"
|
||||||
}
|
}
|
||||||
|
maven {
|
||||||
|
url 'https://maven.gravit-support.ru/repository/jitpack'
|
||||||
|
credentials {
|
||||||
|
username = 'gravitlauncher'
|
||||||
|
password = 'gravitlauncher'
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceCompatibility = '21'
|
sourceCompatibility = '21'
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
import pro.gravit.launchserver.modules.events.*;
|
import pro.gravit.launchserver.modules.events.*;
|
||||||
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
|
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
|
||||||
import pro.gravit.launchserver.socket.Client;
|
import pro.gravit.launchserver.socket.Client;
|
||||||
|
import pro.gravit.launchserver.socket.SocketCommandServer;
|
||||||
import pro.gravit.launchserver.socket.handlers.NettyServerSocketHandler;
|
import pro.gravit.launchserver.socket.handlers.NettyServerSocketHandler;
|
||||||
import pro.gravit.launchserver.socket.response.auth.ProfilesResponse;
|
import pro.gravit.launchserver.socket.response.auth.ProfilesResponse;
|
||||||
import pro.gravit.launchserver.socket.response.auth.RestoreResponse;
|
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 modulesDir;
|
||||||
public final Path launcherModulesDir;
|
public final Path launcherModulesDir;
|
||||||
public final Path librariesDir;
|
public final Path librariesDir;
|
||||||
|
public final Path controlFile;
|
||||||
/**
|
/**
|
||||||
* This object contains runtime configuration
|
* This object contains runtime configuration
|
||||||
*/
|
*/
|
||||||
|
@ -113,6 +115,7 @@ public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurab
|
||||||
// Server
|
// Server
|
||||||
public final CommandHandler commandHandler;
|
public final CommandHandler commandHandler;
|
||||||
public final NettyServerSocketHandler nettyServerSocketHandler;
|
public final NettyServerSocketHandler nettyServerSocketHandler;
|
||||||
|
public final SocketCommandServer socketCommandServer;
|
||||||
public final ScheduledExecutorService service;
|
public final ScheduledExecutorService service;
|
||||||
public final AtomicBoolean started = new AtomicBoolean(false);
|
public final AtomicBoolean started = new AtomicBoolean(false);
|
||||||
public final LauncherModuleLoader launcherModuleLoader;
|
public final LauncherModuleLoader launcherModuleLoader;
|
||||||
|
@ -139,6 +142,7 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
|
||||||
modulesDir = directories.modules;
|
modulesDir = directories.modules;
|
||||||
launcherModulesDir = directories.launcherModules;
|
launcherModulesDir = directories.launcherModules;
|
||||||
librariesDir = directories.librariesDir;
|
librariesDir = directories.librariesDir;
|
||||||
|
controlFile = directories.controlFile;
|
||||||
this.shardId = shardId;
|
this.shardId = shardId;
|
||||||
if(!Files.isDirectory(launcherPack)) {
|
if(!Files.isDirectory(launcherPack)) {
|
||||||
Files.createDirectories(launcherPack);
|
Files.createDirectories(launcherPack);
|
||||||
|
@ -190,6 +194,7 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
|
||||||
}
|
}
|
||||||
launcherModuleLoader.init();
|
launcherModuleLoader.init();
|
||||||
nettyServerSocketHandler = new NettyServerSocketHandler(this);
|
nettyServerSocketHandler = new NettyServerSocketHandler(this);
|
||||||
|
socketCommandServer = new SocketCommandServer(commandHandler, controlFile);
|
||||||
if(config.sign.checkCertificateExpired) {
|
if(config.sign.checkCertificateExpired) {
|
||||||
checkCertificateExpired();
|
checkCertificateExpired();
|
||||||
service.scheduleAtFixedRate(this::checkCertificateExpired, 24, 24, TimeUnit.HOURS);
|
service.scheduleAtFixedRate(this::checkCertificateExpired, 24, 24, TimeUnit.HOURS);
|
||||||
|
@ -353,6 +358,7 @@ public void run() {
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
CommonHelper.newThread("Command Thread", true, commandHandler).start();
|
CommonHelper.newThread("Command Thread", true, commandHandler).start();
|
||||||
|
CommonHelper.newThread("Socket Command Thread", true, socketCommandServer).start();
|
||||||
// Sync updates dir
|
// Sync updates dir
|
||||||
CommonHelper.newThread("Profiles and updates sync", true, () -> {
|
CommonHelper.newThread("Profiles and updates sync", true, () -> {
|
||||||
try {
|
try {
|
||||||
|
@ -461,7 +467,7 @@ public interface LaunchServerConfigManager {
|
||||||
public static class LaunchServerDirectories {
|
public static class LaunchServerDirectories {
|
||||||
public static final String UPDATES_NAME = "updates",
|
public static final String UPDATES_NAME = "updates",
|
||||||
TRUSTSTORE_NAME = "truststore", LAUNCHERLIBRARIES_NAME = "launcher-libraries",
|
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 updatesDir;
|
||||||
public Path librariesDir;
|
public Path librariesDir;
|
||||||
public Path launcherLibrariesDir;
|
public Path launcherLibrariesDir;
|
||||||
|
@ -473,6 +479,7 @@ public static class LaunchServerDirectories {
|
||||||
public Path tmpDir;
|
public Path tmpDir;
|
||||||
public Path modules;
|
public Path modules;
|
||||||
public Path launcherModules;
|
public Path launcherModules;
|
||||||
|
public Path controlFile;
|
||||||
|
|
||||||
public void collect() {
|
public void collect() {
|
||||||
if (updatesDir == null) updatesDir = getPath(UPDATES_NAME);
|
if (updatesDir == null) updatesDir = getPath(UPDATES_NAME);
|
||||||
|
@ -486,6 +493,7 @@ public void collect() {
|
||||||
if (modules == null) modules = getPath(MODULES);
|
if (modules == null) modules = getPath(MODULES);
|
||||||
if (launcherModules == null) launcherModules = getPath(LAUNCHER_MODULES);
|
if (launcherModules == null) launcherModules = getPath(LAUNCHER_MODULES);
|
||||||
if (librariesDir == null) librariesDir = getPath(LIBRARIES);
|
if (librariesDir == null) librariesDir = getPath(LIBRARIES);
|
||||||
|
if (controlFile == null) controlFile = getPath(CONTROL_FILE);
|
||||||
if (tmpDir == null)
|
if (tmpDir == null)
|
||||||
tmpDir = Paths.get(System.getProperty("java.io.tmpdir")).resolve("launchserver-%s".formatted(SecurityHelper.randomStringToken()));
|
tmpDir = Paths.get(System.getProperty("java.io.tmpdir")).resolve("launchserver-%s".formatted(SecurityHelper.randomStringToken()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -88,7 +88,7 @@ private static void realMain(String[] args) throws Throwable {
|
||||||
ClientParams params = readParams(new InetSocketAddress("127.0.0.1", Launcher.getConfig().clientPort));
|
ClientParams params = readParams(new InetSocketAddress("127.0.0.1", Launcher.getConfig().clientPort));
|
||||||
ClientLauncherMethods.verifyNoAgent();
|
ClientLauncherMethods.verifyNoAgent();
|
||||||
if(params.timestamp > System.currentTimeMillis() || params.timestamp + 30*1000 < System.currentTimeMillis() ) {
|
if(params.timestamp > System.currentTimeMillis() || params.timestamp + 30*1000 < System.currentTimeMillis() ) {
|
||||||
LogHelper.error("Timestamp failed. Exit");
|
LogHelper.error("Timestamp failed: current %d | params %d | diff %d", System.currentTimeMillis(), params.timestamp, System.currentTimeMillis() - params.timestamp);
|
||||||
ClientLauncherMethods.exitLauncher(-662);
|
ClientLauncherMethods.exitLauncher(-662);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ public final class Version implements Comparable<Version> {
|
||||||
|
|
||||||
public static final int MAJOR = 5;
|
public static final int MAJOR = 5;
|
||||||
public static final int MINOR = 6;
|
public static final int MINOR = 6;
|
||||||
public static final int PATCH = 8;
|
public static final int PATCH = 9;
|
||||||
public static final int BUILD = 1;
|
public static final int BUILD = 1;
|
||||||
public static final Version.Type RELEASE = Type.STABLE;
|
public static final Version.Type RELEASE = Type.STABLE;
|
||||||
public final int major;
|
public final int major;
|
||||||
|
|
|
@ -10,8 +10,18 @@
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public abstract class CommandHandler implements Runnable {
|
public abstract class CommandHandler implements Runnable {
|
||||||
private final List<Category> categories = new ArrayList<>();
|
protected final List<Category> categories;
|
||||||
private final CommandCategory baseCategory = new BaseCommandCategory();
|
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) {
|
public void eval(String line, boolean bell) {
|
||||||
LogHelper.info("Command '%s'", line);
|
LogHelper.info("Command '%s'", line);
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class StdCommandHandler extends CommandHandler {
|
public class StdCommandHandler extends CommandHandler {
|
||||||
private final BufferedReader reader;
|
private final BufferedReader reader;
|
||||||
|
@ -14,6 +16,31 @@ public StdCommandHandler(boolean readCommands) {
|
||||||
reader = readCommands ? IOHelper.newReader(System.in) : null;
|
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
|
@Override
|
||||||
public void bell() {
|
public void bell() {
|
||||||
}
|
}
|
||||||
|
@ -37,4 +64,16 @@ public void clear() throws IOException {
|
||||||
public String readLine() throws IOException {
|
public String readLine() throws IOException {
|
||||||
return reader == null ? null : reader.readLine();
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,6 +123,9 @@ protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String findLibrary(String name) {
|
public String findLibrary(String name) {
|
||||||
|
if(nativePath == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return nativePath.concat(IOHelper.PLATFORM_SEPARATOR).concat(JVMHelper.NATIVE_PREFIX).concat(name).concat(JVMHelper.NATIVE_EXTENSION);
|
return nativePath.concat(IOHelper.PLATFORM_SEPARATOR).concat(JVMHelper.NATIVE_PREFIX).concat(name).concat(JVMHelper.NATIVE_EXTENSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -262,6 +262,9 @@ protected Class<?> findClass(String moduleName, String name) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String findLibrary(String name) {
|
public String findLibrary(String name) {
|
||||||
|
if(nativePath == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return nativePath.concat(IOHelper.PLATFORM_SEPARATOR).concat(JVMHelper.NATIVE_PREFIX).concat(name).concat(JVMHelper.NATIVE_EXTENSION);
|
return nativePath.concat(IOHelper.PLATFORM_SEPARATOR).concat(JVMHelper.NATIVE_PREFIX).concat(name).concat(JVMHelper.NATIVE_EXTENSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
id 'org.openjfx.javafxplugin' version '0.1.0' apply false
|
id 'org.openjfx.javafxplugin' version '0.1.0' apply false
|
||||||
}
|
}
|
||||||
group = 'pro.gravit.launcher'
|
group = 'pro.gravit.launcher'
|
||||||
version = '5.6.8'
|
version = '5.6.9'
|
||||||
|
|
||||||
apply from: 'props.gradle'
|
apply from: 'props.gradle'
|
||||||
|
|
||||||
|
@ -30,6 +30,13 @@
|
||||||
maven {
|
maven {
|
||||||
url "https://jitpack.io/"
|
url "https://jitpack.io/"
|
||||||
}
|
}
|
||||||
|
maven {
|
||||||
|
url 'https://maven.gravit-support.ru/repository/jitpack'
|
||||||
|
credentials {
|
||||||
|
username = 'gravitlauncher'
|
||||||
|
password = 'gravitlauncher'
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
|
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +1,6 @@
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|
2
modules
2
modules
|
@ -1 +1 @@
|
||||||
Subproject commit 65f882bd90623aa1581ad24cfa4f52563ea95bc0
|
Subproject commit bf37c6860a80acfd516ee533494d64b226d89309
|
18
props.gradle
18
props.gradle
|
@ -1,18 +1,18 @@
|
||||||
project.ext {
|
project.ext {
|
||||||
verAsm = '9.7'
|
verAsm = '9.7.1'
|
||||||
verNetty = '4.1.111.Final'
|
verNetty = '4.1.114.Final'
|
||||||
verOshiCore = '6.6.4'
|
verOshiCore = '6.6.5'
|
||||||
verJunit = '5.10.2'
|
verJunit = '5.11.2'
|
||||||
verJansi = '2.4.1'
|
verJansi = '2.4.1'
|
||||||
verJline = '3.26.3'
|
verJline = '3.26.3'
|
||||||
verJwt = '0.12.5'
|
verJwt = '0.12.6'
|
||||||
verGson = '2.11.0'
|
verGson = '2.11.0'
|
||||||
verBcpkix = '1.78.1'
|
verBcpkix = '1.78.1'
|
||||||
verSlf4j = '2.0.13'
|
verSlf4j = '2.0.16'
|
||||||
verLog4j = '2.23.1'
|
verLog4j = '2.24.1'
|
||||||
verMySQLConn = '9.0.0'
|
verMySQLConn = '9.0.0'
|
||||||
verMariaDBConn = '3.4.0'
|
verMariaDBConn = '3.4.1'
|
||||||
verPostgreSQLConn = '42.7.4'
|
verPostgreSQLConn = '42.7.4'
|
||||||
verH2Conn = '2.3.232'
|
verH2Conn = '2.3.232'
|
||||||
verProguard = '7.5.0'
|
verProguard = '7.6.0'
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue