mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-12-22 16:41:46 +03:00
[FEATURE] Support virtual threads and client locks
This commit is contained in:
parent
34ac6a0f28
commit
7060697bad
21 changed files with 222 additions and 144 deletions
|
@ -422,21 +422,6 @@ public void syncUpdatesDir(Collection<String> dirs) throws IOException {
|
|||
updatesManager.syncUpdatesDir(dirs);
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
ProcessBuilder builder = new ProcessBuilder();
|
||||
if (config.startScript != null) builder.command(Collections.singletonList(config.startScript));
|
||||
else throw new IllegalArgumentException("Please create start script and link it as startScript in config.");
|
||||
builder.directory(this.dir.toFile());
|
||||
builder.inheritIO();
|
||||
builder.redirectErrorStream(true);
|
||||
builder.redirectOutput(Redirect.PIPE);
|
||||
try {
|
||||
builder.start();
|
||||
} catch (IOException e) {
|
||||
logger.error("Restart failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerObject(String name, Object object) {
|
||||
if (object instanceof Reconfigurable) {
|
||||
reconfigurableManager.registerReconfigurable(name, (Reconfigurable) object);
|
||||
|
@ -449,11 +434,6 @@ public void unregisterObject(String name, Object object) {
|
|||
}
|
||||
}
|
||||
|
||||
public void fullyRestart() {
|
||||
restart();
|
||||
JVMHelper.RUNTIME.exit(0);
|
||||
}
|
||||
|
||||
|
||||
public enum ReloadType {
|
||||
NO_AUTH,
|
||||
|
|
|
@ -63,27 +63,7 @@ public LaunchServerBuilder setLaunchServerConfigManager(LaunchServer.LaunchServe
|
|||
public LaunchServer build() throws Exception {
|
||||
directories.collect();
|
||||
if (launchServerConfigManager == null) {
|
||||
launchServerConfigManager = new LaunchServer.LaunchServerConfigManager() {
|
||||
@Override
|
||||
public LaunchServerConfig readConfig() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LaunchServerRuntimeConfig readRuntimeConfig() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeConfig(LaunchServerConfig config) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeRuntimeConfig(LaunchServerRuntimeConfig config) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
launchServerConfigManager = new NullLaunchServerConfigManager();
|
||||
}
|
||||
if (keyAgreementManager == null) {
|
||||
keyAgreementManager = new KeyAgreementManager(directories.keyDirectory);
|
||||
|
@ -99,4 +79,26 @@ public LaunchServerBuilder setCertificateManager(CertificateManager certificateM
|
|||
public void setKeyAgreementManager(KeyAgreementManager keyAgreementManager) {
|
||||
this.keyAgreementManager = keyAgreementManager;
|
||||
}
|
||||
|
||||
private static class NullLaunchServerConfigManager implements LaunchServer.LaunchServerConfigManager {
|
||||
@Override
|
||||
public LaunchServerConfig readConfig() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LaunchServerRuntimeConfig readRuntimeConfig() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeConfig(LaunchServerConfig config) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeRuntimeConfig(LaunchServerRuntimeConfig config) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,57 +122,7 @@ public static void main(String[] args) throws Exception {
|
|||
}
|
||||
}
|
||||
|
||||
LaunchServer.LaunchServerConfigManager launchServerConfigManager = new LaunchServer.LaunchServerConfigManager() {
|
||||
@Override
|
||||
public LaunchServerConfig readConfig() throws IOException {
|
||||
LaunchServerConfig config1;
|
||||
try (BufferedReader reader = IOHelper.newReader(configFile)) {
|
||||
config1 = Launcher.gsonManager.gson.fromJson(reader, LaunchServerConfig.class);
|
||||
}
|
||||
return config1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LaunchServerRuntimeConfig readRuntimeConfig() throws IOException {
|
||||
LaunchServerRuntimeConfig config1;
|
||||
try (BufferedReader reader = IOHelper.newReader(runtimeConfigFile)) {
|
||||
config1 = Launcher.gsonManager.gson.fromJson(reader, LaunchServerRuntimeConfig.class);
|
||||
}
|
||||
return config1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeConfig(LaunchServerConfig config) throws IOException {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
try (Writer writer = IOHelper.newWriter(output)) {
|
||||
if (Launcher.gsonManager.configGson != null) {
|
||||
Launcher.gsonManager.configGson.toJson(config, writer);
|
||||
} else {
|
||||
logger.error("Error writing LaunchServer config file. Gson is null");
|
||||
}
|
||||
}
|
||||
byte[] bytes = output.toByteArray();
|
||||
if(bytes.length > 0) {
|
||||
IOHelper.write(configFile, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeRuntimeConfig(LaunchServerRuntimeConfig config) throws IOException {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
try (Writer writer = IOHelper.newWriter(output)) {
|
||||
if (Launcher.gsonManager.configGson != null) {
|
||||
Launcher.gsonManager.configGson.toJson(config, writer);
|
||||
} else {
|
||||
logger.error("Error writing LaunchServer runtime config file. Gson is null");
|
||||
}
|
||||
}
|
||||
byte[] bytes = output.toByteArray();
|
||||
if(bytes.length > 0) {
|
||||
IOHelper.write(runtimeConfigFile, bytes);
|
||||
}
|
||||
}
|
||||
};
|
||||
LaunchServer.LaunchServerConfigManager launchServerConfigManager = new BasicLaunchServerConfigManager(configFile, runtimeConfigFile);
|
||||
LaunchServer.LaunchServerDirectories directories = new LaunchServer.LaunchServerDirectories();
|
||||
directories.dir = dir;
|
||||
LaunchServer server = new LaunchServerBuilder()
|
||||
|
@ -284,4 +234,64 @@ public static void generateConfigIfNotExists(Path configFile, CommandHandler com
|
|||
Launcher.gsonManager.configGson.toJson(newConfig, writer);
|
||||
}
|
||||
}
|
||||
|
||||
private static class BasicLaunchServerConfigManager implements LaunchServer.LaunchServerConfigManager {
|
||||
private final Path configFile;
|
||||
private final Path runtimeConfigFile;
|
||||
|
||||
public BasicLaunchServerConfigManager(Path configFile, Path runtimeConfigFile) {
|
||||
this.configFile = configFile;
|
||||
this.runtimeConfigFile = runtimeConfigFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LaunchServerConfig readConfig() throws IOException {
|
||||
LaunchServerConfig config1;
|
||||
try (BufferedReader reader = IOHelper.newReader(configFile)) {
|
||||
config1 = Launcher.gsonManager.gson.fromJson(reader, LaunchServerConfig.class);
|
||||
}
|
||||
return config1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LaunchServerRuntimeConfig readRuntimeConfig() throws IOException {
|
||||
LaunchServerRuntimeConfig config1;
|
||||
try (BufferedReader reader = IOHelper.newReader(runtimeConfigFile)) {
|
||||
config1 = Launcher.gsonManager.gson.fromJson(reader, LaunchServerRuntimeConfig.class);
|
||||
}
|
||||
return config1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeConfig(LaunchServerConfig config) throws IOException {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
try (Writer writer = IOHelper.newWriter(output)) {
|
||||
if (Launcher.gsonManager.configGson != null) {
|
||||
Launcher.gsonManager.configGson.toJson(config, writer);
|
||||
} else {
|
||||
logger.error("Error writing LaunchServer config file. Gson is null");
|
||||
}
|
||||
}
|
||||
byte[] bytes = output.toByteArray();
|
||||
if(bytes.length > 0) {
|
||||
IOHelper.write(configFile, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeRuntimeConfig(LaunchServerRuntimeConfig config) throws IOException {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
try (Writer writer = IOHelper.newWriter(output)) {
|
||||
if (Launcher.gsonManager.configGson != null) {
|
||||
Launcher.gsonManager.configGson.toJson(config, writer);
|
||||
} else {
|
||||
logger.error("Error writing LaunchServer runtime config file. Gson is null");
|
||||
}
|
||||
}
|
||||
byte[] bytes = output.toByteArray();
|
||||
if(bytes.length > 0) {
|
||||
IOHelper.write(runtimeConfigFile, bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,9 @@ protected boolean showApplyDialog(String text) throws IOException {
|
|||
protected Downloader downloadWithProgressBar(String taskName, List<Downloader.SizedFile> list, String baseUrl, Path targetDir) throws Exception {
|
||||
long total = 0;
|
||||
for (Downloader.SizedFile file : list) {
|
||||
if(file.size < 0) {
|
||||
continue;
|
||||
}
|
||||
total += file.size;
|
||||
}
|
||||
long totalFiles = list.size();
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
package pro.gravit.launchserver.command.basic;
|
||||
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
|
||||
public final class RestartCommand extends Command {
|
||||
public RestartCommand(LaunchServer server) {
|
||||
super(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgsDescription() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsageDescription() {
|
||||
return "Restart LaunchServer";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(String... args) {
|
||||
server.fullyRestart();
|
||||
}
|
||||
}
|
|
@ -6,6 +6,9 @@
|
|||
import pro.gravit.launchserver.command.modules.LoadModuleCommand;
|
||||
import pro.gravit.launchserver.command.modules.ModulesCommand;
|
||||
import pro.gravit.launchserver.command.service.*;
|
||||
import pro.gravit.launchserver.command.sync.*;
|
||||
import pro.gravit.launchserver.command.tools.SignDirCommand;
|
||||
import pro.gravit.launchserver.command.tools.SignJarCommand;
|
||||
import pro.gravit.utils.command.BaseCommandCategory;
|
||||
import pro.gravit.utils.command.basic.ClearCommand;
|
||||
import pro.gravit.utils.command.basic.GCCommand;
|
||||
|
@ -19,7 +22,6 @@ public static void registerCommands(pro.gravit.utils.command.CommandHandler hand
|
|||
basic.registerCommand("version", new VersionCommand(server));
|
||||
basic.registerCommand("build", new BuildCommand(server));
|
||||
basic.registerCommand("stop", new StopCommand(server));
|
||||
basic.registerCommand("restart", new RestartCommand(server));
|
||||
basic.registerCommand("debug", new DebugCommand(server));
|
||||
basic.registerCommand("clear", new ClearCommand(handler));
|
||||
basic.registerCommand("gc", new GCCommand());
|
||||
|
@ -34,10 +36,7 @@ public static void registerCommands(pro.gravit.utils.command.CommandHandler hand
|
|||
updates.registerCommand("unindexAsset", new UnindexAssetCommand(server));
|
||||
updates.registerCommand("downloadAsset", new DownloadAssetCommand(server));
|
||||
updates.registerCommand("downloadClient", new DownloadClientCommand(server));
|
||||
updates.registerCommand("syncBinaries", new SyncBinariesCommand(server));
|
||||
updates.registerCommand("syncUpdates", new SyncUpdatesCommand(server));
|
||||
updates.registerCommand("syncProfiles", new SyncProfilesCommand(server));
|
||||
updates.registerCommand("syncUP", new SyncUPCommand(server));
|
||||
updates.registerCommand("sync", new SyncCommand(server));
|
||||
updates.registerCommand("saveProfiles", new SaveProfilesCommand(server));
|
||||
updates.registerCommand("makeProfile", new MakeProfileCommand(server));
|
||||
Category updatesCategory = new Category(updates, "updates", "Update and Sync Management");
|
||||
|
@ -50,11 +49,16 @@ public static void registerCommands(pro.gravit.utils.command.CommandHandler hand
|
|||
service.registerCommand("notify", new NotifyCommand(server));
|
||||
service.registerCommand("component", new ComponentCommand(server));
|
||||
service.registerCommand("clients", new ClientsCommand(server));
|
||||
service.registerCommand("signJar", new SignJarCommand(server));
|
||||
service.registerCommand("signDir", new SignDirCommand(server));
|
||||
service.registerCommand("securitycheck", new SecurityCheckCommand(server));
|
||||
service.registerCommand("token", new TokenCommand(server));
|
||||
Category serviceCategory = new Category(service, "service", "Managing LaunchServer Components");
|
||||
handler.registerCategory(serviceCategory);
|
||||
|
||||
//Register tools commands
|
||||
BaseCommandCategory tools = new BaseCommandCategory();
|
||||
tools.registerCommand("signJar", new SignJarCommand(server));
|
||||
tools.registerCommand("signDir", new SignDirCommand(server));
|
||||
Category toolsCategory = new Category(tools, "tools", "Other tools");
|
||||
handler.registerCategory(toolsCategory);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package pro.gravit.launchserver.command.hash;
|
||||
package pro.gravit.launchserver.command.sync;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
|
@ -0,0 +1,30 @@
|
|||
package pro.gravit.launchserver.command.sync;
|
||||
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
|
||||
public class SyncCommand extends Command {
|
||||
public SyncCommand(LaunchServer server) {
|
||||
super(server);
|
||||
this.childCommands.put("profiles", new SyncProfilesCommand(server));
|
||||
this.childCommands.put("binaries", new SyncBinariesCommand(server));
|
||||
this.childCommands.put("updates", new SyncUpdatesCommand(server));
|
||||
this.childCommands.put("up", new SyncUPCommand(server));
|
||||
this.childCommands.put("launchermodules", new SyncLauncherModulesCommand(server));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgsDescription() {
|
||||
return "[updates/profiles/up/binaries/launchermodules] [args...]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsageDescription() {
|
||||
return "sync specified objects";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
invokeSubcommands(args);
|
||||
}
|
||||
}
|
|
@ -1,31 +1,31 @@
|
|||
package pro.gravit.launchserver.launchermodules;
|
||||
package pro.gravit.launchserver.command.sync;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.utils.command.Command;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
|
||||
public class SyncLauncherModulesCommand extends Command {
|
||||
private final LauncherModuleLoader mod;
|
||||
private transient final Logger logger = LogManager.getLogger();
|
||||
|
||||
public SyncLauncherModulesCommand(LauncherModuleLoader mod) {
|
||||
this.mod = mod;
|
||||
public SyncLauncherModulesCommand(LaunchServer server) {
|
||||
super(server);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getArgsDescription() {
|
||||
return "Resync launcher modules";
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsageDescription() {
|
||||
return "[]";
|
||||
return "Resync launcher modules";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
mod.syncModules();
|
||||
server.launcherModuleLoader.syncModules();
|
||||
logger.info("Launcher Modules synced");
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package pro.gravit.launchserver.command.hash;
|
||||
package pro.gravit.launchserver.command.sync;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
|
@ -1,4 +1,4 @@
|
|||
package pro.gravit.launchserver.command.hash;
|
||||
package pro.gravit.launchserver.command.sync;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
|
@ -1,4 +1,4 @@
|
|||
package pro.gravit.launchserver.command.hash;
|
||||
package pro.gravit.launchserver.command.sync;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
|
@ -1,4 +1,4 @@
|
|||
package pro.gravit.launchserver.command.service;
|
||||
package pro.gravit.launchserver.command.tools;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
|
@ -1,4 +1,4 @@
|
|||
package pro.gravit.launchserver.command.service;
|
||||
package pro.gravit.launchserver.command.tools;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
|
@ -41,7 +41,6 @@ public final class LaunchServerConfig {
|
|||
public NettyConfig netty;
|
||||
public LauncherConf launcher;
|
||||
public JarSignerConf sign;
|
||||
public String startScript;
|
||||
private transient LaunchServer server = null;
|
||||
private transient AuthProviderPair authDefault;
|
||||
|
||||
|
@ -49,7 +48,6 @@ public static LaunchServerConfig getDefault(LaunchServer.LaunchServerEnv env) {
|
|||
LaunchServerConfig newConfig = new LaunchServerConfig();
|
||||
newConfig.mirrors = new String[]{"https://mirror.gravitlauncher.com/5.6.x/", "https://gravit-launcher-mirror.storage.googleapis.com/"};
|
||||
newConfig.env = LauncherConfig.LauncherEnvironment.STD;
|
||||
newConfig.startScript = JVMHelper.OS_TYPE.equals(JVMHelper.OS.MUSTDIE) ? "." + File.separator + "start.bat" : "." + File.separator + "start.sh";
|
||||
newConfig.auth = new HashMap<>();
|
||||
AuthProviderPair a = new AuthProviderPair(new RejectAuthCoreProvider(),
|
||||
new RequestTextureProvider("http://example.com/skins/%username%.png", "http://example.com/cloaks/%username%.png")
|
||||
|
@ -263,6 +261,12 @@ public static class NettyPerformanceConfig {
|
|||
public int workerThread;
|
||||
public int schedulerThread;
|
||||
public int maxWebSocketRequestBytes = 1024 * 1024;
|
||||
public boolean disableThreadSafeClientObject;
|
||||
public NettyExecutorType executorType = NettyExecutorType.VIRTUAL_THREADS;
|
||||
|
||||
public enum NettyExecutorType {
|
||||
NONE, DEFAULT, WORK_STEAL, VIRTUAL_THREADS
|
||||
}
|
||||
}
|
||||
|
||||
public static class NettyBindAddress {
|
||||
|
|
|
@ -44,7 +44,6 @@ public void init() {
|
|||
logger.error(e);
|
||||
}
|
||||
}
|
||||
server.commandHandler.registerCommand("syncLauncherModules", new SyncLauncherModulesCommand(this));
|
||||
MainBuildTask mainTask = server.launcherBinary.getTaskByClass(MainBuildTask.class).get();
|
||||
mainTask.preBuildHook.registerHook((buildContext) -> {
|
||||
for (ModuleEntity e : launcherModules) {
|
||||
|
|
|
@ -10,8 +10,11 @@
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
public class Client {
|
||||
ReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
public String auth_id;
|
||||
public long timestamp;
|
||||
public AuthResponse.ConnectTypes type;
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
public class WebSocketService {
|
||||
|
@ -51,11 +53,18 @@ public class WebSocketService {
|
|||
private final LaunchServer server;
|
||||
private final Gson gson;
|
||||
private transient final Logger logger = LogManager.getLogger();
|
||||
private ExecutorService executors;
|
||||
|
||||
public WebSocketService(ChannelGroup channels, LaunchServer server) {
|
||||
this.channels = channels;
|
||||
this.server = server;
|
||||
this.gson = Launcher.gsonManager.gson;
|
||||
executors = switch (server.config.netty.performance.executorType) {
|
||||
case NONE -> null;
|
||||
case DEFAULT -> Executors.newCachedThreadPool();
|
||||
case WORK_STEAL -> Executors.newWorkStealingPool();
|
||||
case VIRTUAL_THREADS -> Executors.newVirtualThreadPerTaskExecutor();
|
||||
};
|
||||
}
|
||||
|
||||
public static void registerResponses() {
|
||||
|
@ -126,7 +135,41 @@ public void process(ChannelHandlerContext ctx, TextWebSocketFrame frame, Client
|
|||
sendObject(ctx.channel(), event, WebSocketEvent.class);
|
||||
return;
|
||||
}
|
||||
process(context, response, client, ip);
|
||||
var safeStatus = server.config.netty.performance.disableThreadSafeClientObject ?
|
||||
WebSocketServerResponse.ThreadSafeStatus.NONE : response.getThreadSafeStatus();
|
||||
if(executors == null) {
|
||||
process(safeStatus, client, ip, context, response);
|
||||
} else {
|
||||
executors.submit(() -> {
|
||||
process(safeStatus, client, ip, context, response);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void process(WebSocketServerResponse.ThreadSafeStatus safeStatus, Client client, String ip, WebSocketRequestContext context, WebSocketServerResponse response) {
|
||||
switch (safeStatus) {
|
||||
case NONE -> {
|
||||
process(context, response, client, ip);
|
||||
}
|
||||
case READ -> {
|
||||
var lock = client.lock.readLock();
|
||||
lock.lock();
|
||||
try {
|
||||
process(context, response, client, ip);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
case READ_WRITE -> {
|
||||
var lock = client.lock.writeLock();
|
||||
lock.lock();
|
||||
try {
|
||||
process(context, response, client, ip);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void process(WebSocketRequestContext context, WebSocketServerResponse response, Client client, String ip) {
|
||||
|
|
|
@ -8,4 +8,12 @@ public interface WebSocketServerResponse extends WebSocketRequest {
|
|||
String getType();
|
||||
|
||||
void execute(ChannelHandlerContext ctx, Client client) throws Exception;
|
||||
|
||||
default ThreadSafeStatus getThreadSafeStatus() {
|
||||
return ThreadSafeStatus.READ;
|
||||
}
|
||||
|
||||
enum ThreadSafeStatus {
|
||||
NONE, READ, READ_WRITE
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"features": ["nojava8support"],
|
||||
"info": ["Java below 17 not supported"]
|
||||
"features": [],
|
||||
"info": []
|
||||
}
|
|
@ -21,6 +21,7 @@
|
|||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
|
@ -159,6 +160,16 @@ public CompletableFuture<Void> downloadFile(URI uri, Path path) {
|
|||
});
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> downloadFile(String url, Path path, DownloadCallback callback, ExecutorService executor) throws Exception {
|
||||
return downloadFiles(new ArrayList<>(List.of(new SizedFile(url, path.getFileName().toString()))), null,
|
||||
path.getParent(), callback, executor, 1);
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> downloadFile(String url, Path path, long size, DownloadCallback callback, ExecutorService executor) throws Exception {
|
||||
return downloadFiles(new ArrayList<>(List.of(new SizedFile(url, path.getFileName().toString(), size))), null,
|
||||
path.getParent(), callback, executor, 1);
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> downloadFiles(List<SizedFile> files, String baseURL, Path targetDir, DownloadCallback callback, ExecutorService executor, int threads) throws Exception {
|
||||
// URI scheme
|
||||
URI baseUri = baseURL == null ? null : new URI(baseURL);
|
||||
|
@ -355,5 +366,11 @@ public SizedFile(String urlPath, String filePath, long size) {
|
|||
this.filePath = filePath;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public SizedFile(String urlPath, String filePath) {
|
||||
this.urlPath = urlPath;
|
||||
this.filePath = filePath;
|
||||
this.size = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue