Added builtin ClassicHandler

This commit is contained in:
Finn
2026-01-18 18:17:35 +01:00
parent 50eac7dbd5
commit da254a6c8e
38 changed files with 982 additions and 1185 deletions

View File

@@ -0,0 +1,178 @@
package org.openautonomousconnection.protocol.side.server;
import dev.unlegitdqrk.unlegitlibrary.network.system.server.ConnectionHandler;
import lombok.Getter;
import org.openautonomousconnection.protocol.packets.OACPacket;
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
public abstract class CustomConnectedClient {
@Getter
private final ConnectionHandler pipelineConnection;
@Getter
private final ProtocolCustomServer server;
private ProtocolVersion clientVersion = null;
@Getter
private boolean clientVersionLoaded = false;
public CustomConnectedClient(ConnectionHandler pipelineConnection, ProtocolCustomServer protocolServer) {
this.pipelineConnection = pipelineConnection;
this.server = protocolServer;
}
public synchronized void disconnect() {
try {
server.clientDisconnected(this);
} catch (Exception ignored) {
}
try {
pipelineConnection.disconnect();
} catch (Exception ignored) {
}
}
/**
* Gets the protocol version of the connected client.
*
* @return The protocol version of the client, defaults to PV_1_0_0_CLASSIC if not set.
*/
public ProtocolVersion getClientVersion() {
return clientVersion == null ? ProtocolVersion.PV_1_0_0_CLASSIC : clientVersion;
}
/**
* Sets the protocol version of the connected client.
*
* @param clientVersion The protocol version to set.
*/
public void setClientVersion(ProtocolVersion clientVersion) {
if (clientVersionLoaded) return;
if (clientVersion == null) return;
this.clientVersion = clientVersion;
this.clientVersionLoaded = true;
}
/**
* Checks if the connected client is a stable client.
*
* @return True if the client is stable, false otherwise.
*/
public boolean isStableClient() {
// Check if the server version is stable
return !isBetaClient() && !isClassicClient();
}
/**
* Checks if the connected client supports stable protocol versions.
*
* @return True if the client supports stable versions, false otherwise.
*/
public boolean supportClientStable() {
boolean yes = false;
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
// Check if compatible version is stable
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.STABLE;
if (yes) break;
}
// Check if the client version is stable
return isStableClient() || yes;
}
/**
* Checks if the connected client is a beta client.
*
* @return True if the client is beta, false otherwise.
*/
public boolean isBetaClient() {
// Check if the server version is beta
return getClientVersion().getProtocolType() == ProtocolVersion.ProtocolType.BETA;
}
/**
* Checks if the connected client supports beta protocol versions.
*
* @return True if the client supports beta versions, false otherwise.
*/
public boolean supportClientBeta() {
boolean yes = false;
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
// Check if compatible version is beta
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.BETA;
if (yes) break;
}
// Check if the client version is beta
return isBetaClient() || yes;
}
/**
* Checks if the connected client is a classic client.
*
* @return True if the client is classic, false otherwise.
*/
public boolean isClassicClient() {
return getClientVersion().getProtocolType() == ProtocolVersion.ProtocolType.CLASSIC;
}
/**
* Checks if the connected client supports classic protocol versions.
*
* @return True if the client supports classic versions, false otherwise.
*/
public boolean supportClientClassic() {
boolean yes = false;
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
// Check if compatible version is classic
yes = compatibleVersion.getProtocolType() == ProtocolVersion.ProtocolType.CLASSIC;
if (yes) break;
}
// Check if the client version is classic
return isClassicClient() || yes;
}
/**
* Checks if the connected client supports the protocol version of the given packet.
*
* @param packet The packet to check support for.
* @return True if the client supports the packet's protocol version, false otherwise.
*/
public boolean supportClientPacket(OACPacket packet) {
return supportClientVersion(packet.getProtocolVersion());
}
/**
* Checks if the connected client supports the given protocol version.
*
* @param targetVersion The protocol version to check support for.
* @return True if the client supports the target version, false otherwise.
*/
public boolean supportClientVersion(ProtocolVersion targetVersion) {
// Check if the client version matches the target version or is compatible
return getClientVersion() == targetVersion || getClientVersion().getCompatibleVersions().contains(targetVersion);
}
/**
* Checks if the connected client supports the given protocol.
*
* @param protocol The protocol to check support for.
* @return True if the client supports the protocol, false otherwise.
*/
public boolean supportClientProtocol(ProtocolVersion.Protocol protocol) {
boolean yes = false;
for (ProtocolVersion compatibleVersion : getClientVersion().getCompatibleVersions()) {
// Check if compatible version supports the protocol
yes = compatibleVersion.getSupportedProtocols().contains(protocol);
if (yes) break;
}
// Check if the client version supports the protocol
return getClientVersion().getSupportedProtocols().contains(protocol) || yes;
}
}

View File

@@ -0,0 +1,206 @@
package org.openautonomousconnection.protocol.side.server;
import dev.unlegitdqrk.unlegitlibrary.network.system.server.NetworkServer;
import dev.unlegitdqrk.unlegitlibrary.network.utils.NetworkUtils;
import lombok.Getter;
import lombok.Setter;
import org.openautonomousconnection.protocol.ProtocolBridge;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.List;
public abstract class ProtocolCustomServer {
/**
* Structure for server.
*/
@Getter
private final ServerCertificateFolderStructure folderStructure;
/**
* Certificate files for SSL.
*/
private final File certFile;
/**
* Certificate files for SSL.
*/
private final File keyFile;
/**
* The reference to the ProtocolBridge Object
*/
@Getter
private ProtocolBridge protocolBridge;
/**
* List of connected web clients.
*/
@Getter
private List<CustomConnectedClient> clients;
@Setter
@Getter
private Class<? extends CustomConnectedClient> customClient;
/**
* The network server handling pipeline connections.
*/
@Getter
private NetworkServer pipelineServer;
/**
* Initializes the web server with the given configuration, authentication, and rules files.
*
* @throws Exception If an error occurs during initialization.
*/
public ProtocolCustomServer(String caPrefix, String certPrefix) throws Exception {
// Initialize the list of connected clients
this.clients = new ArrayList<>();
// Set up folder structure for certificates
folderStructure = new ServerCertificateFolderStructure(caPrefix, certPrefix);
// Check for necessary certificate files
checkFileExists(folderStructure.publicServerFolder, folderStructure.certPrefix, ".crt");
checkFileExists(folderStructure.privateServerFolder, folderStructure.certPrefix, ".key");
// Set up certificate files based on public IP address
this.certFile = new File(folderStructure.publicServerFolder, folderStructure.certPrefix + NetworkUtils.getPublicIPAddress() + ".crt");
this.keyFile = new File(folderStructure.privateServerFolder, folderStructure.certPrefix + NetworkUtils.getPublicIPAddress() + ".key");
}
/**
* Injects the ProtocolBridge.
*
* @param bridge the Bridge instance.
* @throws IOException when NetworkServer failed to create.
*/
public final void attachBridge(ProtocolBridge bridge) throws IOException {
if (this.protocolBridge != null)
throw new IllegalStateException("ProtocolBridge already attached!");
this.protocolBridge = bridge;
createNetworkServer();
}
/**
* Initialize the pipeline server
*/
private void createNetworkServer() {
pipelineServer = new NetworkServer.ServerBuilder().
setPort(protocolBridge.getProtocolSettings().port).setTimeout(0).
setPacketHandler(protocolBridge.getProtocolSettings().packetHandler).setEventManager(protocolBridge.getProtocolSettings().eventManager).
setLogger(protocolBridge.getLogger()).
setServerCertificate(certFile, keyFile).setRootCAFolder(folderStructure.publicCAFolder).
build();
}
/**
* Retrieves a connected web client by its client ID.
*
* @param clientID The client ID to search for.
* @return The connected web client with the specified ID, or null if not found.
*/
public final <T extends CustomConnectedClient> T getClientByID(int clientID) {
for (CustomConnectedClient client : clients)
if (client.getPipelineConnection().getClientID() == clientID) return (T) client;
return null;
}
/**
* Checks if the required certificate files exist in the specified folder.
*
* @param folder The folder to check for certificate files.
* @param prefix The prefix of the certificate files.
* @param extension The extension of the certificate files.
* @throws CertificateException If a required certificate file is missing or invalid.
* @throws IOException If an I/O error occurs while checking the files.
*/
private void checkFileExists(File folder, String prefix, String extension) throws CertificateException, IOException {
boolean found = false;
// Ensure the folder exists
if (folder == null) throw new FileNotFoundException("Folder does not exist");
// List all files in the folder
File[] files = folder.listFiles();
if (files == null || files.length == 0)
throw new FileNotFoundException("Folder " + folder.getAbsolutePath() + " is empty");
// Check for the required certificate file
for (File file : files) {
if (!file.getName().startsWith(prefix))
throw new CertificateException(file.getAbsolutePath() + " is not valid");
// Check for file matching the public IP address
if (!found) found = file.getName().equalsIgnoreCase(prefix + NetworkUtils.getPublicIPAddress() + extension);
}
// Throw exception if the required file is not found
if (!found) throw new CertificateException("Missing " + prefix + NetworkUtils.getPublicIPAddress() + extension);
}
public final void clientDisconnected(CustomConnectedClient client) {
clients.remove(client);
onDisconnect(client);
}
/**
* Optional callback when the connection closes.
*/
public void onDisconnect(CustomConnectedClient client) {
}
/**
* Represents the folder structure for server certificates.
*/
public final class ServerCertificateFolderStructure {
public final File certificatesFolder;
public final File publicFolder;
public final File privateFolder;
public final File privateCAFolder;
public final File privateServerFolder;
public final File publicCAFolder;
public final File publicServerFolder;
@Getter
private String caPrefix = "ca_server_";
@Getter
private String certPrefix = "cert_server_";
public ServerCertificateFolderStructure(String caPrefix, String certPrefix) {
this.caPrefix = caPrefix;
this.certPrefix = certPrefix;
certificatesFolder = new File("certificates");
publicFolder = new File(certificatesFolder, "public");
privateFolder = new File(certificatesFolder, "private");
privateCAFolder = new File(privateFolder, "ca");
privateServerFolder = new File(privateFolder, "server");
publicCAFolder = new File(publicFolder, "ca");
publicServerFolder = new File(publicFolder, "server");
if (!certificatesFolder.exists()) certificatesFolder.mkdirs();
if (!publicFolder.exists()) publicFolder.mkdirs();
if (!privateFolder.exists()) privateFolder.mkdirs();
if (!privateCAFolder.exists()) privateCAFolder.mkdirs();
if (!privateServerFolder.exists()) privateServerFolder.mkdirs();
if (!publicCAFolder.exists()) publicCAFolder.mkdirs();
if (!publicServerFolder.exists()) publicServerFolder.mkdirs();
}
}
}

View File

@@ -0,0 +1,21 @@
package org.openautonomousconnection.protocol.side.server.events;
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
import lombok.Getter;
import org.openautonomousconnection.protocol.side.server.CustomConnectedClient;
/**
* Event triggered when a web client connects to the web server.
*/
public final class S_CustomClientConnectedEvent extends Event {
/**
* The connected web client.
*/
@Getter
private final CustomConnectedClient client;
public S_CustomClientConnectedEvent(CustomConnectedClient client) {
this.client = client;
}
}

View File

@@ -0,0 +1,21 @@
package org.openautonomousconnection.protocol.side.server.events;
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
import lombok.Getter;
import org.openautonomousconnection.protocol.side.server.CustomConnectedClient;
/**
* Event triggered when a web client connects to the web server.
*/
public final class S_CustomClientDisconnectedEvent extends Event {
/**
* The connected web client.
*/
@Getter
private final CustomConnectedClient client;
public S_CustomClientDisconnectedEvent(CustomConnectedClient client) {
this.client = client;
}
}