mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-11-15 19:49:11 +03:00
Compare commits
No commits in common. "f297a5878d636f4db79d86b90f5b78849ad647f1" and "83cc4415749f16c27fa63e670694b617b61eeb24" have entirely different histories.
f297a5878d
...
83cc441574
34 changed files with 162 additions and 452 deletions
|
@ -61,6 +61,7 @@
|
||||||
dependsOn jar
|
dependsOn jar
|
||||||
archiveClassifier.set('clean')
|
archiveClassifier.set('clean')
|
||||||
manifest.attributes("Main-Class": mainClassName,
|
manifest.attributes("Main-Class": mainClassName,
|
||||||
|
"Premain-Class": mainAgentName,
|
||||||
"Automatic-Module-Name": "launchserver"
|
"Automatic-Module-Name": "launchserver"
|
||||||
)
|
)
|
||||||
from sourceSets.main.output
|
from sourceSets.main.output
|
||||||
|
@ -70,6 +71,7 @@
|
||||||
dependencies {
|
dependencies {
|
||||||
pack project(':LauncherAPI')
|
pack project(':LauncherAPI')
|
||||||
bundle group: 'me.tongfei', name: 'progressbar', version: '0.10.1'
|
bundle group: 'me.tongfei', name: 'progressbar', version: '0.10.1'
|
||||||
|
bundle group: 'com.github.Marcono1234', name: 'gson-record-type-adapter-factory', version: 'v0.3.0'
|
||||||
bundle group: 'org.fusesource.jansi', name: 'jansi', version: rootProject['verJansi']
|
bundle group: 'org.fusesource.jansi', name: 'jansi', version: rootProject['verJansi']
|
||||||
bundle group: 'org.jline', name: 'jline', version: rootProject['verJline']
|
bundle group: 'org.jline', name: 'jline', version: rootProject['verJline']
|
||||||
bundle group: 'org.jline', name: 'jline-reader', version: rootProject['verJline']
|
bundle group: 'org.jline', name: 'jline-reader', version: rootProject['verJline']
|
||||||
|
@ -80,7 +82,6 @@ pack project(':LauncherAPI')
|
||||||
bundle group: 'io.netty', name: 'netty-codec-http', version: rootProject['verNetty']
|
bundle group: 'io.netty', name: 'netty-codec-http', version: rootProject['verNetty']
|
||||||
bundle group: 'io.netty', name: 'netty-transport-classes-epoll', version: rootProject['verNetty']
|
bundle group: 'io.netty', name: 'netty-transport-classes-epoll', version: rootProject['verNetty']
|
||||||
bundle group: 'io.netty', name: 'netty-transport-native-epoll', version: rootProject['verNetty'], classifier: 'linux-x86_64'
|
bundle group: 'io.netty', name: 'netty-transport-native-epoll', version: rootProject['verNetty'], classifier: 'linux-x86_64'
|
||||||
bundle group: 'io.netty', name: 'netty-transport-native-epoll', version: rootProject['verNetty'], classifier: 'linux-aarch_64'
|
|
||||||
bundle group: 'org.slf4j', name: 'slf4j-api', version: rootProject['verSlf4j']
|
bundle group: 'org.slf4j', name: 'slf4j-api', version: rootProject['verSlf4j']
|
||||||
bundle group: 'com.mysql', name: 'mysql-connector-j', version: rootProject['verMySQLConn']
|
bundle group: 'com.mysql', name: 'mysql-connector-j', version: rootProject['verMySQLConn']
|
||||||
bundle group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: rootProject['verMariaDBConn']
|
bundle group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: rootProject['verMariaDBConn']
|
||||||
|
@ -92,16 +93,20 @@ pack project(':LauncherAPI')
|
||||||
bundle group: 'io.jsonwebtoken', name: 'jjwt-api', version: rootProject['verJwt']
|
bundle group: 'io.jsonwebtoken', name: 'jjwt-api', version: rootProject['verJwt']
|
||||||
bundle group: 'io.jsonwebtoken', name: 'jjwt-impl', version: rootProject['verJwt']
|
bundle group: 'io.jsonwebtoken', name: 'jjwt-impl', version: rootProject['verJwt']
|
||||||
bundle group: 'io.jsonwebtoken', name: 'jjwt-gson', version: rootProject['verJwt']
|
bundle group: 'io.jsonwebtoken', name: 'jjwt-gson', version: rootProject['verJwt']
|
||||||
bundle group: 'com.google.code.gson', name: 'gson', version: rootProject['verGson']
|
|
||||||
annotationProcessor(group: 'org.apache.logging.log4j', name: 'log4j-core', version: rootProject['verLog4j'])
|
annotationProcessor(group: 'org.apache.logging.log4j', name: 'log4j-core', version: rootProject['verLog4j'])
|
||||||
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter', version: rootProject['verJunit']
|
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter', version: rootProject['verJunit']
|
||||||
|
|
||||||
hikari 'io.micrometer:micrometer-core:1.13.1'
|
hikari 'io.micrometer:micrometer-core:1.8.4'
|
||||||
hikari('com.zaxxer:HikariCP:5.1.0') {
|
hikari('com.zaxxer:HikariCP:5.0.1') {
|
||||||
exclude group: 'javassist'
|
exclude group: 'javassist'
|
||||||
exclude group: 'io.micrometer'
|
exclude group: 'io.micrometer'
|
||||||
exclude group: 'org.slf4j'
|
exclude group: 'org.slf4j'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
compileOnlyA group: 'com.google.guava', name: 'guava', version: rootProject['verGuavaC']
|
||||||
|
// Do not update (laggy deps).
|
||||||
|
compileOnlyA 'log4j:log4j:1.2.17'
|
||||||
|
compileOnlyA 'org.apache.logging.log4j:log4j-core:2.14.1'
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register('hikari', Copy) {
|
tasks.register('hikari', Copy) {
|
||||||
|
|
|
@ -80,10 +80,8 @@ public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurab
|
||||||
/**
|
/**
|
||||||
* The path to the folder with profiles
|
* The path to the folder with profiles
|
||||||
*/
|
*/
|
||||||
|
public final Path profilesDir;
|
||||||
public final Path tmpDir;
|
public final Path tmpDir;
|
||||||
public final Path modulesDir;
|
|
||||||
public final Path launcherModulesDir;
|
|
||||||
public final Path librariesDir;
|
|
||||||
/**
|
/**
|
||||||
* This object contains runtime configuration
|
* This object contains runtime configuration
|
||||||
*/
|
*/
|
||||||
|
@ -118,6 +116,8 @@ public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurab
|
||||||
private final Logger logger = LogManager.getLogger();
|
private final Logger logger = LogManager.getLogger();
|
||||||
public final int shardId;
|
public final int shardId;
|
||||||
public LaunchServerConfig config;
|
public LaunchServerConfig config;
|
||||||
|
// Updates and profiles
|
||||||
|
private volatile Set<ClientProfile> profilesList;
|
||||||
|
|
||||||
public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, LaunchServerConfig config, LaunchServerRuntimeConfig runtimeConfig, LaunchServerConfigManager launchServerConfigManager, LaunchServerModulesManager modulesManager, KeyAgreementManager keyAgreementManager, CommandHandler commandHandler, CertificateManager certificateManager, int shardId) throws IOException {
|
public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, LaunchServerConfig config, LaunchServerRuntimeConfig runtimeConfig, LaunchServerConfigManager launchServerConfigManager, LaunchServerModulesManager modulesManager, KeyAgreementManager keyAgreementManager, CommandHandler commandHandler, CertificateManager certificateManager, int shardId) throws IOException {
|
||||||
this.dir = directories.dir;
|
this.dir = directories.dir;
|
||||||
|
@ -126,6 +126,7 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.launchServerConfigManager = launchServerConfigManager;
|
this.launchServerConfigManager = launchServerConfigManager;
|
||||||
this.modulesManager = modulesManager;
|
this.modulesManager = modulesManager;
|
||||||
|
this.profilesDir = directories.profilesDir;
|
||||||
this.updatesDir = directories.updatesDir;
|
this.updatesDir = directories.updatesDir;
|
||||||
this.keyAgreementManager = keyAgreementManager;
|
this.keyAgreementManager = keyAgreementManager;
|
||||||
this.commandHandler = commandHandler;
|
this.commandHandler = commandHandler;
|
||||||
|
@ -135,9 +136,6 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
|
||||||
launcherLibraries = directories.launcherLibrariesDir;
|
launcherLibraries = directories.launcherLibrariesDir;
|
||||||
launcherLibrariesCompile = directories.launcherLibrariesCompileDir;
|
launcherLibrariesCompile = directories.launcherLibrariesCompileDir;
|
||||||
launcherPack = directories.launcherPackDir;
|
launcherPack = directories.launcherPackDir;
|
||||||
modulesDir = directories.modules;
|
|
||||||
launcherModulesDir = directories.launcherModules;
|
|
||||||
librariesDir = directories.librariesDir;
|
|
||||||
this.shardId = shardId;
|
this.shardId = shardId;
|
||||||
if(!Files.isDirectory(launcherPack)) {
|
if(!Files.isDirectory(launcherPack)) {
|
||||||
Files.createDirectories(launcherPack);
|
Files.createDirectories(launcherPack);
|
||||||
|
@ -322,14 +320,12 @@ public void close() throws Exception {
|
||||||
logger.info("LaunchServer stopped");
|
logger.info("LaunchServer stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public Set<ClientProfile> getProfiles() {
|
public Set<ClientProfile> getProfiles() {
|
||||||
return config.profileProvider.getProfiles();
|
return profilesList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void setProfiles(Set<ClientProfile> profilesList) {
|
public void setProfiles(Set<ClientProfile> profilesList) {
|
||||||
throw new UnsupportedOperationException();
|
this.profilesList = Collections.unmodifiableSet(profilesList);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void rebindNettyServerSocket() {
|
public void rebindNettyServerSocket() {
|
||||||
|
@ -355,15 +351,14 @@ public void run() {
|
||||||
// Sync updates dir
|
// Sync updates dir
|
||||||
CommonHelper.newThread("Profiles and updates sync", true, () -> {
|
CommonHelper.newThread("Profiles and updates sync", true, () -> {
|
||||||
try {
|
try {
|
||||||
// Sync profiles dir
|
|
||||||
syncProfilesDir();
|
|
||||||
|
|
||||||
// Sync updates dir
|
|
||||||
if (!IOHelper.isDir(updatesDir))
|
if (!IOHelper.isDir(updatesDir))
|
||||||
Files.createDirectory(updatesDir);
|
Files.createDirectory(updatesDir);
|
||||||
updatesManager.readUpdatesDir();
|
updatesManager.readUpdatesDir();
|
||||||
|
|
||||||
|
// Sync profiles dir
|
||||||
|
if (!IOHelper.isDir(profilesDir))
|
||||||
|
Files.createDirectory(profilesDir);
|
||||||
|
syncProfilesDir();
|
||||||
modulesManager.invokeEvent(new LaunchServerProfilesSyncEvent(this));
|
modulesManager.invokeEvent(new LaunchServerProfilesSyncEvent(this));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.error("Updates/Profiles not synced", e);
|
logger.error("Updates/Profiles not synced", e);
|
||||||
|
@ -398,7 +393,12 @@ public void syncLauncherBinaries() throws IOException {
|
||||||
|
|
||||||
public void syncProfilesDir() throws IOException {
|
public void syncProfilesDir() throws IOException {
|
||||||
logger.info("Syncing profiles dir");
|
logger.info("Syncing profiles dir");
|
||||||
config.profileProvider.sync();
|
List<ClientProfile> newProfies = new LinkedList<>();
|
||||||
|
IOHelper.walk(profilesDir, new ProfilesFileVisitor(newProfies), false);
|
||||||
|
|
||||||
|
// Sort and set new profiles
|
||||||
|
newProfies.sort(Comparator.comparing(a -> a));
|
||||||
|
profilesList = Set.copyOf(newProfies);
|
||||||
if (config.netty.sendProfileUpdatesEvent) {
|
if (config.netty.sendProfileUpdatesEvent) {
|
||||||
sendUpdateProfilesEvent();
|
sendUpdateProfilesEvent();
|
||||||
}
|
}
|
||||||
|
@ -413,7 +413,7 @@ private void sendUpdateProfilesEvent() {
|
||||||
if (client == null || !client.isAuth) {
|
if (client == null || !client.isAuth) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ProfilesRequestEvent event = new ProfilesRequestEvent(config.profileProvider.getProfiles(client));
|
ProfilesRequestEvent event = new ProfilesRequestEvent(ProfilesResponse.getListVisibleProfiles(this, client));
|
||||||
event.requestUUID = RequestEvent.eventUUID;
|
event.requestUUID = RequestEvent.eventUUID;
|
||||||
handler.service.sendObject(ch, event);
|
handler.service.sendObject(ch, event);
|
||||||
});
|
});
|
||||||
|
@ -459,12 +459,38 @@ public interface LaunchServerConfigManager {
|
||||||
void writeRuntimeConfig(LaunchServerRuntimeConfig config) throws IOException;
|
void writeRuntimeConfig(LaunchServerRuntimeConfig config) throws IOException;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class ProfilesFileVisitor extends SimpleFileVisitor<Path> {
|
||||||
|
private final Collection<ClientProfile> result;
|
||||||
|
private final Logger logger = LogManager.getLogger();
|
||||||
|
|
||||||
|
private ProfilesFileVisitor(Collection<ClientProfile> result) {
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||||
|
logger.info("Syncing '{}' profile", IOHelper.getFileName(file));
|
||||||
|
|
||||||
|
// Read profile
|
||||||
|
ClientProfile profile;
|
||||||
|
try (BufferedReader reader = IOHelper.newReader(file)) {
|
||||||
|
profile = Launcher.gsonManager.gson.fromJson(reader, ClientProfile.class);
|
||||||
|
}
|
||||||
|
profile.verify();
|
||||||
|
profile.setProfileFilePath(file);
|
||||||
|
|
||||||
|
// Add SIGNED profile to result list
|
||||||
|
result.add(profile);
|
||||||
|
return super.visitFile(file, attrs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class LaunchServerDirectories {
|
public static class LaunchServerDirectories {
|
||||||
public static final String UPDATES_NAME = "updates",
|
public static final String UPDATES_NAME = "updates", PROFILES_NAME = "profiles",
|
||||||
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";
|
||||||
public Path updatesDir;
|
public Path updatesDir;
|
||||||
public Path librariesDir;
|
public Path profilesDir;
|
||||||
public Path launcherLibrariesDir;
|
public Path launcherLibrariesDir;
|
||||||
public Path launcherLibrariesCompileDir;
|
public Path launcherLibrariesCompileDir;
|
||||||
public Path launcherPackDir;
|
public Path launcherPackDir;
|
||||||
|
@ -472,11 +498,10 @@ public static class LaunchServerDirectories {
|
||||||
public Path dir;
|
public Path dir;
|
||||||
public Path trustStore;
|
public Path trustStore;
|
||||||
public Path tmpDir;
|
public Path tmpDir;
|
||||||
public Path modules;
|
|
||||||
public Path launcherModules;
|
|
||||||
|
|
||||||
public void collect() {
|
public void collect() {
|
||||||
if (updatesDir == null) updatesDir = getPath(UPDATES_NAME);
|
if (updatesDir == null) updatesDir = getPath(UPDATES_NAME);
|
||||||
|
if (profilesDir == null) profilesDir = getPath(PROFILES_NAME);
|
||||||
if (trustStore == null) trustStore = getPath(TRUSTSTORE_NAME);
|
if (trustStore == null) trustStore = getPath(TRUSTSTORE_NAME);
|
||||||
if (launcherLibrariesDir == null) launcherLibrariesDir = getPath(LAUNCHERLIBRARIES_NAME);
|
if (launcherLibrariesDir == null) launcherLibrariesDir = getPath(LAUNCHERLIBRARIES_NAME);
|
||||||
if (launcherLibrariesCompileDir == null)
|
if (launcherLibrariesCompileDir == null)
|
||||||
|
@ -484,9 +509,6 @@ public void collect() {
|
||||||
if(launcherPackDir == null)
|
if(launcherPackDir == null)
|
||||||
launcherPackDir = getPath(LAUNCHERPACK_NAME);
|
launcherPackDir = getPath(LAUNCHERPACK_NAME);
|
||||||
if (keyDirectory == null) keyDirectory = getPath(KEY_NAME);
|
if (keyDirectory == null) keyDirectory = getPath(KEY_NAME);
|
||||||
if (modules == null) modules = getPath(MODULES);
|
|
||||||
if (launcherModules == null) launcherModules = getPath(LAUNCHER_MODULES);
|
|
||||||
if (librariesDir == null) librariesDir = getPath(LIBRARIES);
|
|
||||||
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()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
||||||
import pro.gravit.launchserver.auth.mix.MixProvider;
|
import pro.gravit.launchserver.auth.mix.MixProvider;
|
||||||
import pro.gravit.launchserver.auth.password.PasswordVerifier;
|
import pro.gravit.launchserver.auth.password.PasswordVerifier;
|
||||||
import pro.gravit.launchserver.auth.profiles.ProfileProvider;
|
|
||||||
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
||||||
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
||||||
import pro.gravit.launchserver.components.Component;
|
import pro.gravit.launchserver.components.Component;
|
||||||
|
@ -35,7 +34,6 @@
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class LaunchServerStarter {
|
public class LaunchServerStarter {
|
||||||
|
@ -53,13 +51,10 @@ public static void main(String[] args) throws Exception {
|
||||||
try {
|
try {
|
||||||
Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider");
|
Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider");
|
||||||
Security.addProvider(new BouncyCastleProvider());
|
Security.addProvider(new BouncyCastleProvider());
|
||||||
} catch (ClassNotFoundException | NoClassDefFoundError ex) {
|
} catch (ClassNotFoundException ex) {
|
||||||
LogHelper.error("Library BouncyCastle not found! Is directory 'libraries' empty?");
|
LogHelper.error("Library BouncyCastle not found! Is directory 'libraries' empty?");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LaunchServer.LaunchServerDirectories directories = new LaunchServer.LaunchServerDirectories();
|
|
||||||
directories.dir = dir;
|
|
||||||
directories.collect();
|
|
||||||
CertificateManager certificateManager = new CertificateManager();
|
CertificateManager certificateManager = new CertificateManager();
|
||||||
try {
|
try {
|
||||||
certificateManager.readTrustStore(dir.resolve("truststore"));
|
certificateManager.readTrustStore(dir.resolve("truststore"));
|
||||||
|
@ -83,7 +78,7 @@ public static void main(String[] args) throws Exception {
|
||||||
LaunchServerRuntimeConfig runtimeConfig;
|
LaunchServerRuntimeConfig runtimeConfig;
|
||||||
LaunchServerConfig config;
|
LaunchServerConfig config;
|
||||||
LaunchServer.LaunchServerEnv env = LaunchServer.LaunchServerEnv.PRODUCTION;
|
LaunchServer.LaunchServerEnv env = LaunchServer.LaunchServerEnv.PRODUCTION;
|
||||||
LaunchServerModulesManager modulesManager = new LaunchServerModulesManager(directories.modules, dir.resolve("config"), certificateManager.trustManager);
|
LaunchServerModulesManager modulesManager = new LaunchServerModulesManager(dir.resolve("modules"), dir.resolve("config"), certificateManager.trustManager);
|
||||||
modulesManager.autoload();
|
modulesManager.autoload();
|
||||||
modulesManager.initModules(null);
|
modulesManager.initModules(null);
|
||||||
registerAll();
|
registerAll();
|
||||||
|
@ -128,6 +123,8 @@ public static void main(String[] args) throws Exception {
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchServer.LaunchServerConfigManager launchServerConfigManager = new BasicLaunchServerConfigManager(configFile, runtimeConfigFile);
|
LaunchServer.LaunchServerConfigManager launchServerConfigManager = new BasicLaunchServerConfigManager(configFile, runtimeConfigFile);
|
||||||
|
LaunchServer.LaunchServerDirectories directories = new LaunchServer.LaunchServerDirectories();
|
||||||
|
directories.dir = dir;
|
||||||
LaunchServer server = new LaunchServerBuilder()
|
LaunchServer server = new LaunchServerBuilder()
|
||||||
.setDirectories(directories)
|
.setDirectories(directories)
|
||||||
.setEnv(env)
|
.setEnv(env)
|
||||||
|
@ -138,24 +135,7 @@ public static void main(String[] args) throws Exception {
|
||||||
.setLaunchServerConfigManager(launchServerConfigManager)
|
.setLaunchServerConfigManager(launchServerConfigManager)
|
||||||
.setCertificateManager(certificateManager)
|
.setCertificateManager(certificateManager)
|
||||||
.build();
|
.build();
|
||||||
List<String> allArgs = List.of(args);
|
if (!prepareMode) {
|
||||||
boolean isPrepareMode = prepareMode || allArgs.contains("--prepare");
|
|
||||||
boolean isRunCommand = false;
|
|
||||||
String runCommand = null;
|
|
||||||
for(var e : allArgs) {
|
|
||||||
if(e.equals("--run")) {
|
|
||||||
isRunCommand = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(isRunCommand) {
|
|
||||||
runCommand = e;
|
|
||||||
isRunCommand = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(runCommand != null) {
|
|
||||||
localCommandHandler.eval(runCommand, false);
|
|
||||||
}
|
|
||||||
if (!isPrepareMode) {
|
|
||||||
server.run();
|
server.run();
|
||||||
} else {
|
} else {
|
||||||
server.close();
|
server.close();
|
||||||
|
@ -179,7 +159,6 @@ public static void registerAll() {
|
||||||
OptionalAction.registerProviders();
|
OptionalAction.registerProviders();
|
||||||
OptionalTrigger.registerProviders();
|
OptionalTrigger.registerProviders();
|
||||||
MixProvider.registerProviders();
|
MixProvider.registerProviders();
|
||||||
ProfileProvider.registerProviders();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void printExperimentalBranch() {
|
private static void printExperimentalBranch() {
|
||||||
|
@ -222,7 +201,7 @@ public static void generateConfigIfNotExists(Path configFile, CommandHandler com
|
||||||
address = System.getProperty("launchserver.address", null);
|
address = System.getProperty("launchserver.address", null);
|
||||||
}
|
}
|
||||||
if (address == null) {
|
if (address == null) {
|
||||||
System.out.println("External launchServer address:port (default: localhost:9274): ");
|
System.out.println("LaunchServer address(default: localhost): ");
|
||||||
address = commandHandler.readLine();
|
address = commandHandler.readLine();
|
||||||
}
|
}
|
||||||
String projectName = System.getenv("PROJECTNAME");
|
String projectName = System.getenv("PROJECTNAME");
|
||||||
|
@ -236,29 +215,18 @@ public static void generateConfigIfNotExists(Path configFile, CommandHandler com
|
||||||
newConfig.setProjectName(projectName);
|
newConfig.setProjectName(projectName);
|
||||||
}
|
}
|
||||||
if (address == null || address.isEmpty()) {
|
if (address == null || address.isEmpty()) {
|
||||||
logger.error("Address null. Using localhost:9274");
|
logger.error("Address null. Using localhost");
|
||||||
address = "localhost:9274";
|
address = "localhost";
|
||||||
}
|
}
|
||||||
if (newConfig.projectName == null || newConfig.projectName.isEmpty()) {
|
if (newConfig.projectName == null || newConfig.projectName.isEmpty()) {
|
||||||
logger.error("ProjectName null. Using MineCraft");
|
logger.error("ProjectName null. Using MineCraft");
|
||||||
newConfig.projectName = "MineCraft";
|
newConfig.projectName = "MineCraft";
|
||||||
}
|
}
|
||||||
int port = 9274;
|
|
||||||
if(address.contains(":")) {
|
newConfig.netty.address = "ws://" + address + ":9274/api";
|
||||||
String portString = address.substring(address.indexOf(':')+1);
|
newConfig.netty.downloadURL = "http://" + address + ":9274/%dirname%/";
|
||||||
try {
|
newConfig.netty.launcherURL = "http://" + address + ":9274/Launcher.jar";
|
||||||
port = Integer.parseInt(portString);
|
newConfig.netty.launcherEXEURL = "http://" + address + ":9274/Launcher.exe";
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
logger.warn("Unknown port {}, using 9274", portString);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.info("Address {} doesn't contains port (you want to use nginx?)", address);
|
|
||||||
}
|
|
||||||
newConfig.netty.address = "ws://" + address + "/api";
|
|
||||||
newConfig.netty.downloadURL = "http://" + address + "/%dirname%/";
|
|
||||||
newConfig.netty.launcherURL = "http://" + address + "/Launcher.jar";
|
|
||||||
newConfig.netty.launcherEXEURL = "http://" + address + "/Launcher.exe";
|
|
||||||
newConfig.netty.binds[0].port = port;
|
|
||||||
|
|
||||||
// Write LaunchServer config
|
// Write LaunchServer config
|
||||||
logger.info("Writing LaunchServer config file");
|
logger.info("Writing LaunchServer config file");
|
||||||
|
|
|
@ -21,7 +21,6 @@ public class Main {
|
||||||
private static final List<String> classpathOnly = List.of("proguard", "jline", "progressbar", "kotlin", "epoll");
|
private static final List<String> classpathOnly = List.of("proguard", "jline", "progressbar", "kotlin", "epoll");
|
||||||
private static final String LOG4J_PROPERTY = "log4j2.configurationFile";
|
private static final String LOG4J_PROPERTY = "log4j2.configurationFile";
|
||||||
private static final String DEBUG_PROPERTY = "launchserver.main.debug";
|
private static final String DEBUG_PROPERTY = "launchserver.main.debug";
|
||||||
private static final String LIBRARIES_PROPERTY = "launchserver.dir.libraries";
|
|
||||||
private static boolean isClasspathOnly(Path path) {
|
private static boolean isClasspathOnly(Path path) {
|
||||||
var fileName = path.getFileName().toString();
|
var fileName = path.getFileName().toString();
|
||||||
for(var e : classpathOnly) {
|
for(var e : classpathOnly) {
|
||||||
|
@ -57,9 +56,8 @@ public static void main(String[] args) throws Throwable {
|
||||||
ModuleLaunch launch = new ModuleLaunch();
|
ModuleLaunch launch = new ModuleLaunch();
|
||||||
LaunchOptions options = new LaunchOptions();
|
LaunchOptions options = new LaunchOptions();
|
||||||
options.moduleConf = new LaunchOptions.ModuleConf();
|
options.moduleConf = new LaunchOptions.ModuleConf();
|
||||||
Path librariesPath = Path.of(System.getProperty(LIBRARIES_PROPERTY, "libraries"));
|
|
||||||
List<Path> libraries;
|
List<Path> libraries;
|
||||||
try(Stream<Path> files = Files.walk(librariesPath, FileVisitOption.FOLLOW_LINKS)) {
|
try(Stream<Path> files = Files.walk(Path.of("libraries"), FileVisitOption.FOLLOW_LINKS)) {
|
||||||
libraries = new ArrayList<>(files.filter(e -> e.getFileName().toString().endsWith(".jar")).toList());
|
libraries = new ArrayList<>(files.filter(e -> e.getFileName().toString().endsWith(".jar")).toList());
|
||||||
}
|
}
|
||||||
List<Path> classpath = new ArrayList<>();
|
List<Path> classpath = new ArrayList<>();
|
||||||
|
|
|
@ -1,109 +0,0 @@
|
||||||
package pro.gravit.launchserver.auth.profiles;
|
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import pro.gravit.launcher.base.Launcher;
|
|
||||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.BufferedWriter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.*;
|
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class LocalProfileProvider extends ProfileProvider {
|
|
||||||
public String profilesDir = "profiles";
|
|
||||||
private transient volatile Map<Path, ClientProfile> profilesMap;
|
|
||||||
private transient volatile Set<ClientProfile> profilesList; // Cache
|
|
||||||
@Override
|
|
||||||
public void sync() throws IOException {
|
|
||||||
Path profilesDirPath = Path.of(profilesDir);
|
|
||||||
if (!IOHelper.isDir(profilesDirPath))
|
|
||||||
Files.createDirectory(profilesDirPath);
|
|
||||||
Map<Path, ClientProfile> newProfiles = new HashMap<>();
|
|
||||||
IOHelper.walk(profilesDirPath, new ProfilesFileVisitor(newProfiles), false);
|
|
||||||
Set<ClientProfile> newProfilesList = new HashSet<>(newProfiles.values());
|
|
||||||
profilesMap = newProfiles;
|
|
||||||
profilesList = newProfilesList;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<ClientProfile> getProfiles() {
|
|
||||||
return profilesList;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addProfile(ClientProfile profile) throws IOException {
|
|
||||||
Path profilesDirPath = Path.of(profilesDir);
|
|
||||||
ClientProfile oldProfile;
|
|
||||||
Path target = null;
|
|
||||||
for(var e : profilesMap.entrySet()) {
|
|
||||||
if(e.getValue().getUUID().equals(profile.getUUID())) {
|
|
||||||
target = e.getKey();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(target == null) {
|
|
||||||
target = IOHelper.resolveIncremental(profilesDirPath,
|
|
||||||
profile.getTitle(), "json");
|
|
||||||
oldProfile = profilesMap.get(target);
|
|
||||||
if(oldProfile != null && !oldProfile.getUUID().equals(profile.getUUID())) {
|
|
||||||
throw new FileAlreadyExistsException(target.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try (BufferedWriter writer = IOHelper.newWriter(target)) {
|
|
||||||
Launcher.gsonManager.configGson.toJson(profile, writer);
|
|
||||||
}
|
|
||||||
addProfile(target, profile);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deleteProfile(ClientProfile profile) throws IOException {
|
|
||||||
for(var e : profilesMap.entrySet()) {
|
|
||||||
if(e.getValue().getUUID().equals(profile.getUUID())) {
|
|
||||||
Files.deleteIfExists(e.getKey());
|
|
||||||
profilesMap.remove(e.getKey());
|
|
||||||
profilesList.remove(e.getValue());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addProfile(Path path, ClientProfile profile) {
|
|
||||||
for(var e : profilesMap.entrySet()) {
|
|
||||||
if(e.getValue().getUUID().equals(profile.getUUID())) {
|
|
||||||
profilesMap.remove(e.getKey());
|
|
||||||
profilesList.remove(e.getValue());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
profilesMap.put(path, profile);
|
|
||||||
profilesList.add(profile);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class ProfilesFileVisitor extends SimpleFileVisitor<Path> {
|
|
||||||
private final Map<Path, ClientProfile> result;
|
|
||||||
private final Logger logger = LogManager.getLogger();
|
|
||||||
|
|
||||||
private ProfilesFileVisitor(Map<Path, ClientProfile> result) {
|
|
||||||
this.result = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
|
||||||
logger.info("Syncing '{}' profile", IOHelper.getFileName(file));
|
|
||||||
|
|
||||||
// Read profile
|
|
||||||
ClientProfile profile;
|
|
||||||
try (BufferedReader reader = IOHelper.newReader(file)) {
|
|
||||||
profile = Launcher.gsonManager.gson.fromJson(reader, ClientProfile.class);
|
|
||||||
}
|
|
||||||
profile.verify();
|
|
||||||
|
|
||||||
// Add SIGNED profile to result list
|
|
||||||
result.put(file.toAbsolutePath(), profile);
|
|
||||||
return super.visitFile(file, attrs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
package pro.gravit.launchserver.auth.profiles;
|
|
||||||
|
|
||||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
|
||||||
import pro.gravit.launchserver.auth.protect.interfaces.ProfilesProtectHandler;
|
|
||||||
import pro.gravit.launchserver.socket.Client;
|
|
||||||
import pro.gravit.utils.ProviderMap;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public abstract class ProfileProvider {
|
|
||||||
public static final ProviderMap<ProfileProvider> providers = new ProviderMap<>("ProfileProvider");
|
|
||||||
private static boolean registredProviders = false;
|
|
||||||
protected transient LaunchServer server;
|
|
||||||
|
|
||||||
public static void registerProviders() {
|
|
||||||
if (!registredProviders) {
|
|
||||||
providers.register("local", LocalProfileProvider.class);
|
|
||||||
registredProviders = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init(LaunchServer server) {
|
|
||||||
this.server = server;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void sync() throws IOException;
|
|
||||||
|
|
||||||
public abstract Set<ClientProfile> getProfiles();
|
|
||||||
|
|
||||||
public abstract void addProfile(ClientProfile profile) throws IOException;
|
|
||||||
|
|
||||||
public abstract void deleteProfile(ClientProfile profile) throws IOException;
|
|
||||||
|
|
||||||
public void close() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClientProfile getProfile(UUID uuid) {
|
|
||||||
for(var e : getProfiles()) {
|
|
||||||
if(e.getUUID().equals(uuid)) {
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClientProfile getProfile(String title) {
|
|
||||||
for(var e : getProfiles()) {
|
|
||||||
if(e.getTitle().equals(title)) {
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ClientProfile> getProfiles(Client client) {
|
|
||||||
List<ClientProfile> profileList;
|
|
||||||
Set<ClientProfile> serverProfiles = getProfiles();
|
|
||||||
if (server.config.protectHandler instanceof ProfilesProtectHandler protectHandler) {
|
|
||||||
profileList = new ArrayList<>(4);
|
|
||||||
for (ClientProfile profile : serverProfiles) {
|
|
||||||
if (protectHandler.canGetProfile(profile, client)) {
|
|
||||||
profileList.add(profile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
profileList = List.copyOf(serverProfiles);
|
|
||||||
}
|
|
||||||
return profileList;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -37,9 +37,7 @@ public Path process(Path inputFile) throws IOException {
|
||||||
server.launcherBinary.addonLibs.clear();
|
server.launcherBinary.addonLibs.clear();
|
||||||
server.launcherBinary.files.clear();
|
server.launcherBinary.files.clear();
|
||||||
IOHelper.walk(server.launcherLibraries, new ListFileVisitor(server.launcherBinary.coreLibs), false);
|
IOHelper.walk(server.launcherLibraries, new ListFileVisitor(server.launcherBinary.coreLibs), false);
|
||||||
if(Files.isDirectory(server.launcherLibrariesCompile)) {
|
|
||||||
IOHelper.walk(server.launcherLibrariesCompile, new ListFileVisitor(server.launcherBinary.addonLibs), false);
|
IOHelper.walk(server.launcherLibrariesCompile, new ListFileVisitor(server.launcherBinary.addonLibs), false);
|
||||||
}
|
|
||||||
try(Stream<Path> stream = Files.walk(server.launcherPack).filter((e) -> {
|
try(Stream<Path> stream = Files.walk(server.launcherPack).filter((e) -> {
|
||||||
try {
|
try {
|
||||||
return !Files.isDirectory(e) && !Files.isHidden(e);
|
return !Files.isDirectory(e) && !Files.isHidden(e);
|
||||||
|
|
|
@ -97,7 +97,10 @@ public void invoke(String... args) throws IOException, CommandException {
|
||||||
isMirrorClientDownload = true;
|
isMirrorClientDownload = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
server.config.profileProvider.addProfile(clientProfile);
|
try (BufferedWriter writer = IOHelper.newWriter(IOHelper.resolveIncremental(server.profilesDir,
|
||||||
|
dirName, "json"))) {
|
||||||
|
Launcher.gsonManager.configGson.toJson(clientProfile, writer);
|
||||||
|
}
|
||||||
|
|
||||||
// Finished
|
// Finished
|
||||||
server.syncProfilesDir();
|
server.syncProfilesDir();
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
import pro.gravit.launcher.base.profiles.ClientProfileBuilder;
|
import pro.gravit.launcher.base.profiles.ClientProfileBuilder;
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
import pro.gravit.launchserver.command.Command;
|
import pro.gravit.launchserver.command.Command;
|
||||||
import pro.gravit.utils.helper.CommonHelper;
|
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -27,7 +26,7 @@ public CloneProfileCommand(LaunchServer server) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getArgsDescription() {
|
public String getArgsDescription() {
|
||||||
return "[profile title/uuid] [new profile title]";
|
return "[profile file name] [new profile title]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -38,12 +37,13 @@ public String getUsageDescription() {
|
||||||
@Override
|
@Override
|
||||||
public void invoke(String... args) throws Exception {
|
public void invoke(String... args) throws Exception {
|
||||||
verifyArgs(args, 2);
|
verifyArgs(args, 2);
|
||||||
|
var profilePath = server.profilesDir.resolve(args[0].concat(".json"));
|
||||||
|
if(!Files.exists(profilePath)) {
|
||||||
|
logger.error("File {} not found", profilePath);
|
||||||
|
}
|
||||||
ClientProfile profile;
|
ClientProfile profile;
|
||||||
try {
|
try(Reader reader = IOHelper.newReader(profilePath)) {
|
||||||
UUID uuid = UUID.fromString(args[0]);
|
profile = Launcher.gsonManager.gson.fromJson(reader, ClientProfile.class);
|
||||||
profile = server.config.profileProvider.getProfile(uuid);
|
|
||||||
} catch (IllegalArgumentException ex) {
|
|
||||||
profile = server.config.profileProvider.getProfile(args[0]);
|
|
||||||
}
|
}
|
||||||
var builder = new ClientProfileBuilder(profile);
|
var builder = new ClientProfileBuilder(profile);
|
||||||
builder.setTitle(args[1]);
|
builder.setTitle(args[1]);
|
||||||
|
@ -65,7 +65,10 @@ public void invoke(String... args) throws Exception {
|
||||||
}
|
}
|
||||||
builder.setDir(args[1]);
|
builder.setDir(args[1]);
|
||||||
profile = builder.createClientProfile();
|
profile = builder.createClientProfile();
|
||||||
server.config.profileProvider.addProfile(profile);
|
var targetPath = server.profilesDir.resolve(args[1].concat(".json"));
|
||||||
|
try(Writer writer = IOHelper.newWriter(targetPath)) {
|
||||||
|
Launcher.gsonManager.gson.toJson(profile, writer);
|
||||||
|
}
|
||||||
logger.info("Profile {} cloned from {}", args[1], args[0]);
|
logger.info("Profile {} cloned from {}", args[1], args[0]);
|
||||||
server.syncProfilesDir();
|
server.syncProfilesDir();
|
||||||
server.syncUpdatesDir(List.of(args[1]));
|
server.syncUpdatesDir(List.of(args[1]));
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class DeleteProfileCommand extends Command {
|
public class DeleteProfileCommand extends Command {
|
||||||
private final transient Logger logger = LogManager.getLogger(ListProfilesCommand.class);
|
private final transient Logger logger = LogManager.getLogger(ListProfilesCommand.class);
|
||||||
|
@ -29,12 +28,12 @@ public String getUsageDescription() {
|
||||||
@Override
|
@Override
|
||||||
public void invoke(String... args) throws Exception {
|
public void invoke(String... args) throws Exception {
|
||||||
verifyArgs(args, 1);
|
verifyArgs(args, 1);
|
||||||
ClientProfile profile;
|
ClientProfile profile = null;
|
||||||
try {
|
for(var p : server.getProfiles()) {
|
||||||
UUID uuid = UUID.fromString(args[0]);
|
if(p.getUUID().toString().equals(args[0]) || p.getTitle().equals(args[0])) {
|
||||||
profile = server.config.profileProvider.getProfile(uuid);
|
profile = p;
|
||||||
} catch (IllegalArgumentException ex) {
|
break;
|
||||||
profile = server.config.profileProvider.getProfile(args[0]);
|
}
|
||||||
}
|
}
|
||||||
if(profile == null) {
|
if(profile == null) {
|
||||||
logger.error("Profile {} not found", args[0]);
|
logger.error("Profile {} not found", args[0]);
|
||||||
|
@ -45,9 +44,13 @@ public void invoke(String... args) throws Exception {
|
||||||
if(!showApplyDialog("Continue?")) {
|
if(!showApplyDialog("Continue?")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logger.info("Delete {} ({})", profile.getTitle(), profile.getUUID());
|
|
||||||
server.config.profileProvider.deleteProfile(profile);
|
|
||||||
logger.info("Delete {}", clientDir);
|
logger.info("Delete {}", clientDir);
|
||||||
IOHelper.deleteDir(clientDir, true);
|
IOHelper.deleteDir(clientDir, true);
|
||||||
|
var profileFile = profile.getProfileFilePath();
|
||||||
|
if(profileFile == null) {
|
||||||
|
profileFile = server.profilesDir.resolve(profile.getTitle().concat(".json"));
|
||||||
|
}
|
||||||
|
logger.info("Delete {}", profileFile);
|
||||||
|
Files.deleteIfExists(profileFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,9 @@ public void invoke(String... args) throws Exception {
|
||||||
logger.info("Detected option {}", option);
|
logger.info("Detected option {}", option);
|
||||||
}
|
}
|
||||||
ClientProfile profile = MakeProfileHelper.makeProfile(version, args[0], options);
|
ClientProfile profile = MakeProfileHelper.makeProfile(version, args[0], options);
|
||||||
server.config.profileProvider.addProfile(profile);
|
try (Writer writer = IOHelper.newWriter(server.profilesDir.resolve(args[0].concat(".json")))) {
|
||||||
|
Launcher.gsonManager.configGson.toJson(profile, writer);
|
||||||
|
}
|
||||||
logger.info("Profile {} created", args[0]);
|
logger.info("Profile {} created", args[0]);
|
||||||
server.syncProfilesDir();
|
server.syncProfilesDir();
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,20 @@ public SaveProfilesCommand(LaunchServer server) {
|
||||||
super(server);
|
super(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void saveProfile(ClientProfile profile, Path path) throws IOException {
|
||||||
|
if (profile.getServers().isEmpty()) {
|
||||||
|
ClientProfile.ServerProfile serverProfile = new ClientProfile.ServerProfile();
|
||||||
|
serverProfile.isDefault = true;
|
||||||
|
serverProfile.name = profile.getTitle();
|
||||||
|
serverProfile.serverAddress = profile.getServerAddress();
|
||||||
|
serverProfile.serverPort = profile.getServerPort();
|
||||||
|
profile.getServers().add(serverProfile);
|
||||||
|
}
|
||||||
|
try (Writer w = IOHelper.newWriter(path)) {
|
||||||
|
Launcher.gsonManager.configGson.toJson(profile, w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getArgsDescription() {
|
public String getArgsDescription() {
|
||||||
return "[profile names...]";
|
return "[profile names...]";
|
||||||
|
@ -37,14 +51,17 @@ public void invoke(String... args) throws Exception {
|
||||||
verifyArgs(args, 1);
|
verifyArgs(args, 1);
|
||||||
if (args.length > 0) {
|
if (args.length > 0) {
|
||||||
for (String profileName : args) {
|
for (String profileName : args) {
|
||||||
ClientProfile profile;
|
Path profilePath = server.profilesDir.resolve(profileName.concat(".json"));
|
||||||
try {
|
if (!Files.exists(profilePath)) {
|
||||||
UUID uuid = UUID.fromString(profileName);
|
logger.error("Profile {} not found", profilePath.toString());
|
||||||
profile = server.config.profileProvider.getProfile(uuid);
|
return;
|
||||||
} catch (IllegalArgumentException ex) {
|
|
||||||
profile = server.config.profileProvider.getProfile(profileName);
|
|
||||||
}
|
}
|
||||||
server.config.profileProvider.addProfile(profile);
|
ClientProfile profile;
|
||||||
|
try (Reader reader = IOHelper.newReader(profilePath)) {
|
||||||
|
profile = Launcher.gsonManager.configGson.fromJson(reader, ClientProfile.class);
|
||||||
|
}
|
||||||
|
saveProfile(profile, profilePath);
|
||||||
|
logger.info("Profile {} save successful", profilePath.toString());
|
||||||
}
|
}
|
||||||
server.syncProfilesDir();
|
server.syncProfilesDir();
|
||||||
}
|
}
|
||||||
|
|
|
@ -213,7 +213,7 @@ public Path process(Path inputFile) throws IOException {
|
||||||
args.add(IOHelper.resolveJavaBin(IOHelper.JVM_DIR).toAbsolutePath().toString());
|
args.add(IOHelper.resolveJavaBin(IOHelper.JVM_DIR).toAbsolutePath().toString());
|
||||||
args.addAll(component.jvmArgs);
|
args.addAll(component.jvmArgs);
|
||||||
args.add("-cp");
|
args.add("-cp");
|
||||||
try(Stream<Path> files = Files.walk(server.librariesDir, FileVisitOption.FOLLOW_LINKS)) {
|
try(Stream<Path> files = Files.walk(Path.of("libraries"), FileVisitOption.FOLLOW_LINKS)) {
|
||||||
args.add(files
|
args.add(files
|
||||||
.filter(e -> e.getFileName().toString().endsWith(".jar"))
|
.filter(e -> e.getFileName().toString().endsWith(".jar"))
|
||||||
.map(path -> path.toAbsolutePath().toString())
|
.map(path -> path.toAbsolutePath().toString())
|
||||||
|
|
|
@ -9,8 +9,6 @@
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
import pro.gravit.launchserver.auth.AuthProviderPair;
|
import pro.gravit.launchserver.auth.AuthProviderPair;
|
||||||
import pro.gravit.launchserver.auth.core.RejectAuthCoreProvider;
|
import pro.gravit.launchserver.auth.core.RejectAuthCoreProvider;
|
||||||
import pro.gravit.launchserver.auth.profiles.LocalProfileProvider;
|
|
||||||
import pro.gravit.launchserver.auth.profiles.ProfileProvider;
|
|
||||||
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
||||||
import pro.gravit.launchserver.auth.protect.StdProtectHandler;
|
import pro.gravit.launchserver.auth.protect.StdProtectHandler;
|
||||||
import pro.gravit.launchserver.auth.texture.RequestTextureProvider;
|
import pro.gravit.launchserver.auth.texture.RequestTextureProvider;
|
||||||
|
@ -38,7 +36,6 @@ public final class LaunchServerConfig {
|
||||||
// Handlers & Providers
|
// Handlers & Providers
|
||||||
public ProtectHandler protectHandler;
|
public ProtectHandler protectHandler;
|
||||||
public Map<String, Component> components;
|
public Map<String, Component> components;
|
||||||
public ProfileProvider profileProvider = new LocalProfileProvider();
|
|
||||||
public NettyConfig netty;
|
public NettyConfig netty;
|
||||||
public LauncherConf launcher;
|
public LauncherConf launcher;
|
||||||
public JarSignerConf sign;
|
public JarSignerConf sign;
|
||||||
|
@ -88,7 +85,6 @@ public static LaunchServerConfig getDefault(LaunchServer.LaunchServerEnv env) {
|
||||||
newConfig.components.put("authLimiter", authLimiterComponent);
|
newConfig.components.put("authLimiter", authLimiterComponent);
|
||||||
ProGuardComponent proGuardComponent = new ProGuardComponent();
|
ProGuardComponent proGuardComponent = new ProGuardComponent();
|
||||||
newConfig.components.put("proguard", proGuardComponent);
|
newConfig.components.put("proguard", proGuardComponent);
|
||||||
newConfig.profileProvider = new LocalProfileProvider();
|
|
||||||
return newConfig;
|
return newConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,10 +166,6 @@ public void init(LaunchServer.ReloadType type) {
|
||||||
server.registerObject("protectHandler", protectHandler);
|
server.registerObject("protectHandler", protectHandler);
|
||||||
protectHandler.init(server);
|
protectHandler.init(server);
|
||||||
}
|
}
|
||||||
if(profileProvider != null) {
|
|
||||||
server.registerObject("profileProvider", profileProvider);
|
|
||||||
profileProvider.init(server);
|
|
||||||
}
|
|
||||||
if (components != null) {
|
if (components != null) {
|
||||||
components.forEach((k, v) -> server.registerObject("component.".concat(k), v));
|
components.forEach((k, v) -> server.registerObject("component.".concat(k), v));
|
||||||
}
|
}
|
||||||
|
@ -214,10 +206,6 @@ public void close(LaunchServer.ReloadType type) {
|
||||||
server.unregisterObject("protectHandler", protectHandler);
|
server.unregisterObject("protectHandler", protectHandler);
|
||||||
protectHandler.close();
|
protectHandler.close();
|
||||||
}
|
}
|
||||||
if(profileProvider != null) {
|
|
||||||
server.unregisterObject("profileProvider", profileProvider);
|
|
||||||
profileProvider.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class JarSignerConf {
|
public static class JarSignerConf {
|
||||||
|
|
|
@ -103,7 +103,6 @@ public static ClientProfile makeProfile(ClientProfile.Version version, String ti
|
||||||
}
|
}
|
||||||
if (fabric.isPresent()) {
|
if (fabric.isPresent()) {
|
||||||
builder.setAltClassPath(fabric.orElseThrow().getAltClassPath());
|
builder.setAltClassPath(fabric.orElseThrow().getAltClassPath());
|
||||||
jvmArgs.add("-Dsodium.checks.issue2561=false"); // Please don't check LWJL3 version (Sodium: https://github.com/CaffeineMC/sodium-fabric/issues/2561 )
|
|
||||||
}
|
}
|
||||||
if(quilt.isPresent()) {
|
if(quilt.isPresent()) {
|
||||||
builder.setClassLoaderConfig(ClientProfile.ClassLoaderConfig.SYSTEM_ARGS);
|
builder.setClassLoaderConfig(ClientProfile.ClassLoaderConfig.SYSTEM_ARGS);
|
||||||
|
@ -197,9 +196,6 @@ public static String getMainClassByVersion(ClientProfile.Version version, MakePr
|
||||||
if(version.compareTo(ClientProfileVersions.MINECRAFT_1_7_10) == 0) {
|
if(version.compareTo(ClientProfileVersions.MINECRAFT_1_7_10) == 0) {
|
||||||
return "com.gtnewhorizons.retrofuturabootstrap.Main";
|
return "com.gtnewhorizons.retrofuturabootstrap.Main";
|
||||||
}
|
}
|
||||||
if(version.compareTo(ClientProfileVersions.MINECRAFT_1_12_2) == 0) {
|
|
||||||
return "top.outlands.foundation.boot.Foundation"; // Cleanroom
|
|
||||||
}
|
|
||||||
if (findOption(options, MakeProfileOptionLaunchWrapper.class).isPresent()) {
|
if (findOption(options, MakeProfileOptionLaunchWrapper.class).isPresent()) {
|
||||||
return "net.minecraft.launchwrapper.Launch";
|
return "net.minecraft.launchwrapper.Launch";
|
||||||
}
|
}
|
||||||
|
@ -207,7 +203,7 @@ public static String getMainClassByVersion(ClientProfile.Version version, MakePr
|
||||||
return "cpw.mods.modlauncher.Launcher";
|
return "cpw.mods.modlauncher.Launcher";
|
||||||
}
|
}
|
||||||
if (findOption(options, MakeProfileOptionFabric.class).isPresent()) {
|
if (findOption(options, MakeProfileOptionFabric.class).isPresent()) {
|
||||||
return "net.fabricmc.loader.impl.launch.knot.KnotClient";
|
return "net.fabricmc.loader.launch.knot.KnotClient";
|
||||||
}
|
}
|
||||||
if(findOption(options, MakeProfilesOptionsQuilt.class).isPresent()) {
|
if(findOption(options, MakeProfilesOptionsQuilt.class).isPresent()) {
|
||||||
return "org.quiltmc.loader.impl.launch.knot.KnotClient";
|
return "org.quiltmc.loader.impl.launch.knot.KnotClient";
|
||||||
|
|
|
@ -33,7 +33,7 @@ public class LauncherModuleLoader {
|
||||||
|
|
||||||
public LauncherModuleLoader(LaunchServer server) {
|
public LauncherModuleLoader(LaunchServer server) {
|
||||||
this.server = server;
|
this.server = server;
|
||||||
modulesDir = server.launcherModulesDir;
|
modulesDir = server.dir.resolve("launcher-modules");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init() {
|
public void init() {
|
||||||
|
|
|
@ -22,7 +22,6 @@ public class KeyAgreementManager {
|
||||||
public final RSAPublicKey rsaPublicKey;
|
public final RSAPublicKey rsaPublicKey;
|
||||||
public final RSAPrivateKey rsaPrivateKey;
|
public final RSAPrivateKey rsaPrivateKey;
|
||||||
public final String legacySalt;
|
public final String legacySalt;
|
||||||
public final Path keyDirectory;
|
|
||||||
|
|
||||||
public KeyAgreementManager(ECPublicKey ecdsaPublicKey, ECPrivateKey ecdsaPrivateKey, RSAPublicKey rsaPublicKey, RSAPrivateKey rsaPrivateKey, String legacySalt) {
|
public KeyAgreementManager(ECPublicKey ecdsaPublicKey, ECPrivateKey ecdsaPrivateKey, RSAPublicKey rsaPublicKey, RSAPrivateKey rsaPrivateKey, String legacySalt) {
|
||||||
this.ecdsaPublicKey = ecdsaPublicKey;
|
this.ecdsaPublicKey = ecdsaPublicKey;
|
||||||
|
@ -30,11 +29,9 @@ public KeyAgreementManager(ECPublicKey ecdsaPublicKey, ECPrivateKey ecdsaPrivate
|
||||||
this.rsaPublicKey = rsaPublicKey;
|
this.rsaPublicKey = rsaPublicKey;
|
||||||
this.rsaPrivateKey = rsaPrivateKey;
|
this.rsaPrivateKey = rsaPrivateKey;
|
||||||
this.legacySalt = legacySalt;
|
this.legacySalt = legacySalt;
|
||||||
this.keyDirectory = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeyAgreementManager(Path keyDirectory) throws IOException, InvalidKeySpecException {
|
public KeyAgreementManager(Path keyDirectory) throws IOException, InvalidKeySpecException {
|
||||||
this.keyDirectory = keyDirectory;
|
|
||||||
Path ecdsaPublicKeyPath = keyDirectory.resolve("ecdsa_id.pub"), ecdsaPrivateKeyPath = keyDirectory.resolve("ecdsa_id");
|
Path ecdsaPublicKeyPath = keyDirectory.resolve("ecdsa_id.pub"), ecdsaPrivateKeyPath = keyDirectory.resolve("ecdsa_id");
|
||||||
Logger logger = LogManager.getLogger();
|
Logger logger = LogManager.getLogger();
|
||||||
if (IOHelper.isFile(ecdsaPublicKeyPath) && IOHelper.isFile(ecdsaPrivateKeyPath)) {
|
if (IOHelper.isFile(ecdsaPublicKeyPath) && IOHelper.isFile(ecdsaPrivateKeyPath)) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package pro.gravit.launchserver.manangers;
|
package pro.gravit.launchserver.manangers;
|
||||||
|
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
|
import marcono1234.gson.recordadapter.RecordTypeAdapterFactory;
|
||||||
import pro.gravit.launcher.base.events.request.GetAvailabilityAuthRequestEvent;
|
import pro.gravit.launcher.base.events.request.GetAvailabilityAuthRequestEvent;
|
||||||
import pro.gravit.launcher.core.managers.GsonManager;
|
import pro.gravit.launcher.core.managers.GsonManager;
|
||||||
import pro.gravit.launcher.base.modules.events.PreGsonPhase;
|
import pro.gravit.launcher.base.modules.events.PreGsonPhase;
|
||||||
|
@ -14,7 +15,6 @@
|
||||||
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
||||||
import pro.gravit.launchserver.auth.mix.MixProvider;
|
import pro.gravit.launchserver.auth.mix.MixProvider;
|
||||||
import pro.gravit.launchserver.auth.password.PasswordVerifier;
|
import pro.gravit.launchserver.auth.password.PasswordVerifier;
|
||||||
import pro.gravit.launchserver.auth.profiles.ProfileProvider;
|
|
||||||
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
||||||
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
||||||
import pro.gravit.launchserver.components.Component;
|
import pro.gravit.launchserver.components.Component;
|
||||||
|
@ -34,6 +34,9 @@ public LaunchServerGsonManager(LaunchServerModulesManager modulesManager) {
|
||||||
@Override
|
@Override
|
||||||
public void registerAdapters(GsonBuilder builder) {
|
public void registerAdapters(GsonBuilder builder) {
|
||||||
super.registerAdapters(builder);
|
super.registerAdapters(builder);
|
||||||
|
builder.registerTypeAdapterFactory(RecordTypeAdapterFactory.builder()
|
||||||
|
.allowMissingComponentValues()
|
||||||
|
.create());
|
||||||
builder.registerTypeAdapter(ClientProfile.Version.class, new ClientProfile.Version.GsonSerializer());
|
builder.registerTypeAdapter(ClientProfile.Version.class, new ClientProfile.Version.GsonSerializer());
|
||||||
builder.registerTypeAdapter(TextureProvider.class, new UniversalJsonAdapter<>(TextureProvider.providers));
|
builder.registerTypeAdapter(TextureProvider.class, new UniversalJsonAdapter<>(TextureProvider.providers));
|
||||||
builder.registerTypeAdapter(AuthCoreProvider.class, new UniversalJsonAdapter<>(AuthCoreProvider.providers));
|
builder.registerTypeAdapter(AuthCoreProvider.class, new UniversalJsonAdapter<>(AuthCoreProvider.providers));
|
||||||
|
@ -47,7 +50,6 @@ public void registerAdapters(GsonBuilder builder) {
|
||||||
builder.registerTypeAdapter(OptionalAction.class, new UniversalJsonAdapter<>(OptionalAction.providers));
|
builder.registerTypeAdapter(OptionalAction.class, new UniversalJsonAdapter<>(OptionalAction.providers));
|
||||||
builder.registerTypeAdapter(OptionalTrigger.class, new UniversalJsonAdapter<>(OptionalTrigger.providers));
|
builder.registerTypeAdapter(OptionalTrigger.class, new UniversalJsonAdapter<>(OptionalTrigger.providers));
|
||||||
builder.registerTypeAdapter(MixProvider.class, new UniversalJsonAdapter<>(MixProvider.providers));
|
builder.registerTypeAdapter(MixProvider.class, new UniversalJsonAdapter<>(MixProvider.providers));
|
||||||
builder.registerTypeAdapter(ProfileProvider.class, new UniversalJsonAdapter<>(ProfileProvider.providers));
|
|
||||||
modulesManager.invokeEvent(new PreGsonPhase(builder));
|
modulesManager.invokeEvent(new PreGsonPhase(builder));
|
||||||
//ClientWebSocketService.appendTypeAdapters(builder);
|
//ClientWebSocketService.appendTypeAdapters(builder);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
import pro.gravit.launcher.core.LauncherNetworkAPI;
|
import pro.gravit.launcher.core.LauncherNetworkAPI;
|
||||||
import pro.gravit.launcher.core.backend.UserSettings;
|
import pro.gravit.launcher.core.backend.UserSettings;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@ -11,7 +10,7 @@ public class BackendSettings extends UserSettings {
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
public AuthorizationData auth;
|
public AuthorizationData auth;
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
public Map<UUID, ProfileSettingsImpl> settings = new HashMap<>();
|
public Map<UUID, ProfileSettingsImpl> settings;
|
||||||
public static class AuthorizationData {
|
public static class AuthorizationData {
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
public String accessToken;
|
public String accessToken;
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
import pro.gravit.launcher.base.profiles.ClientProfile;
|
||||||
import pro.gravit.launcher.core.api.LauncherAPIHolder;
|
import pro.gravit.launcher.core.api.LauncherAPIHolder;
|
||||||
import pro.gravit.launcher.core.api.features.AuthFeatureAPI;
|
import pro.gravit.launcher.core.api.features.AuthFeatureAPI;
|
||||||
import pro.gravit.launcher.core.api.features.CoreFeatureAPI;
|
|
||||||
import pro.gravit.launcher.core.api.features.ProfileFeatureAPI;
|
import pro.gravit.launcher.core.api.features.ProfileFeatureAPI;
|
||||||
import pro.gravit.launcher.core.api.method.AuthMethod;
|
import pro.gravit.launcher.core.api.method.AuthMethod;
|
||||||
import pro.gravit.launcher.core.api.method.AuthMethodPassword;
|
import pro.gravit.launcher.core.api.method.AuthMethodPassword;
|
||||||
|
@ -16,8 +15,6 @@
|
||||||
import pro.gravit.launcher.core.backend.exceptions.LauncherBackendException;
|
import pro.gravit.launcher.core.backend.exceptions.LauncherBackendException;
|
||||||
import pro.gravit.launcher.core.backend.extensions.Extension;
|
import pro.gravit.launcher.core.backend.extensions.Extension;
|
||||||
import pro.gravit.launcher.runtime.NewLauncherSettings;
|
import pro.gravit.launcher.runtime.NewLauncherSettings;
|
||||||
import pro.gravit.launcher.runtime.client.ServerPinger;
|
|
||||||
import pro.gravit.launcher.runtime.debug.DebugMain;
|
|
||||||
import pro.gravit.launcher.runtime.managers.SettingsManager;
|
import pro.gravit.launcher.runtime.managers.SettingsManager;
|
||||||
import pro.gravit.launcher.runtime.utils.LauncherUpdater;
|
import pro.gravit.launcher.runtime.utils.LauncherUpdater;
|
||||||
import pro.gravit.utils.helper.JavaHelper;
|
import pro.gravit.utils.helper.JavaHelper;
|
||||||
|
@ -30,10 +27,7 @@
|
||||||
import java.time.ZoneOffset;
|
import java.time.ZoneOffset;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
@ -53,7 +47,6 @@ public class LauncherBackendImpl implements LauncherBackendAPI {
|
||||||
private volatile SelfUser selfUser;
|
private volatile SelfUser selfUser;
|
||||||
private volatile List<Java> availableJavas;
|
private volatile List<Java> availableJavas;
|
||||||
private volatile CompletableFuture<List<Java>> availableJavasFuture;
|
private volatile CompletableFuture<List<Java>> availableJavasFuture;
|
||||||
private final Map<UUID, CompletableFuture<ServerPingInfo>> pingFutures = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCallback(MainCallback callback) {
|
public void setCallback(MainCallback callback) {
|
||||||
|
@ -82,13 +75,7 @@ public CompletableFuture<LauncherInitData> init() {
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
return CompletableFuture.failedFuture(e);
|
return CompletableFuture.failedFuture(e);
|
||||||
}
|
}
|
||||||
CompletableFuture<CoreFeatureAPI.LauncherUpdateInfo> feature;
|
return LauncherAPIHolder.core().checkUpdates().thenCombineAsync(LauncherAPIHolder.core().getAuthMethods(), (updatesInfo, authMethods) -> {
|
||||||
if(isTestMode()) {
|
|
||||||
feature = CompletableFuture.completedFuture(new CoreFeatureAPI.LauncherUpdateInfo(null, "Unknown", false, false));
|
|
||||||
} else {
|
|
||||||
feature = LauncherAPIHolder.core().checkUpdates();
|
|
||||||
}
|
|
||||||
return feature.thenCombineAsync(LauncherAPIHolder.core().getAuthMethods(), (updatesInfo, authMethods) -> {
|
|
||||||
if(updatesInfo.required()) {
|
if(updatesInfo.required()) {
|
||||||
try {
|
try {
|
||||||
LauncherUpdater.prepareUpdate(URI.create(updatesInfo.url()).toURL());
|
LauncherUpdater.prepareUpdate(URI.create(updatesInfo.url()).toURL());
|
||||||
|
@ -144,7 +131,6 @@ private void setAuthToken(AuthFeatureAPI.AuthToken authToken) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onAuthorize(SelfUser selfUser) {
|
private void onAuthorize(SelfUser selfUser) {
|
||||||
this.selfUser = selfUser;
|
|
||||||
permissions = selfUser.getPermissions();
|
permissions = selfUser.getPermissions();
|
||||||
callback.onAuthorize(selfUser);
|
callback.onAuthorize(selfUser);
|
||||||
}
|
}
|
||||||
|
@ -196,7 +182,7 @@ public CompletableFuture<ReadyProfile> downloadProfile(ProfileFeatureAPI.ClientP
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<byte[]> fetchTexture(Texture texture) {
|
public CompletableFuture<byte[]> fetchTexture(Texture texture) {
|
||||||
return CompletableFuture.failedFuture(new UnsupportedOperationException());
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
|
@ -215,22 +201,6 @@ public CompletableFuture<List<Java>> getAvailableJava() {
|
||||||
return CompletableFuture.completedFuture(availableJavas);
|
return CompletableFuture.completedFuture(availableJavas);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompletableFuture<ServerPingInfo> pingServer(ProfileFeatureAPI.ClientProfile profile) {
|
|
||||||
return pingFutures.computeIfAbsent(profile.getUUID(), (k) -> {
|
|
||||||
CompletableFuture<ServerPingInfo> future = new CompletableFuture<>();
|
|
||||||
executorService.submit(() -> {
|
|
||||||
try {
|
|
||||||
ServerPinger pinger = new ServerPinger((ClientProfile) profile);
|
|
||||||
future.complete(pinger.ping());
|
|
||||||
} catch (Throwable e) {
|
|
||||||
future.completeExceptionally(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return future;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerUserSettings(String name, Class<? extends UserSettings> clazz) {
|
public void registerUserSettings(String name, Class<? extends UserSettings> clazz) {
|
||||||
UserSettings.providers.register(name, clazz);
|
UserSettings.providers.register(name, clazz);
|
||||||
|
@ -261,15 +231,6 @@ public SelfUser getSelfUser() {
|
||||||
return selfUser;
|
return selfUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isTestMode() {
|
|
||||||
try {
|
|
||||||
return DebugMain.IS_DEBUG.get();
|
|
||||||
} catch (Throwable ex) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T extends Extension> T getExtension(Class<T> clazz) {
|
public <T extends Extension> T getExtension(Class<T> clazz) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -277,10 +238,7 @@ public <T extends Extension> T getExtension(Class<T> clazz) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
if(executorService != null) {
|
|
||||||
executorService.shutdownNow();
|
executorService.shutdownNow();
|
||||||
}
|
|
||||||
if(settingsManager != null) {
|
|
||||||
try {
|
try {
|
||||||
settingsManager.saveConfig();
|
settingsManager.saveConfig();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -288,4 +246,3 @@ public void shutdown() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -145,22 +145,7 @@ public void start(boolean pipeOutput) throws IOException, InterruptedException {
|
||||||
if (params.profile.getClassLoaderConfig() == ClientProfile.ClassLoaderConfig.AGENT) {
|
if (params.profile.getClassLoaderConfig() == ClientProfile.ClassLoaderConfig.AGENT) {
|
||||||
processArgs.add("-javaagent:".concat(IOHelper.getCodeSource(ClientLauncherEntryPoint.class).toAbsolutePath().toString()));
|
processArgs.add("-javaagent:".concat(IOHelper.getCodeSource(ClientLauncherEntryPoint.class).toAbsolutePath().toString()));
|
||||||
} else if (params.profile.getClassLoaderConfig() == ClientProfile.ClassLoaderConfig.SYSTEM_ARGS) {
|
} else if (params.profile.getClassLoaderConfig() == ClientProfile.ClassLoaderConfig.SYSTEM_ARGS) {
|
||||||
Set<Path> ignorePath = new HashSet<>();
|
systemClassPath.addAll(ClientLauncherEntryPoint.resolveClassPath(new HashSet<>(), workDir, params.actions, params.profile)
|
||||||
var moduleConf = params.profile.getModuleConf();
|
|
||||||
if(moduleConf != null) {
|
|
||||||
if(moduleConf.modulePath != null && !moduleConf.modulePath.isEmpty()) {
|
|
||||||
processArgs.add("-p");
|
|
||||||
for(var e : moduleConf.modulePath) {
|
|
||||||
ignorePath.add(Path.of(e));
|
|
||||||
}
|
|
||||||
processArgs.add(String.join(File.pathSeparator, moduleConf.modulePath));
|
|
||||||
}
|
|
||||||
if(moduleConf.modules != null && !moduleConf.modules.isEmpty()) {
|
|
||||||
processArgs.add("--add-modules");
|
|
||||||
processArgs.add(String.join(",", moduleConf.modules));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
systemClassPath.addAll(ClientLauncherEntryPoint.resolveClassPath(ignorePath, workDir, params.actions, params.profile)
|
|
||||||
.map(Path::toString)
|
.map(Path::toString)
|
||||||
.toList());
|
.toList());
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
import pro.gravit.launcher.base.profiles.ClientProfile;
|
||||||
import pro.gravit.launcher.base.profiles.ClientProfileVersions;
|
import pro.gravit.launcher.base.profiles.ClientProfileVersions;
|
||||||
import pro.gravit.launcher.core.backend.LauncherBackendAPI;
|
|
||||||
import pro.gravit.launcher.core.serialize.HInput;
|
import pro.gravit.launcher.core.serialize.HInput;
|
||||||
import pro.gravit.launcher.core.serialize.HOutput;
|
import pro.gravit.launcher.core.serialize.HOutput;
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
|
@ -19,7 +18,6 @@
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@ -210,7 +208,7 @@ public Result ping() throws IOException {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class Result implements LauncherBackendAPI.ServerPingInfo {
|
public static final class Result {
|
||||||
|
|
||||||
public final int onlinePlayers;
|
public final int onlinePlayers;
|
||||||
|
|
||||||
|
@ -230,20 +228,5 @@ public Result(int onlinePlayers, int maxPlayers, String raw) {
|
||||||
public boolean isOverfilled() {
|
public boolean isOverfilled() {
|
||||||
return onlinePlayers >= maxPlayers;
|
return onlinePlayers >= maxPlayers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getMaxOnline() {
|
|
||||||
return maxPlayers;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getOnline() {
|
|
||||||
return onlinePlayers;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<String> getPlayerNames() {
|
|
||||||
return List.of();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -261,7 +261,7 @@ protected HttpRequest makeHttpRequest(URI baseUri, String filePath) throws URISy
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ProgressTrackingBodyHandler<Path> makeBodyHandler(Path file, DownloadCallback callback) {
|
protected ProgressTrackingBodyHandler<Path> makeBodyHandler(Path file, DownloadCallback callback) {
|
||||||
return new ProgressTrackingBodyHandler<>(HttpResponse.BodyHandlers.ofFile(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING), callback);
|
return new ProgressTrackingBodyHandler<>(HttpResponse.BodyHandlers.ofFile(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE), callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface DownloadCallback {
|
public interface DownloadCallback {
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
public final class ClientProfile implements Comparable<ClientProfile>, ProfileFeatureAPI.ClientProfile {
|
public final class ClientProfile implements Comparable<ClientProfile>, ProfileFeatureAPI.ClientProfile {
|
||||||
private static final FileNameMatcher ASSET_MATCHER = new FileNameMatcher(
|
private static final FileNameMatcher ASSET_MATCHER = new FileNameMatcher(
|
||||||
new String[0], new String[]{"indexes", "objects"}, new String[0]);
|
new String[0], new String[]{"indexes", "objects"}, new String[0]);
|
||||||
|
private transient Path profileFilePath;
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
private String title;
|
private String title;
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
|
@ -379,11 +380,6 @@ public Map<String, String> getProperties() {
|
||||||
return Collections.unmodifiableMap(properties);
|
return Collections.unmodifiableMap(properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ServerInfo getServer() {
|
|
||||||
return getDefaultServerProfile();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getCompatClasses() {
|
public List<String> getCompatClasses() {
|
||||||
return Collections.unmodifiableList(compatClasses);
|
return Collections.unmodifiableList(compatClasses);
|
||||||
}
|
}
|
||||||
|
@ -413,6 +409,14 @@ public List<CompatibilityFlags> getFlags() {
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Path getProfileFilePath() {
|
||||||
|
return profileFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProfileFilePath(Path profileFilePath) {
|
||||||
|
this.profileFilePath = profileFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
public enum ClassLoaderConfig {
|
public enum ClassLoaderConfig {
|
||||||
AGENT, LAUNCHER, MODULE, SYSTEM_ARGS
|
AGENT, LAUNCHER, MODULE, SYSTEM_ARGS
|
||||||
}
|
}
|
||||||
|
@ -521,7 +525,7 @@ public JsonElement serialize(Version src, Type typeOfSrc, JsonSerializationConte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ServerProfile implements ServerInfo {
|
public static class ServerProfile {
|
||||||
public String name;
|
public String name;
|
||||||
public String serverAddress;
|
public String serverAddress;
|
||||||
public int serverPort;
|
public int serverPort;
|
||||||
|
@ -548,16 +552,6 @@ public ServerProfile(String name, String serverAddress, int serverPort, boolean
|
||||||
public InetSocketAddress toSocketAddress() {
|
public InetSocketAddress toSocketAddress() {
|
||||||
return InetSocketAddress.createUnresolved(serverAddress, serverPort);
|
return InetSocketAddress.createUnresolved(serverAddress, serverPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAddress() {
|
|
||||||
return serverAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getPort() {
|
|
||||||
return serverPort;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ProfileDefaultSettings {
|
public static class ProfileDefaultSettings {
|
||||||
|
|
|
@ -79,7 +79,6 @@ public ClientProfileBuilder(ClientProfile profile) {
|
||||||
this.loadNatives = new ArrayList<>(profile.getLoadNatives());
|
this.loadNatives = new ArrayList<>(profile.getLoadNatives());
|
||||||
this.properties = new HashMap<>(profile.getProperties());
|
this.properties = new HashMap<>(profile.getProperties());
|
||||||
this.servers = new ArrayList<>(profile.getServers());
|
this.servers = new ArrayList<>(profile.getServers());
|
||||||
this.classLoaderConfig = profile.getClassLoaderConfig();
|
|
||||||
this.flags = new ArrayList<>(profile.getFlags());
|
this.flags = new ArrayList<>(profile.getFlags());
|
||||||
this.recommendJavaVersion = profile.getRecommendJavaVersion();
|
this.recommendJavaVersion = profile.getRecommendJavaVersion();
|
||||||
this.minJavaVersion = profile.getMinJavaVersion();
|
this.minJavaVersion = profile.getMinJavaVersion();
|
||||||
|
|
|
@ -88,7 +88,7 @@ public Set<OptionalAction> getEnabledActions() {
|
||||||
public void fixDependencies() {
|
public void fixDependencies() {
|
||||||
Set<OptionalFile> disabled = all.stream().filter(t -> !isEnabled(t)).collect(Collectors.toSet());
|
Set<OptionalFile> disabled = all.stream().filter(t -> !isEnabled(t)).collect(Collectors.toSet());
|
||||||
for (OptionalFile file : disabled) {
|
for (OptionalFile file : disabled) {
|
||||||
if (file.group != null && file.group.length > 0 && Arrays.stream(file.group).noneMatch(this::isEnabled)) {
|
if (file.group != null && Arrays.stream(file.group).noneMatch(this::isEnabled)) {
|
||||||
enable(file.group[0], false, null);
|
enable(file.group[0], false, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,11 +42,7 @@ public CompletableFuture<SelfUser> getCurrentUser() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<AuthResponse> auth(String login, AuthMethodPassword password) {
|
public CompletableFuture<AuthResponse> auth(String login, AuthMethodPassword password) {
|
||||||
AuthRequest.ConnectTypes connectType = AuthRequest.ConnectTypes.API;
|
return request.request(new AuthRequest(login, convertAuthPasswordAll(password), authId, false, AuthRequest.ConnectTypes.CLIENT))
|
||||||
if(Request.getExtendedTokens() != null && Request.getExtendedTokens().get("launcher") != null) {
|
|
||||||
connectType = AuthRequest.ConnectTypes.CLIENT;
|
|
||||||
}
|
|
||||||
return request.request(new AuthRequest(login, convertAuthPasswordAll(password), authId, false, connectType))
|
|
||||||
.thenApply(response -> new AuthResponse(response.makeUserInfo(), response.oauth));
|
.thenApply(response -> new AuthResponse(response.makeUserInfo(), response.oauth));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
compileOnly group: 'org.jline', name: 'jline', version: rootProject['verJline']
|
compileOnly group: 'org.jline', name: 'jline', version: rootProject['verJline']
|
||||||
compileOnly group: 'org.jline', name: 'jline-reader', version: rootProject['verJline']
|
compileOnly group: 'org.jline', name: 'jline-reader', version: rootProject['verJline']
|
||||||
compileOnly group: 'org.jline', name: 'jline-terminal', version: rootProject['verJline']
|
compileOnly group: 'org.jline', name: 'jline-terminal', version: rootProject['verJline']
|
||||||
|
compileOnly group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: rootProject['verBcprov']
|
||||||
compileOnly group: 'org.slf4j', name: 'slf4j-api', version: rootProject['verSlf4j']
|
compileOnly group: 'org.slf4j', name: 'slf4j-api', version: rootProject['verSlf4j']
|
||||||
api group: 'com.google.code.gson', name: 'gson', version: rootProject['verGson']
|
api group: 'com.google.code.gson', name: 'gson', version: rootProject['verGson']
|
||||||
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter', version: rootProject['verJunit']
|
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter', version: rootProject['verJunit']
|
||||||
|
|
|
@ -23,12 +23,6 @@ interface ClientProfile {
|
||||||
List<OptionalMod> getOptionalMods();
|
List<OptionalMod> getOptionalMods();
|
||||||
String getProperty(String name);
|
String getProperty(String name);
|
||||||
Map<String, String> getProperties();
|
Map<String, String> getProperties();
|
||||||
ServerInfo getServer();
|
|
||||||
|
|
||||||
interface ServerInfo {
|
|
||||||
String getAddress();
|
|
||||||
int getPort();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface OptionalMod {
|
interface OptionalMod {
|
||||||
|
|
|
@ -28,7 +28,6 @@ public interface LauncherBackendAPI {
|
||||||
// Tools
|
// Tools
|
||||||
CompletableFuture<byte[]> fetchTexture(Texture texture);
|
CompletableFuture<byte[]> fetchTexture(Texture texture);
|
||||||
CompletableFuture<List<Java>> getAvailableJava();
|
CompletableFuture<List<Java>> getAvailableJava();
|
||||||
CompletableFuture<ServerPingInfo> pingServer(ProfileFeatureAPI.ClientProfile profile);
|
|
||||||
// Settings
|
// Settings
|
||||||
void registerUserSettings(String name, Class<? extends UserSettings> clazz);
|
void registerUserSettings(String name, Class<? extends UserSettings> clazz);
|
||||||
UserSettings getUserSettings(String name, Function<String, UserSettings> ifNotExist);
|
UserSettings getUserSettings(String name, Function<String, UserSettings> ifNotExist);
|
||||||
|
@ -37,7 +36,6 @@ public interface LauncherBackendAPI {
|
||||||
boolean hasPermission(String permission);
|
boolean hasPermission(String permission);
|
||||||
String getUsername();
|
String getUsername();
|
||||||
SelfUser getSelfUser();
|
SelfUser getSelfUser();
|
||||||
boolean isTestMode();
|
|
||||||
// Extensions
|
// Extensions
|
||||||
<T extends Extension> T getExtension(Class<T> clazz);
|
<T extends Extension> T getExtension(Class<T> clazz);
|
||||||
void shutdown();
|
void shutdown();
|
||||||
|
@ -165,10 +163,4 @@ interface Java {
|
||||||
int getMajorVersion();
|
int getMajorVersion();
|
||||||
Path getPath();
|
Path getPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ServerPingInfo {
|
|
||||||
int getMaxOnline();
|
|
||||||
int getOnline();
|
|
||||||
List<String> getPlayerNames();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,10 +54,6 @@ private class LegacyClassLoader extends URLClassLoader {
|
||||||
private final Map<String, Class<?>> classMap = new ConcurrentHashMap<>();
|
private final Map<String, Class<?>> classMap = new ConcurrentHashMap<>();
|
||||||
private String nativePath;
|
private String nativePath;
|
||||||
|
|
||||||
static {
|
|
||||||
ClassLoader.registerAsParallelCapable();
|
|
||||||
}
|
|
||||||
|
|
||||||
private final List<String> packages = new ArrayList<>();
|
private final List<String> packages = new ArrayList<>();
|
||||||
public LegacyClassLoader(URL[] urls) {
|
public LegacyClassLoader(URL[] urls) {
|
||||||
super(urls);
|
super(urls);
|
||||||
|
|
|
@ -164,11 +164,6 @@ private class ModuleClassLoader extends URLClassLoader {
|
||||||
private String nativePath;
|
private String nativePath;
|
||||||
|
|
||||||
private final List<String> packages = new ArrayList<>();
|
private final List<String> packages = new ArrayList<>();
|
||||||
|
|
||||||
static {
|
|
||||||
ClassLoader.registerAsParallelCapable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ModuleClassLoader(URL[] urls, ClassLoader parent) {
|
public ModuleClassLoader(URL[] urls, ClassLoader parent) {
|
||||||
super("LAUNCHER", urls, parent);
|
super("LAUNCHER", urls, parent);
|
||||||
packages.add("pro.gravit.launcher.");
|
packages.add("pro.gravit.launcher.");
|
||||||
|
|
2
modules
2
modules
|
@ -1 +1 @@
|
||||||
Subproject commit c5087d40c9dd5b065fccedeac21afb967a25e112
|
Subproject commit a52b9cc8552445167b95e8933f4289bbaa70677d
|
|
@ -1,16 +1,18 @@
|
||||||
project.ext {
|
project.ext {
|
||||||
verAsm = '9.7'
|
verAsm = '9.7'
|
||||||
verNetty = '4.1.111.Final'
|
verNetty = '4.1.110.Final'
|
||||||
verOshiCore = '6.6.1'
|
verOshiCore = '6.6.1'
|
||||||
verJunit = '5.10.2'
|
verJunit = '5.10.2'
|
||||||
|
verGuavaC = '30.1.1-jre'
|
||||||
verJansi = '2.4.1'
|
verJansi = '2.4.1'
|
||||||
verJline = '3.26.1'
|
verJline = '3.26.1'
|
||||||
verJwt = '0.12.5'
|
verJwt = '0.12.5'
|
||||||
|
verBcprov = '1.70'
|
||||||
verGson = '2.11.0'
|
verGson = '2.11.0'
|
||||||
verBcpkix = '1.78.1'
|
verBcpkix = '1.78.1'
|
||||||
verSlf4j = '2.0.13'
|
verSlf4j = '2.0.13'
|
||||||
verLog4j = '2.23.1'
|
verLog4j = '2.23.1'
|
||||||
verMySQLConn = '9.0.0'
|
verMySQLConn = '8.4.0'
|
||||||
verMariaDBConn = '3.4.0'
|
verMariaDBConn = '3.4.0'
|
||||||
verPostgreSQLConn = '42.7.3'
|
verPostgreSQLConn = '42.7.3'
|
||||||
verH2Conn = '2.2.224'
|
verH2Conn = '2.2.224'
|
||||||
|
|
Loading…
Reference in a new issue