2025-09-24 22:02:10 +02:00
|
|
|
package org.openautonomousconnection.protocol;
|
2025-09-19 21:27:35 +02:00
|
|
|
|
2026-02-01 17:13:33 +01:00
|
|
|
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.ClientAuthMode;
|
2025-09-25 23:41:17 +02:00
|
|
|
import dev.unlegitdqrk.unlegitlibrary.utils.Logger;
|
|
|
|
|
import lombok.Getter;
|
|
|
|
|
import lombok.Setter;
|
2025-09-29 13:18:15 +02:00
|
|
|
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
|
2025-09-24 22:02:10 +02:00
|
|
|
import org.openautonomousconnection.protocol.listeners.ClientListener;
|
2026-01-18 18:17:35 +01:00
|
|
|
import org.openautonomousconnection.protocol.listeners.CustomServerListener;
|
2025-09-24 22:02:10 +02:00
|
|
|
import org.openautonomousconnection.protocol.packets.OACPacket;
|
2026-01-18 18:17:35 +01:00
|
|
|
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.AuthPacket;
|
|
|
|
|
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.INSQueryPacket;
|
|
|
|
|
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.INSResponsePacket;
|
|
|
|
|
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.web.WebRequestPacket;
|
|
|
|
|
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.web.WebResponsePacket;
|
|
|
|
|
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.web.stream.WebStreamChunkPacket;
|
|
|
|
|
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.web.stream.WebStreamEndPacket;
|
|
|
|
|
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.web.stream.WebStreamStartPacket;
|
2025-09-24 22:02:10 +02:00
|
|
|
import org.openautonomousconnection.protocol.side.client.ProtocolClient;
|
2025-12-08 09:59:58 +01:00
|
|
|
import org.openautonomousconnection.protocol.side.ins.ProtocolINSServer;
|
2026-01-18 18:17:35 +01:00
|
|
|
import org.openautonomousconnection.protocol.side.server.ProtocolCustomServer;
|
2025-09-25 23:40:24 +02:00
|
|
|
import org.openautonomousconnection.protocol.side.web.ProtocolWebServer;
|
2025-09-24 22:02:10 +02:00
|
|
|
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
2025-09-19 21:27:35 +02:00
|
|
|
|
|
|
|
|
import java.io.File;
|
|
|
|
|
import java.io.IOException;
|
2025-10-04 00:04:33 +02:00
|
|
|
import java.net.Proxy;
|
2025-09-19 21:27:35 +02:00
|
|
|
|
2025-09-29 17:46:30 +02:00
|
|
|
/**
|
|
|
|
|
* The main bridge class for the protocol connection.
|
|
|
|
|
* It manages the protocol settings, version, and side instances.
|
|
|
|
|
*/
|
2025-09-29 17:56:51 +02:00
|
|
|
public final class ProtocolBridge {
|
2025-09-29 17:46:30 +02:00
|
|
|
/**
|
|
|
|
|
* The protocol settings for the current connection
|
|
|
|
|
*/
|
2025-09-19 21:27:35 +02:00
|
|
|
@Getter
|
2026-01-18 21:48:43 +01:00
|
|
|
private final ProtocolValues protocolValues;
|
2025-09-29 17:46:30 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The protocol version for the current connection
|
|
|
|
|
*/
|
2025-09-19 21:27:35 +02:00
|
|
|
@Getter
|
|
|
|
|
private final ProtocolVersion protocolVersion;
|
2025-09-29 17:46:30 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The logger instance for logging events and errors
|
|
|
|
|
*/
|
2025-09-20 20:42:58 +02:00
|
|
|
@Getter
|
2025-09-29 17:46:30 +02:00
|
|
|
private Logger logger;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The protocol side instances
|
|
|
|
|
*/
|
2025-09-19 21:27:35 +02:00
|
|
|
@Getter
|
|
|
|
|
private ProtocolClient protocolClient;
|
2025-09-29 17:46:30 +02:00
|
|
|
|
2026-01-18 18:17:35 +01:00
|
|
|
|
2025-09-29 17:46:30 +02:00
|
|
|
/**
|
|
|
|
|
* The protocol side instances
|
|
|
|
|
*/
|
2025-09-19 21:27:35 +02:00
|
|
|
@Getter
|
2026-01-18 18:17:35 +01:00
|
|
|
private ProtocolCustomServer protocolServer;
|
2025-09-29 17:46:30 +02:00
|
|
|
|
2025-10-04 00:04:33 +02:00
|
|
|
/**
|
|
|
|
|
* The proxy for client side
|
|
|
|
|
*/
|
|
|
|
|
@Getter
|
|
|
|
|
@Setter
|
|
|
|
|
private Proxy proxy;
|
|
|
|
|
|
2025-09-29 17:46:30 +02:00
|
|
|
/**
|
2026-01-18 18:17:35 +01:00
|
|
|
* Initialize the ProtocolBridge instance for the client side
|
2025-09-29 18:46:31 +02:00
|
|
|
*
|
2026-01-18 18:17:35 +01:00
|
|
|
* @param protocolServer The ProtocolCustomServer instance
|
2026-01-18 21:48:43 +01:00
|
|
|
* @param protocolValues The ProtocolSettings instance
|
2026-01-18 18:17:35 +01:00
|
|
|
* @param protocolVersion The ProtocolVersion instance
|
|
|
|
|
* @param logFolder The folder to store the log files
|
2025-09-29 17:46:30 +02:00
|
|
|
* @throws Exception if an error occurs while initializing the ProtocolBridge
|
|
|
|
|
*/
|
2026-01-18 21:48:43 +01:00
|
|
|
public ProtocolBridge(ProtocolCustomServer protocolServer, ProtocolValues protocolValues, ProtocolVersion protocolVersion, File logFolder) throws Exception {
|
2025-09-29 17:46:30 +02:00
|
|
|
// Assign the parameters to the class fields
|
2026-01-18 18:17:35 +01:00
|
|
|
this.protocolServer = protocolServer;
|
2026-01-18 21:48:43 +01:00
|
|
|
this.protocolValues = protocolValues;
|
2025-09-29 13:18:15 +02:00
|
|
|
this.protocolVersion = protocolVersion;
|
|
|
|
|
|
2026-02-01 17:13:33 +01:00
|
|
|
if (protocolServer instanceof ProtocolINSServer) {
|
|
|
|
|
protocolServer.attachBridge(this, null, false, ClientAuthMode.NONE);
|
|
|
|
|
} else
|
|
|
|
|
protocolServer.attachBridge(this, protocolValues.keyPass, protocolValues.ssl, protocolValues.authMode);
|
|
|
|
|
|
2025-09-29 17:46:30 +02:00
|
|
|
// Initialize the logger and protocol version
|
|
|
|
|
initializeLogger(logFolder);
|
|
|
|
|
initializeProtocolVersion();
|
2025-09-19 21:27:35 +02:00
|
|
|
|
2025-09-29 17:46:30 +02:00
|
|
|
// Register the appropriate listeners and packets
|
|
|
|
|
registerListeners();
|
2025-09-20 20:41:08 +02:00
|
|
|
registerPackets();
|
2025-09-19 21:27:35 +02:00
|
|
|
}
|
|
|
|
|
|
2025-09-29 17:46:30 +02:00
|
|
|
/**
|
|
|
|
|
* Initialize the ProtocolBridge instance for the client side
|
2025-09-29 18:46:31 +02:00
|
|
|
*
|
|
|
|
|
* @param protocolClient The ProtocolClient instance
|
2026-01-18 21:48:43 +01:00
|
|
|
* @param protocolValues The ProtocolSettings instance
|
2025-09-29 18:46:31 +02:00
|
|
|
* @param protocolVersion The ProtocolVersion instance
|
|
|
|
|
* @param logFolder The folder to store the log files
|
2025-09-29 17:46:30 +02:00
|
|
|
* @throws Exception if an error occurs while initializing the ProtocolBridge
|
|
|
|
|
*/
|
2025-09-29 13:18:15 +02:00
|
|
|
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.CLIENT)
|
2026-01-18 21:48:43 +01:00
|
|
|
public ProtocolBridge(ProtocolClient protocolClient, ProtocolValues protocolValues, ProtocolVersion protocolVersion, File logFolder) throws Exception {
|
2025-09-29 17:46:30 +02:00
|
|
|
// Assign the parameters to the class fields
|
2025-09-19 21:27:35 +02:00
|
|
|
this.protocolClient = protocolClient;
|
2026-01-18 21:48:43 +01:00
|
|
|
this.protocolValues = protocolValues;
|
2025-09-19 21:27:35 +02:00
|
|
|
this.protocolVersion = protocolVersion;
|
|
|
|
|
|
2026-02-01 17:13:33 +01:00
|
|
|
protocolClient.attachBridge(this);
|
|
|
|
|
|
2025-09-29 17:46:30 +02:00
|
|
|
// Initialize the logger and protocol version
|
|
|
|
|
initializeLogger(logFolder);
|
|
|
|
|
initializeProtocolVersion();
|
2025-09-19 20:46:57 +02:00
|
|
|
|
2025-09-29 17:46:30 +02:00
|
|
|
// Register the appropriate listeners and packets
|
|
|
|
|
registerListeners();
|
2025-09-20 20:41:08 +02:00
|
|
|
registerPackets();
|
2025-09-19 21:27:35 +02:00
|
|
|
}
|
|
|
|
|
|
2025-09-29 17:46:30 +02:00
|
|
|
/**
|
|
|
|
|
* Register the appropriate packets based on the current protocol version
|
|
|
|
|
*/
|
2025-09-20 20:41:08 +02:00
|
|
|
private void registerPackets() {
|
|
|
|
|
// 1.0.0-BETA packets
|
2026-02-01 17:13:33 +01:00
|
|
|
if (isPacketSupported(new AuthPacket(this))) protocolValues.packetHandler.registerPacket(() -> new AuthPacket(this));
|
|
|
|
|
if (isPacketSupported(new INSQueryPacket())) protocolValues.packetHandler.registerPacket(INSQueryPacket::new);
|
|
|
|
|
if (isPacketSupported(new INSResponsePacket(this))) protocolValues.packetHandler.registerPacket(() -> new INSResponsePacket(this));
|
|
|
|
|
if (isPacketSupported(new WebRequestPacket())) protocolValues.packetHandler.registerPacket(WebRequestPacket::new);
|
|
|
|
|
if (isPacketSupported(new WebResponsePacket())) protocolValues.packetHandler.registerPacket(WebResponsePacket::new);
|
|
|
|
|
if (isPacketSupported(new WebStreamChunkPacket())) protocolValues.packetHandler.registerPacket(WebStreamChunkPacket::new);
|
|
|
|
|
if (isPacketSupported(new WebStreamStartPacket())) protocolValues.packetHandler.registerPacket(WebStreamStartPacket::new);
|
|
|
|
|
if (isPacketSupported(new WebStreamEndPacket())) protocolValues.packetHandler.registerPacket(WebStreamEndPacket::new);
|
2025-09-20 20:41:08 +02:00
|
|
|
}
|
|
|
|
|
|
2026-02-01 17:13:33 +01:00
|
|
|
|
2025-09-29 17:46:30 +02:00
|
|
|
/**
|
|
|
|
|
* Register the appropriate listeners based on the current side
|
2025-09-29 18:46:31 +02:00
|
|
|
*
|
2025-09-29 17:46:30 +02:00
|
|
|
* @throws Exception if an error occurs while registering the listeners
|
|
|
|
|
*/
|
|
|
|
|
private void registerListeners() throws Exception {
|
|
|
|
|
// Client Listeners
|
|
|
|
|
if (isRunningAsClient()) {
|
2026-02-01 17:13:33 +01:00
|
|
|
protocolValues.eventManager.registerListener(new ClientListener(protocolClient));
|
2026-01-18 21:48:43 +01:00
|
|
|
protocolValues.eventManager.unregisterListener(CustomServerListener.class);
|
2026-01-18 18:17:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Server Listeners
|
|
|
|
|
if (isRunningAsServer()) {
|
2026-02-01 17:13:33 +01:00
|
|
|
protocolValues.eventManager.registerListener(new CustomServerListener(protocolServer));
|
2026-01-18 21:48:43 +01:00
|
|
|
protocolValues.eventManager.unregisterListener(ClientListener.class);
|
2025-09-29 17:46:30 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Initialize the logger instance
|
2025-09-29 18:46:31 +02:00
|
|
|
*
|
2025-09-29 17:46:30 +02:00
|
|
|
* @param logFolder The folder to store the log files
|
|
|
|
|
*/
|
|
|
|
|
private void initializeLogger(File logFolder) {
|
|
|
|
|
// Create a temporary logger instance to avoid final field issues
|
|
|
|
|
Logger tmpLogger = null;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// Initialize temporary logger
|
|
|
|
|
tmpLogger = new Logger(logFolder, false, true);
|
|
|
|
|
} catch (IOException | NoSuchFieldException | IllegalAccessException exception) {
|
|
|
|
|
exception.printStackTrace();
|
|
|
|
|
System.exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Assign the temporary logger to the final field
|
|
|
|
|
this.logger = tmpLogger;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Initialize the protocol version
|
|
|
|
|
* Validate if the protocol version is valid for the current side
|
|
|
|
|
* If not, log an error and exit the application
|
|
|
|
|
*/
|
|
|
|
|
private void initializeProtocolVersion() {
|
|
|
|
|
// Check if the protocol version is valid for the current side
|
|
|
|
|
// If not, log an error and exit the application
|
|
|
|
|
if (!validateProtocolSide()) {
|
|
|
|
|
this.logger.error("Invalid protocol version '" + protocolVersion.toString() + "'!");
|
|
|
|
|
System.exit(1);
|
|
|
|
|
}
|
2025-09-20 15:17:36 +02:00
|
|
|
}
|
|
|
|
|
|
2025-09-29 17:46:30 +02:00
|
|
|
/**
|
|
|
|
|
* Check if the classic protocol is supported by the current protocol version
|
2025-09-29 18:46:31 +02:00
|
|
|
*
|
2025-09-29 17:46:30 +02:00
|
|
|
* @return true if the classic protocol is supported, false otherwise
|
|
|
|
|
*/
|
2025-09-29 18:46:31 +02:00
|
|
|
public boolean isClassicSupported() {
|
2025-09-19 20:20:20 +02:00
|
|
|
boolean yes = false;
|
|
|
|
|
for (ProtocolVersion compatibleVersion : protocolVersion.getCompatibleVersions()) {
|
2025-09-29 17:46:30 +02:00
|
|
|
// Check if the compatible version is classic
|
2025-09-19 20:20:20 +02:00
|
|
|
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.CLASSIC;
|
|
|
|
|
if (yes) break;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-29 17:46:30 +02:00
|
|
|
// Check if the current protocol version is classic or if it is supported by any of the compatible versions
|
2025-09-19 20:20:20 +02:00
|
|
|
return protocolVersion.getProtocolType() == ProtocolVersion.ProtocolType.CLASSIC || yes;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-29 17:46:30 +02:00
|
|
|
/**
|
|
|
|
|
* Check if the target protocol is supported by the current protocol version
|
2025-09-29 18:46:31 +02:00
|
|
|
*
|
2025-09-29 17:46:30 +02:00
|
|
|
* @param protocol The target protocol to check
|
|
|
|
|
* @return true If the target protocol is supported, false otherwise
|
|
|
|
|
*/
|
2025-09-29 18:46:31 +02:00
|
|
|
public boolean isProtocolSupported(ProtocolVersion.Protocol protocol) {
|
2025-09-25 23:40:24 +02:00
|
|
|
boolean yes = false;
|
|
|
|
|
for (ProtocolVersion compatibleVersion : protocolVersion.getCompatibleVersions()) {
|
2025-09-29 17:46:30 +02:00
|
|
|
// Check if the compatible version supports the target protocol
|
2025-09-25 23:40:24 +02:00
|
|
|
yes = compatibleVersion.getSupportedProtocols().contains(protocol);
|
|
|
|
|
if (yes) break;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-29 17:46:30 +02:00
|
|
|
// Check if the current protocol version supports the target protocol or if it is supported by any of the compatible versions
|
2025-09-25 23:40:24 +02:00
|
|
|
return protocolVersion.getSupportedProtocols().contains(protocol) || yes;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-29 17:46:30 +02:00
|
|
|
/**
|
|
|
|
|
* Check if the target packet is supported by the current protocol version
|
2025-09-29 18:46:31 +02:00
|
|
|
*
|
2025-09-29 17:46:30 +02:00
|
|
|
* @param packet The target packet to check
|
|
|
|
|
* @return true if the target packet is supported, false otherwise
|
|
|
|
|
*/
|
2025-09-29 18:46:31 +02:00
|
|
|
public boolean isPacketSupported(OACPacket packet) {
|
2025-09-29 17:46:30 +02:00
|
|
|
return isVersionSupported(packet.getProtocolVersion());
|
2025-09-19 21:27:35 +02:00
|
|
|
}
|
|
|
|
|
|
2025-09-29 17:46:30 +02:00
|
|
|
/**
|
|
|
|
|
* Check if the target protocol version is supported by the current protocol version
|
2025-09-29 18:46:31 +02:00
|
|
|
*
|
2025-09-29 17:46:30 +02:00
|
|
|
* @param targetVersion The target protocol version to check
|
|
|
|
|
* @return true if the target protocol version is supported, false otherwise
|
|
|
|
|
*/
|
2025-09-29 18:46:31 +02:00
|
|
|
public boolean isVersionSupported(ProtocolVersion targetVersion) {
|
2025-09-29 17:46:30 +02:00
|
|
|
// Check if the target protocol version is the same as the current protocol version or if it is in the list of compatible versions
|
|
|
|
|
return protocolVersion == targetVersion || protocolVersion.getCompatibleVersions().contains(targetVersion);
|
2025-09-25 23:40:24 +02:00
|
|
|
}
|
|
|
|
|
|
2025-09-29 17:46:30 +02:00
|
|
|
/**
|
|
|
|
|
* Validate if the protocol version is valid for the current side
|
2025-09-29 18:46:31 +02:00
|
|
|
*
|
2025-09-29 17:46:30 +02:00
|
|
|
* @return true if the protocol version is valid for the current side, false otherwise
|
|
|
|
|
*/
|
2025-09-20 15:17:36 +02:00
|
|
|
private boolean validateProtocolSide() {
|
2025-09-25 23:40:24 +02:00
|
|
|
return
|
|
|
|
|
(isRunningAsClient() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.CLIENT) ||
|
2025-09-25 23:41:17 +02:00
|
|
|
(isRunningAsClient() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.CLIENT_WEB) ||
|
2025-12-08 09:59:58 +01:00
|
|
|
(isRunningAsClient() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.CLIENT_INS) ||
|
2025-09-25 23:41:17 +02:00
|
|
|
(isRunningAsClient() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.ALL) ||
|
|
|
|
|
|
|
|
|
|
(isRunningAsWebServer() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.WEB) ||
|
|
|
|
|
(isRunningAsWebServer() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.CLIENT_WEB) ||
|
2025-12-08 09:59:58 +01:00
|
|
|
(isRunningAsWebServer() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.WEB_INS) ||
|
2025-09-25 23:41:17 +02:00
|
|
|
(isRunningAsWebServer() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.ALL) ||
|
|
|
|
|
|
2026-01-18 18:17:35 +01:00
|
|
|
(isRunningAsServer() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.ALL) ||
|
|
|
|
|
|
2025-12-08 09:59:58 +01:00
|
|
|
(isRunningAsINSServer() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.INS) ||
|
|
|
|
|
(isRunningAsINSServer() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.WEB_INS) ||
|
|
|
|
|
(isRunningAsINSServer() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.CLIENT_INS) ||
|
|
|
|
|
(isRunningAsINSServer() && protocolVersion.getProtocolSide() == ProtocolVersion.ProtocolSide.ALL);
|
2025-09-19 21:27:35 +02:00
|
|
|
}
|
|
|
|
|
|
2025-09-29 17:46:30 +02:00
|
|
|
/**
|
2025-12-08 09:59:58 +01:00
|
|
|
* Check if the current instance is running as a INS server
|
2025-09-29 18:46:31 +02:00
|
|
|
*
|
2025-12-08 09:59:58 +01:00
|
|
|
* @return true if the current instance is running as a INS server, false otherwise
|
2025-09-29 17:46:30 +02:00
|
|
|
*/
|
2025-12-08 09:59:58 +01:00
|
|
|
public boolean isRunningAsINSServer() {
|
2026-01-18 18:17:35 +01:00
|
|
|
return isRunningAsServer() && protocolServer instanceof ProtocolINSServer;
|
2025-09-29 17:46:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if the current instance is running as a client
|
2025-09-29 18:46:31 +02:00
|
|
|
*
|
2025-09-29 17:46:30 +02:00
|
|
|
* @return true if the current instance is running as a client, false otherwise
|
|
|
|
|
*/
|
2025-09-29 18:46:31 +02:00
|
|
|
public boolean isRunningAsClient() {
|
2025-09-29 17:46:30 +02:00
|
|
|
return protocolClient != null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if the current instance is running as a web server
|
2025-09-29 18:46:31 +02:00
|
|
|
*
|
2025-09-29 17:46:30 +02:00
|
|
|
* @return true if the current instance is running as a web server, false otherwise
|
|
|
|
|
*/
|
2025-09-29 18:46:31 +02:00
|
|
|
public boolean isRunningAsWebServer() {
|
2026-01-18 18:17:35 +01:00
|
|
|
return isRunningAsServer() && protocolServer instanceof ProtocolWebServer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if the current instance is running as a custom server
|
|
|
|
|
*
|
|
|
|
|
* @return true if the current instance is running as a custom server, false otherwise
|
|
|
|
|
*/
|
|
|
|
|
public boolean isRunningAsServer() {
|
|
|
|
|
return protocolServer != null;
|
2025-09-19 21:27:35 +02:00
|
|
|
}
|
|
|
|
|
}
|