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

@@ -19,7 +19,8 @@ public enum ProtocolVersion implements Serializable {
/**
* First Beta Version of OAC-Protocol
*/
PV_1_0_0_BETA("1.0.0", ProtocolType.BETA, ProtocolSide.ALL, List.of(Protocol.OAC), PV_1_0_0_CLASSIC),;
PV_1_0_0_BETA("1.0.0", ProtocolType.BETA, ProtocolSide.ALL, List.of(Protocol.OAC), PV_1_0_0_CLASSIC),
;
/**
* The version string of the protocol version.

View File

@@ -1,8 +1,6 @@
package org.openautonomousconnection.protocol.versions.v1_0_0.beta;
import org.openautonomousconnection.protocol.side.ins.ProtocolINSServer;
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSRecord;
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSRecordType;
import java.util.*;
@@ -42,7 +40,6 @@ public final class INSRecordTools {
* @param name InfoName.
* @param sub Optional sub-name, may be {@code null}.
* @param type Desired record type.
*
* @return A list of resolved records. May be empty if nothing could be resolved.
*/
public static List<INSRecord> resolveWithCNAME(ProtocolINSServer server,
@@ -87,7 +84,7 @@ public final class INSRecordTools {
ParsedName target = parseTargetName(cname.value);
if (target == null) continue;
List<INSRecord> resolved = server.resolve(target.tln, target.name,target.sub, targetType);
List<INSRecord> resolved = server.resolve(target.tln, target.name, target.sub, targetType);
if (!resolved.isEmpty()) return resolved;
@@ -110,7 +107,6 @@ public final class INSRecordTools {
* and the one before that is the InfoName.
*
* @param target FQDN string.
*
* @return ParsedName or {@code null} if it cannot be parsed.
*/
private static ParsedName parseTargetName(String target) {
@@ -130,12 +126,6 @@ public final class INSRecordTools {
return new ParsedName(tln, name, sub);
}
private record ParsedName(String tln, String name, String sub) {}
// -------------------------------------------------------------------------
// Validation helpers
// -------------------------------------------------------------------------
/**
* Performs basic validation on a single {@link INSRecord}.
* <p>
@@ -148,7 +138,6 @@ public final class INSRecordTools {
* </ul>
*
* @param record The record to validate.
*
* @return {@code true} if the record passes all checks, {@code false} otherwise.
*/
public static boolean isValidRecord(INSRecord record) {
@@ -157,17 +146,18 @@ public final class INSRecordTools {
if (record.value == null || record.value.isEmpty()) return false;
if (record.port < 0 || record.port > 65535) return false;
if (record.ttl < 0) return false;
return true;
return record.ttl >= 0;
}
// -------------------------------------------------------------------------
// Validation helpers
// -------------------------------------------------------------------------
/**
* Validates a collection of records by applying {@link #isValidRecord(INSRecord)}
* to each element.
*
* @param records Records to validate.
*
* @return A new list containing only valid records.
*/
public static List<INSRecord> filterValid(List<INSRecord> records) {
@@ -178,4 +168,7 @@ public final class INSRecordTools {
}
return out;
}
private record ParsedName(String tln, String name, String sub) {
}
}

View File

@@ -40,7 +40,7 @@ public abstract class ClassicHandlerClient {
public abstract void handleMessage(String message, Classic_ProtocolVersion protocolVersion);
public final void sendMessage(String message) throws IOException, ClassNotFoundException {
client.getClientINSConnection().sendPacket(new Classic_MessagePacket(message, 0, client.getProtocolBridge()));
client.getClientINSConnection().sendPacket(new Classic_MessagePacket(message, client.getClientServerConnection().getClientID(), client.getProtocolBridge()));
}
public abstract void validationCompleted(Classic_Domain domain, INSResponseStatus insResponseStatus);

View File

@@ -0,0 +1,74 @@
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers.builtin;
import lombok.Getter;
import org.openautonomousconnection.protocol.ProtocolBridge;
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSRecordType;
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSResponseStatus;
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers.ClassicHandlerClient;
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.helper.ClassicHelper;
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_Domain;
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.site.Classic_SiteType;
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.site.Classic_WebsitesContent;
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.utils.Classic_ProtocolVersion;
import java.io.IOException;
public abstract class ClientClassic extends ClassicHandlerClient {
@Getter
private final ProtocolBridge bridge;
@Getter
private final ClassicHelper helper;
public ClientClassic(ProtocolBridge bridge) {
super(bridge.getProtocolClient());
this.bridge = bridge;
this.helper = new ClassicHelper(bridge);
}
@Override
public void unsupportedClassicPacket(String className, Object[] content) {
bridge.getLogger().warn(
"[Classic UnsupportedPacket] packet=" + className + " content=" + java.util.Arrays.toString(content)
);
onUnsupportedClassicPacket(className, content);
}
/**
* Optional callback
*
* @param className The class name
* @param content The content
*/
public void onUnsupportedClassicPacket(String className, Object[] content) {
}
@Override
public void handleMessage(String message, Classic_ProtocolVersion protocolVersion) {
bridge.getLogger().info("[ClassicHandler] Message received (Classic Version " + protocolVersion.version + "): " + message);
onMessage(message, protocolVersion);
}
/**
* Optional callback
*
* @param message The Message
* @param protocolVersion the Classic version
*/
public void onMessage(String message, Classic_ProtocolVersion protocolVersion) {
}
@Override
public void validationCompleted(Classic_Domain domain, INSResponseStatus insResponseStatus) {
if (insResponseStatus == INSResponseStatus.OK) {
try {
bridge.getProtocolClient().sendINSQuery(domain.topLevelDomain, domain.name, null, INSRecordType.A);
} catch (IOException | ClassNotFoundException e) {
handleHTMLContent(Classic_SiteType.CLIENT, domain, Classic_WebsitesContent.ERROR_OCCURRED(e.getMessage()));
}
} else {
handleHTMLContent(Classic_SiteType.CLIENT, domain, Classic_WebsitesContent.DOMAIN_NOT_REACHABLE);
}
}
}

View File

@@ -0,0 +1,93 @@
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers.builtin;
import lombok.Getter;
import org.openautonomousconnection.protocol.ProtocolBridge;
import org.openautonomousconnection.protocol.side.ins.ConnectedProtocolClient;
import org.openautonomousconnection.protocol.side.ins.ProtocolINSServer;
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSRecord;
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSRecordType;
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers.ClassicHandlerINSServer;
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.helper.ClassicHelper;
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.helper.ParsedDomain;
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_Domain;
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_RequestDomain;
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.utils.Classic_ProtocolVersion;
import java.sql.SQLException;
import java.util.List;
public class INSClassic extends ClassicHandlerINSServer {
@Getter
private final ProtocolBridge bridge;
@Getter
private final ClassicHelper helper;
public INSClassic(ProtocolBridge bridge) {
this.bridge = bridge;
this.helper = new ClassicHelper(bridge);
}
@Override
public void handleMessage(ConnectedProtocolClient client, String message, Classic_ProtocolVersion protocolVersion) {
client.getServer().getProtocolBridge().getLogger().info("[ClassicHandler] Message received from ClientID " +
client.getPipelineConnection().getClientID() +
" (Classic Version " + protocolVersion.version + ", Client Version: " +
client.getClientVersion().toString() + "): " + message);
onMessage(client, message, protocolVersion);
}
/**
* Optional callback.
*
* @param client The client sender.
* @param message The message.
* @param protocolVersion The classic version.
*/
public void onMessage(ConnectedProtocolClient client, String message, Classic_ProtocolVersion protocolVersion) {
}
@Override
public Classic_Domain getDomain(Classic_RequestDomain requestDomain) throws SQLException {
if (!bridge.isRunningAsINSServer()) return null;
ParsedDomain pd = helper.parseDomain(requestDomain);
ProtocolINSServer server = (ProtocolINSServer) bridge.getProtocolServer();
// IMPORTANT: resolve() already performs CNAME recursion + sorting.
// Request A directly and pick the first (= best after sorting).
List<INSRecord> aRecords = server.resolve(pd.tln(), pd.name(), pd.sub(), INSRecordType.A);
if (aRecords.isEmpty()) return null;
INSRecord targetA = aRecords.get(0);
return helper.buildClassicDomain(pd, targetA);
}
@Override
public Classic_Domain ping(Classic_RequestDomain req) throws SQLException {
if (!bridge.isRunningAsINSServer()) return null;
return new Classic_Domain(req.name, req.topLevelDomain, null, req.path, bridge);
}
@Override
public void unsupportedClassicPacket(String className, Object[] content, ConnectedProtocolClient client) {
client.getServer().getProtocolBridge().getLogger().warn(
"[Classic UnsupportedPacket] From client " + client.getPipelineConnection().getClientID() +
": packet=" + className + " content=" + java.util.Arrays.toString(content)
);
onUnsupportedClassicPacket(className, content, client);
}
/**
* Optional callback.
*
* @param className The class name.
* @param content The content.
* @param client The client sender.
*/
public void onUnsupportedClassicPacket(String className, Object[] content, ConnectedProtocolClient client) {
}
}

View File

@@ -0,0 +1,56 @@
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers.builtin;
import lombok.Getter;
import org.openautonomousconnection.protocol.ProtocolBridge;
import org.openautonomousconnection.protocol.side.ins.ConnectedProtocolClient;
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers.ClassicHandlerWebServer;
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.utils.Classic_ProtocolVersion;
public class WebClassic extends ClassicHandlerWebServer {
@Getter
private final ProtocolBridge bridge;
public WebClassic(ProtocolBridge bridge) {
this.bridge = bridge;
}
@Override
public void handleMessage(ConnectedProtocolClient client, String message, Classic_ProtocolVersion protocolVersion) {
client.getServer().getProtocolBridge().getLogger().info("[ClassicHandler] Message received from ClientID " +
client.getPipelineConnection().getClientID() +
" (Classic Version " + protocolVersion.version + ", Client Version: " +
client.getClientVersion().toString() + "): " + message);
onMessage(client, message, protocolVersion);
}
/**
* Optional callback
*
* @param client The client sender
* @param message The Message
* @param protocolVersion the Classic version
*/
public void onMessage(ConnectedProtocolClient client, String message, Classic_ProtocolVersion protocolVersion) {
}
@Override
public void unsupportedClassicPacket(String className, Object[] content, ConnectedProtocolClient client) {
client.getServer().getProtocolBridge().getLogger().warn(
"[Classic UnsupportedPacket] From client " + client.getPipelineConnection().getClientID() +
": packet=" + className + " content=" + java.util.Arrays.toString(content)
);
onUnsupportedClassicPacket(className, content, client);
}
/**
* Optional callback
*
* @param className The class name
* @param content The content
* @param client The client sender
*/
public void onUnsupportedClassicPacket(String className, Object[] content, ConnectedProtocolClient client) {
}
}

View File

@@ -0,0 +1,41 @@
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.helper;
import org.openautonomousconnection.protocol.ProtocolBridge;
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSRecord;
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_Domain;
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_RequestDomain;
import java.util.Arrays;
public record ClassicHelper(ProtocolBridge bridge) {
public Classic_Domain buildClassicDomain(ParsedDomain req, INSRecord rec) {
Classic_Domain info = new Classic_Domain(req.name(), req.tln(), req.sub(), req.path(), bridge);
String host = rec.value;
int port = rec.port > 0 ? rec.port : 80;
return new Classic_Domain(
req.name(), req.tln(),
host.contains(":") ? host : host + ":" + port,
req.path(), bridge);
}
public ParsedDomain parseDomain(Classic_RequestDomain req) {
String tln = req.topLevelDomain; // example: "net"
String full = req.name; // example: "api.v1.example"
String[] parts = full.split("\\.");
if (parts.length == 1) {
return new ParsedDomain(tln, full, null, req.path);
}
String name = parts[parts.length - 1];
String sub = parts.length > 1
? String.join(".", Arrays.copyOfRange(parts, 0, parts.length - 1))
: null;
return new ParsedDomain(tln, name, sub, req.path);
}
}

View File

@@ -0,0 +1,4 @@
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.helper;
public record ParsedDomain(String tln, String name, String sub, String path) {
}

View File

@@ -0,0 +1,7 @@
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.helper;
/**
* Represents a parsed CNAME target in (tln, name, sub) form.
*/
public record TargetName(String tln, String name, String sub) {
}

View File

@@ -1,6 +1,5 @@
package org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects;
import lombok.Getter;
import org.openautonomousconnection.protocol.ProtocolBridge;
import java.io.Serializable;