Run IRC socket I/O on a dedicated background thread
Some checks failed
continuous-integration/drone/push Build is failing

Auto-connect on CLIENT_STARTED, .irc reconnect and .irc <msg> all used
to open a TCP socket on the render thread with a 5s connect timeout,
freezing client startup and chat input when the server was unreachable.
Dispatch those paths through a single daemon executor instead, and
release the socket plus the executor on CLIENT_STOPPING.
This commit is contained in:
2026-06-21 15:40:02 +06:00
parent 153d85602c
commit 77a44be34b

View File

@@ -11,12 +11,21 @@ import net.minecraft.network.chat.Component;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public final class ClientIrcMod implements ClientModInitializer { public final class ClientIrcMod implements ClientModInitializer {
public static final String MOD_ID = "clientirc"; public static final String MOD_ID = "clientirc";
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
private static final String COMMAND_PREFIX = ".irc"; private static final String COMMAND_PREFIX = ".irc";
private static final ExecutorService IO_EXECUTOR = Executors.newSingleThreadExecutor(runnable -> {
Thread thread = new Thread(runnable, "clientirc-io");
thread.setDaemon(true);
return thread;
});
private static IrcConfig config; private static IrcConfig config;
private static IrcService service; private static IrcService service;
@@ -27,10 +36,16 @@ public final class ClientIrcMod implements ClientModInitializer {
ClientLifecycleEvents.CLIENT_STARTED.register(client -> { ClientLifecycleEvents.CLIENT_STARTED.register(client -> {
if (config.autoConnect) { if (config.autoConnect) {
service.connect(resolvePlayerName(client)); String playerName = resolvePlayerName(client);
IO_EXECUTOR.execute(() -> service.connect(playerName));
} }
}); });
ClientLifecycleEvents.CLIENT_STOPPING.register(client -> {
service.disconnect();
IO_EXECUTOR.shutdownNow();
});
ClientTickEvents.END_CLIENT_TICK.register(client -> { ClientTickEvents.END_CLIENT_TICK.register(client -> {
IrcService.DisplayLine line; IrcService.DisplayLine line;
while ((line = service.pollLine()) != null) { while ((line = service.pollLine()) != null) {
@@ -63,9 +78,12 @@ public final class ClientIrcMod implements ClientModInitializer {
} }
if ("reconnect".equalsIgnoreCase(argument)) { if ("reconnect".equalsIgnoreCase(argument)) {
boolean connected = service.reconnect(resolvePlayerName(client)); String playerName = resolvePlayerName(client);
ChatFormatting color = connected ? ChatFormatting.GREEN : ChatFormatting.RED; IO_EXECUTOR.execute(() -> {
pushClientChat(client, Component.literal("[IRC] reconnect " + (connected ? "ok" : "failed")).withStyle(color)); boolean connected = service.reconnect(playerName);
ChatFormatting color = connected ? ChatFormatting.GREEN : ChatFormatting.RED;
pushClientChat(client, Component.literal("[IRC] reconnect " + (connected ? "ok" : "failed")).withStyle(color));
});
return true; return true;
} }
@@ -76,15 +94,16 @@ public final class ClientIrcMod implements ClientModInitializer {
return true; return true;
} }
if (!service.ensureConnected(resolvePlayerName(client))) { String playerName = resolvePlayerName(client);
pushClientChat(client, Component.literal("[IRC] server is offline or config is wrong").withStyle(ChatFormatting.RED)); IO_EXECUTOR.execute(() -> {
return true; if (!service.ensureConnected(playerName)) {
} pushClientChat(client, Component.literal("[IRC] server is offline or config is wrong").withStyle(ChatFormatting.RED));
return;
boolean sent = service.sendChat(resolvePlayerName(client), argument); }
if (!sent) { if (!service.sendChat(playerName, argument)) {
pushClientChat(client, Component.literal("[IRC] send failed").withStyle(ChatFormatting.RED)); pushClientChat(client, Component.literal("[IRC] send failed").withStyle(ChatFormatting.RED));
} }
});
return true; return true;
} }