mirror of
https://github.com/funkemunky/AntiVPN.git
synced 2026-05-31 09:31:54 +00:00
Fixing SQL load errors
This commit is contained in:
@@ -63,7 +63,7 @@
|
|||||||
<goal>shade</goal>
|
<goal>shade</goal>
|
||||||
</goals>
|
</goals>
|
||||||
<configuration>
|
<configuration>
|
||||||
<minimizeJar>true</minimizeJar>
|
<minimizeJar>false</minimizeJar>
|
||||||
<relocations>
|
<relocations>
|
||||||
<relocation>
|
<relocation>
|
||||||
<pattern>org.yaml.snakeyaml</pattern>
|
<pattern>org.yaml.snakeyaml</pattern>
|
||||||
@@ -148,7 +148,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.mysql</groupId>
|
<groupId>com.mysql</groupId>
|
||||||
<artifactId>mysql-connector-j</artifactId>
|
<artifactId>mysql-connector-j</artifactId>
|
||||||
<version>9.1.0</version>
|
<version>9.3.0</version>
|
||||||
<type>jar</type>
|
<type>jar</type>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
@@ -182,7 +182,6 @@
|
|||||||
<version>3.1.8</version>
|
<version>3.1.8</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mongodb</groupId>
|
<groupId>org.mongodb</groupId>
|
||||||
<artifactId>mongo-java-driver</artifactId>
|
<artifactId>mongo-java-driver</artifactId>
|
||||||
|
|||||||
@@ -57,10 +57,10 @@ import java.util.List;
|
|||||||
@MavenLibrary(
|
@MavenLibrary(
|
||||||
groupId = "com.mysql",
|
groupId = "com.mysql",
|
||||||
artifactId = "mysql-connector-j",
|
artifactId = "mysql-connector-j",
|
||||||
version = "9.1.0",
|
version = "9.3.0",
|
||||||
relocations = {
|
relocations = {
|
||||||
@Relocate(from = "com.my\\" + "sql.cj", to = "dev.brighten.antivpn.shaded.com.mysql.cj"),
|
@Relocate(from = "com.my\\" + "sql.cj", to = "dev.brighten.antivpn.shaded.com.mysql.cj"),
|
||||||
@Relocate(from = "com.my\\" + "sql.jdbc", to = "dev.brighten.antivpn.shaded.com.mysql.jdbc")
|
@Relocate(from = "com.my\\" + "sql.jdbc", to = "dev.brighten.antivpn.shaded.com.mysql.jdbc"),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@MavenLibrary(groupId = "com.\\github\\.ben-manes\\.caffeine", artifactId = "caffeine", version = "3.1.8",
|
@MavenLibrary(groupId = "com.\\github\\.ben-manes\\.caffeine", artifactId = "caffeine", version = "3.1.8",
|
||||||
|
|||||||
@@ -359,15 +359,37 @@ public class H2VPN implements VPNDatabase {
|
|||||||
public void backupDatabase() {
|
public void backupDatabase() {
|
||||||
File dataFolder = new File(AntiVPN.getInstance().getPluginFolder(), "databases");
|
File dataFolder = new File(AntiVPN.getInstance().getPluginFolder(), "databases");
|
||||||
|
|
||||||
if(!dataFolder.exists()) {
|
if(!dataFolder.exists() || MySQL.isClosed()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<File> files = new ArrayList<>(List.of(Optional.ofNullable(dataFolder.listFiles()).orElse(new File[0])));
|
try {
|
||||||
files.sort(Comparator.comparingLong(File::lastModified));
|
var connection = Query.getConn();
|
||||||
|
if (connection == null || connection.getMetaData() == null
|
||||||
|
|| !connection.getMetaData().getDatabaseProductName().equalsIgnoreCase("H2")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
AntiVPN.getInstance().getExecutor().logException("Could not verify database type before H2 backup.", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (File file : files) {
|
File backupDir = new File(dataFolder, "backups");
|
||||||
MySQL.backupOldDB(file, dataFolder);
|
if (!backupDir.exists() && !backupDir.mkdirs()) {
|
||||||
|
AntiVPN.getInstance().getExecutor().log("Could not create backup directory");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
File backupFile = new File(backupDir, "database.h2_backup_" + System.currentTimeMillis() + ".zip");
|
||||||
|
String backupPath = backupFile.getAbsolutePath()
|
||||||
|
.replace("\\", "/")
|
||||||
|
.replace("'", "''");
|
||||||
|
|
||||||
|
try (var statement = Query.prepare("BACKUP TO '" + backupPath + "'")) {
|
||||||
|
statement.execute();
|
||||||
|
AntiVPN.getInstance().getExecutor().log("Created H2 backup at " + backupFile.getName());
|
||||||
|
} catch (SQLException e) {
|
||||||
|
AntiVPN.getInstance().getExecutor().logException("Could not create H2 backup before migration.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import dev.brighten.antivpn.database.sql.utils.Query;
|
|||||||
import dev.brighten.antivpn.database.version.Version;
|
import dev.brighten.antivpn.database.version.Version;
|
||||||
import dev.brighten.antivpn.utils.MiscUtils;
|
import dev.brighten.antivpn.utils.MiscUtils;
|
||||||
|
|
||||||
|
import java.sql.DatabaseMetaData;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -51,11 +52,11 @@ public class First implements Version<VPNDatabase> {
|
|||||||
.append(versionNumber())).execute();
|
.append(versionNumber())).execute();
|
||||||
|
|
||||||
AntiVPN.getInstance().getExecutor().log("Creating indexes...");
|
AntiVPN.getInstance().getExecutor().log("Creating indexes...");
|
||||||
closeOnEnd(Query.prepare("create index if not exists `uuid_1` on `whitelisted` (`uuid`)")).execute();
|
createIndexIfAbsent("whitelisted", "uuid_1", "`uuid`");
|
||||||
closeOnEnd(Query.prepare("create index if not exists `ip_1` on `responses` (`ip`)")).execute();
|
createIndexIfAbsent("responses", "ip_1", "`ip`");
|
||||||
closeOnEnd(Query.prepare("create index if not exists `proxy_1` on `responses` (`proxy`)")).execute();
|
createIndexIfAbsent("responses", "proxy_1", "`proxy`");
|
||||||
closeOnEnd(Query.prepare("create index if not exists `inserted_1` on `responses` (`inserted`)")).execute();
|
createIndexIfAbsent("responses", "inserted_1", "`inserted`");
|
||||||
closeOnEnd(Query.prepare("create index if not exists `ip_1` on `whitelisted-ips` (`ip`)")).execute();
|
createIndexIfAbsent("whitelisted-ips", "ip_1", "`ip`");
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new DatabaseException("Failed to update database", e);
|
throw new DatabaseException("Failed to update database", e);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -69,6 +70,47 @@ public class First implements Version<VPNDatabase> {
|
|||||||
return statement;
|
return statement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void createIndexIfAbsent(String tableName, String indexName, String columnList) throws SQLException {
|
||||||
|
if (hasIndex(tableName, indexName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
closeOnEnd(Query.prepare(String.format(
|
||||||
|
"create index `%s` on `%s` (%s)",
|
||||||
|
indexName,
|
||||||
|
tableName,
|
||||||
|
columnList
|
||||||
|
))).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void dropIndexIfPresent(String tableName, String indexName) throws SQLException {
|
||||||
|
if (!hasIndex(tableName, indexName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
closeOnEnd(Query.prepare(String.format(
|
||||||
|
"drop index `%s` on `%s`",
|
||||||
|
indexName,
|
||||||
|
tableName
|
||||||
|
))).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean hasIndex(String tableName, String indexName) throws SQLException {
|
||||||
|
DatabaseMetaData metaData = Query.getConn().getMetaData();
|
||||||
|
|
||||||
|
try (ResultSet indexes = metaData.getIndexInfo(null, null, tableName, false, false)) {
|
||||||
|
while (indexes.next()) {
|
||||||
|
String existingIndexName = indexes.getString("INDEX_NAME");
|
||||||
|
|
||||||
|
if (existingIndexName != null && existingIndexName.equalsIgnoreCase(indexName)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int versionNumber() {
|
public int versionNumber() {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -78,7 +120,7 @@ public class First implements Version<VPNDatabase> {
|
|||||||
public boolean needsUpdate(VPNDatabase database) {
|
public boolean needsUpdate(VPNDatabase database) {
|
||||||
try(var statement = Query.prepare("select * from `database_version` where version = 0")) {
|
try(var statement = Query.prepare("select * from `database_version` where version = 0")) {
|
||||||
try(ResultSet set = statement.executeQuery()) {
|
try(ResultSet set = statement.executeQuery()) {
|
||||||
return set.getFetchSize() == 0;
|
return !set.next();
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
+8
-11
@@ -20,6 +20,7 @@ import dev.brighten.antivpn.AntiVPN;
|
|||||||
import dev.brighten.antivpn.database.DatabaseException;
|
import dev.brighten.antivpn.database.DatabaseException;
|
||||||
import dev.brighten.antivpn.database.VPNDatabase;
|
import dev.brighten.antivpn.database.VPNDatabase;
|
||||||
import dev.brighten.antivpn.database.local.H2VPN;
|
import dev.brighten.antivpn.database.local.H2VPN;
|
||||||
|
import dev.brighten.antivpn.database.sql.MySqlVPN;
|
||||||
import dev.brighten.antivpn.database.sql.utils.ExecutableStatement;
|
import dev.brighten.antivpn.database.sql.utils.ExecutableStatement;
|
||||||
import dev.brighten.antivpn.database.sql.utils.Query;
|
import dev.brighten.antivpn.database.sql.utils.Query;
|
||||||
import dev.brighten.antivpn.database.version.Version;
|
import dev.brighten.antivpn.database.version.Version;
|
||||||
@@ -31,12 +32,12 @@ import java.sql.SQLException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class Second implements Version<VPNDatabase> {
|
public class Second extends First implements Version<VPNDatabase> {
|
||||||
private final List<AutoCloseable> toClose = new ArrayList<>();
|
private final List<AutoCloseable> toClose = new ArrayList<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(VPNDatabase database) throws DatabaseException {
|
public void update(VPNDatabase database) throws DatabaseException {
|
||||||
if(database instanceof H2VPN h2VPN) {
|
if(database instanceof H2VPN h2VPN && !(database instanceof MySqlVPN)) {
|
||||||
h2VPN.backupDatabase();
|
h2VPN.backupDatabase();
|
||||||
}
|
}
|
||||||
List<String> whitelistedIps = new ArrayList<>();
|
List<String> whitelistedIps = new ArrayList<>();
|
||||||
@@ -58,7 +59,7 @@ public class Second implements Version<VPNDatabase> {
|
|||||||
"ip_start BIGINT NOT NULL, " +
|
"ip_start BIGINT NOT NULL, " +
|
||||||
"ip_end BIGINT NOT NULL)"))
|
"ip_end BIGINT NOT NULL)"))
|
||||||
.execute();
|
.execute();
|
||||||
closeOnEnd(Query.prepare("CREATE INDEX idx_ip_range ON `whitelisted-ranges` (ip_start, ip_end)")).execute();
|
createIndexIfAbsent("whitelisted-ranges", "idx_ip_range", "ip_start, ip_end");
|
||||||
|
|
||||||
var cidrs = whitelistedIps.stream().map(ip -> {
|
var cidrs = whitelistedIps.stream().map(ip -> {
|
||||||
try {
|
try {
|
||||||
@@ -84,7 +85,7 @@ public class Second implements Version<VPNDatabase> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
closeOnEnd(Query.prepare("DROP INDEX ip_1 on `whitelisted-ips`")).execute();
|
dropIndexIfPresent("whitelisted-ips", "ip_1");
|
||||||
closeOnEnd(Query.prepare("DROP TABLE `whitelisted-ips`")).execute();
|
closeOnEnd(Query.prepare("DROP TABLE `whitelisted-ips`")).execute();
|
||||||
closeOnEnd(Query.prepare("INSERT INTO `database_version` (`version`) VALUES (?)").append(versionNumber())).execute();
|
closeOnEnd(Query.prepare("INSERT INTO `database_version` (`version`) VALUES (?)").append(versionNumber())).execute();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
@@ -109,9 +110,7 @@ public class Second implements Version<VPNDatabase> {
|
|||||||
|
|
||||||
private void rollback(List<String> ipAddresses) throws SQLException {
|
private void rollback(List<String> ipAddresses) throws SQLException {
|
||||||
AntiVPN.getInstance().getExecutor().log("Rolling back to version 0...");
|
AntiVPN.getInstance().getExecutor().log("Rolling back to version 0...");
|
||||||
try(var statement = Query.prepare("DROP INDEX idx_ip_range ON `whitelisted-ranges`")) {
|
dropIndexIfPresent("whitelisted-ranges", "idx_ip_range");
|
||||||
statement.execute();
|
|
||||||
}
|
|
||||||
try(var statement = Query.prepare("DROP TABLE `whitelisted-ranges`")) {
|
try(var statement = Query.prepare("DROP TABLE `whitelisted-ranges`")) {
|
||||||
statement.execute();
|
statement.execute();
|
||||||
}
|
}
|
||||||
@@ -124,9 +123,7 @@ public class Second implements Version<VPNDatabase> {
|
|||||||
statement.execute();
|
statement.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
try(var statement = Query.prepare("create index if not exists `ip_1` on `whitelisted-ips` (`ip`)")) {
|
createIndexIfAbsent("whitelisted-ips", "ip_1", "`ip`");
|
||||||
statement.execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
try(var statement = Query.prepare("DELETE FROM `whitelisted-ips`")) {
|
try(var statement = Query.prepare("DELETE FROM `whitelisted-ips`")) {
|
||||||
statement.execute();
|
statement.execute();
|
||||||
@@ -151,7 +148,7 @@ public class Second implements Version<VPNDatabase> {
|
|||||||
public boolean needsUpdate(VPNDatabase database) {
|
public boolean needsUpdate(VPNDatabase database) {
|
||||||
try (var statement = Query.prepare("select * from `database_version` where version = 1")) {
|
try (var statement = Query.prepare("select * from `database_version` where version = 1")) {
|
||||||
try(var set = statement.executeQuery()) {
|
try(var set = statement.executeQuery()) {
|
||||||
return set.getFetchSize() == 0;
|
return !set.next();
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ public class Third implements Version<VPNDatabase> {
|
|||||||
public boolean needsUpdate(VPNDatabase database) {
|
public boolean needsUpdate(VPNDatabase database) {
|
||||||
try (var statement = Query.prepare("select * from `database_version` where version = 2")) {
|
try (var statement = Query.prepare("select * from `database_version` where version = 2")) {
|
||||||
try(var set = statement.executeQuery()) {
|
try(var set = statement.executeQuery()) {
|
||||||
return set.getFetchSize() == 0;
|
return !set.next();
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -54,14 +54,11 @@ public class MySQL {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean didRetry = false;
|
|
||||||
|
|
||||||
public static void initH2() {
|
public static void initH2() {
|
||||||
if(didRetry) {
|
initH2(true);
|
||||||
AntiVPN.getInstance().getExecutor().log(Level.WARNING,
|
}
|
||||||
"Already attempted to retry H2 connection, skipping.");
|
|
||||||
return;
|
private static void initH2(boolean allowRetry) {
|
||||||
}
|
|
||||||
File dataFolder = new File(AntiVPN.getInstance().getPluginFolder(), "databases");
|
File dataFolder = new File(AntiVPN.getInstance().getPluginFolder(), "databases");
|
||||||
if (!dataFolder.exists() && dataFolder.mkdirs()) {
|
if (!dataFolder.exists() && dataFolder.mkdirs()) {
|
||||||
AntiVPN.getInstance().getExecutor().log("Created database directory");
|
AntiVPN.getInstance().getExecutor().log("Created database directory");
|
||||||
@@ -85,9 +82,13 @@ public class MySQL {
|
|||||||
AntiVPN.getInstance().getExecutor()
|
AntiVPN.getInstance().getExecutor()
|
||||||
.log("H2 database file is incompatible with this version of AntiVPN. " +
|
.log("H2 database file is incompatible with this version of AntiVPN. " +
|
||||||
"Backing up old database file...");
|
"Backing up old database file...");
|
||||||
backupOldDB(dbFile, dataFolder);
|
shutdown();
|
||||||
initH2();
|
if (allowRetry && backupOldDB(dbFile, dataFolder)) {
|
||||||
didRetry = true;
|
initH2(false);
|
||||||
|
} else {
|
||||||
|
AntiVPN.getInstance().getExecutor().log(
|
||||||
|
"Could not back up and remove the incompatible H2 database file automatically.");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
AntiVPN.getInstance().getExecutor().logException("Failed to load H2 database: " + ex.getCause().toString(), ex);
|
AntiVPN.getInstance().getExecutor().logException("Failed to load H2 database: " + ex.getCause().toString(), ex);
|
||||||
}
|
}
|
||||||
@@ -97,31 +98,42 @@ public class MySQL {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void backupOldDB(File dbFile, File dataFolder) {
|
public static boolean backupOldDB(File dbFile, File dataFolder) {
|
||||||
if (dbFile.exists()) {
|
if (!dbFile.exists()) {
|
||||||
try {
|
return true;
|
||||||
// Optional: Make backup first
|
|
||||||
File backupDir = new File(dataFolder, "backups");
|
|
||||||
if(backupDir.mkdirs()) {
|
|
||||||
AntiVPN.getInstance().getExecutor().log("Created backup directory");
|
|
||||||
} else {
|
|
||||||
AntiVPN.getInstance().getExecutor().log("Backup directory already exists");
|
|
||||||
}
|
|
||||||
File backupFile = new File(backupDir, dbFile.getName() + ".backup_" + System.currentTimeMillis());
|
|
||||||
Files.copy(dbFile.toPath(), backupFile.toPath());
|
|
||||||
|
|
||||||
// Actually delete the file
|
|
||||||
if (!dbFile.delete()) {
|
|
||||||
// If normal delete fails, try force delete on JVM exit
|
|
||||||
dbFile.deleteOnExit();
|
|
||||||
AntiVPN.getInstance().getExecutor().log("Could not delete database file - will try again on shutdown");
|
|
||||||
} else {
|
|
||||||
AntiVPN.getInstance().getExecutor().log("Successfully deleted incompatible database file");
|
|
||||||
}
|
|
||||||
} catch (IOException ex) {
|
|
||||||
AntiVPN.getInstance().getExecutor().logException("Failed to handle database file", ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!dbFile.isFile()) {
|
||||||
|
AntiVPN.getInstance().getExecutor().log("Skipping backup for non-file path: " + dbFile.getAbsolutePath());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
File backupDir = new File(dataFolder, "backups");
|
||||||
|
if(backupDir.mkdirs()) {
|
||||||
|
AntiVPN.getInstance().getExecutor().log("Created backup directory");
|
||||||
|
} else if (backupDir.exists()) {
|
||||||
|
AntiVPN.getInstance().getExecutor().log("Backup directory already exists");
|
||||||
|
} else {
|
||||||
|
AntiVPN.getInstance().getExecutor().log("Could not create backup directory");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
File backupFile = new File(backupDir, dbFile.getName() + ".backup_" + System.currentTimeMillis());
|
||||||
|
Files.copy(dbFile.toPath(), backupFile.toPath());
|
||||||
|
|
||||||
|
if (!dbFile.delete()) {
|
||||||
|
dbFile.deleteOnExit();
|
||||||
|
AntiVPN.getInstance().getExecutor().log("Could not delete database file - will try again on shutdown");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AntiVPN.getInstance().getExecutor().log("Successfully deleted incompatible database file");
|
||||||
|
return true;
|
||||||
|
} catch (IOException ex) {
|
||||||
|
AntiVPN.getInstance().getExecutor().logException("Failed to handle database file", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void use() {
|
public static void use() {
|
||||||
|
|||||||
Reference in New Issue
Block a user