package org.openautonomousconnection.ins; import dev.unlegitdqrk.unlegitlibrary.file.ConfigurationManager; import org.openautonomousconnection.protocol.ProtocolBridge; 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.io.File; import java.io.IOException; import java.security.cert.CertificateException; import java.sql.*; import java.util.ArrayList; import java.util.List; /** * Concrete INS server implementation backed by a SQL database. *
* This implementation expects a table schema similar to: *
* CREATE TABLE ins_records (
* id BIGINT PRIMARY KEY AUTO_INCREMENT,
* tln VARCHAR(64) NOT NULL,
* name VARCHAR(255) NOT NULL,
* sub VARCHAR(255) NULL,
* type VARCHAR(16) NOT NULL, -- matches {@link INSRecordType#name()}
* value VARCHAR(1024) NOT NULL,
* priority INT NOT NULL,
* weight INT NOT NULL,
* port INT NOT NULL,
* ttl INT NOT NULL
* );
*
* CREATE TABLE ins_tln_info (
* tln VARCHAR(64) PRIMARY KEY,
* host VARCHAR(255) NOT NULL,
* port INT NOT NULL
* );
*
*/
public final class DatabaseINSServer extends ProtocolINSServer {
private final String jdbcUrl;
private final String jdbcUser;
private final String jdbcPassword;
private final ConfigurationManager configurationManager;
/**
* Creates a new database-backed INS server.
*
* @throws IOException If the base server initialization fails.
* @throws CertificateException If required certificate files are missing or invalid.
*/
public DatabaseINSServer() throws IOException, CertificateException {
super(new File("config.properties"));
configurationManager = new ConfigurationManager(new File("config.properties"));
configurationManager.loadProperties();
if (!configurationManager.isSet("db.url")) {
configurationManager.set("db.url", "jdbc:mysql://localhost:3306/DB_NAME?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC\n");
configurationManager.saveProperties();
}
if (!configurationManager.isSet("db.user")) {
configurationManager.set("db.user", "username");
configurationManager.saveProperties();
}
if (!configurationManager.isSet("db.password")) {
configurationManager.set("db.password", "password");
configurationManager.saveProperties();
}
jdbcUrl = configurationManager.getString("db.url");
jdbcUser = configurationManager.getString("db.user");
jdbcPassword = configurationManager.getString("db.password");
}
private Connection openConnection() throws SQLException {
return DriverManager.getConnection(jdbcUrl, jdbcUser, jdbcPassword);
}
/**
* Resolves records for the given INS name from the database.
*
* This method does a single lookup and returns exactly the records that
* match the given query (no CNAME recursion here – that is handled on a
* higher level, e.g. via {@code INSRecordTools.resolveWithCNAME(...)}).
*
* @param tln Top-level-name.
* @param name InfoName.
* @param sub Optional sub-name. May be {@code null}.
* @param type Desired record type.
*
* @return List of matching {@link INSRecord}s, or an empty list if none exist.
*/
@Override
public List
* The result must be returned as {@code "host:port"}.
*
* @param tln The TLN the client is asking about.
*
* @return A {@code "host:port"} string or {@code null} if no TLN info site is configured.
*/
@Override
public String resolveTLNInfoSite(String tln) {
String sql = "SELECT host, port FROM ins_tln_info WHERE tln = ?";
try (Connection conn = openConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, tln);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
String host = rs.getString("host");
int port = rs.getInt("port");
return host + ":" + port;
}
}
} catch (SQLException ex) {
getProtocolBridge().getLogger().exception("Failed to resolve TLN info site for tln=" + tln, ex);
}
return null;
}
}