From d4740d71e71793d556f6998ec609325c3e5d31de Mon Sep 17 00:00:00 2001 From: Zontreck Date: Tue, 13 Feb 2024 21:58:34 -0700 Subject: [PATCH] Save current progress --- server/build.gradle | 8 +- server/gradle.properties | 6 +- .../dev/zontreck/playsync/PlaySyncServer.java | 119 ++++++++++-- .../java/dev/zontreck/playsync/Settings.java | 8 + .../zontreck/playsync/data/DataFragment.java | 48 +++-- .../dev/zontreck/playsync/data/Manifest.java | 3 + .../data/database/DatabaseConnection.java | 36 ++++ .../playsync/data/database/Migrations.java | 176 ++++++++++++++++++ .../data/database/migrations/ChunksTable.java | 146 +++++++++++++++ .../database/migrations/ManifestsTable.java | 73 ++++++++ .../playsync/events/EventHandlers.java | 29 +++ .../server/events/HTTPRequestEvent.java | 3 +- .../server/events/MigrationEvent.java | 7 + 13 files changed, 631 insertions(+), 31 deletions(-) create mode 100644 server/src/main/java/dev/zontreck/playsync/data/database/DatabaseConnection.java create mode 100644 server/src/main/java/dev/zontreck/playsync/data/database/Migrations.java create mode 100644 server/src/main/java/dev/zontreck/playsync/data/database/migrations/ChunksTable.java create mode 100644 server/src/main/java/dev/zontreck/playsync/data/database/migrations/ManifestsTable.java create mode 100644 server/src/main/java/dev/zontreck/playsync/server/events/MigrationEvent.java diff --git a/server/build.gradle b/server/build.gradle index 642f6ae..e2802a2 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -68,7 +68,12 @@ repositories { dependencies { provided "dev.zontreck:EventsBus:${Bus_API}.${Bus_Patch}" + provided "dev.zontreck:LibAC:${LibAC_API}.${LibAC_Patch}" + + provided "org.mariadb.jdbc:mariadb-java-client:${MariaDB_JDBC_Version}" + provided "org.slf4j:log4j-over-slf4j:2.0.7" + provided "org.slf4j:slf4j-simple:2.0.7" } def MAVEN_PASSWORD_PROPERTY = "AriasCreationsMavenPassword" @@ -117,7 +122,8 @@ task jarjar(type: Jar) { manifest { attributes ( 'Main-Class': application.mainClass, - 'Multi-Release': 'true' + 'Multi-Release': 'true', + 'Implementation-Version': version ) } archiveClassifier = "AIO" diff --git a/server/gradle.properties b/server/gradle.properties index 500a142..194544d 100644 --- a/server/gradle.properties +++ b/server/gradle.properties @@ -1,9 +1,11 @@ apiVer=1.0 Bus_API=1.0 -Bus_Patch=33 +Bus_Patch=45 LibAC_API=1.4 -LibAC_Patch=35 +LibAC_Patch=46 + +MariaDB_JDBC_Version=3.3.2 org.gradle.daemon=false \ No newline at end of file diff --git a/server/src/main/java/dev/zontreck/playsync/PlaySyncServer.java b/server/src/main/java/dev/zontreck/playsync/PlaySyncServer.java index 603c696..44fbebd 100644 --- a/server/src/main/java/dev/zontreck/playsync/PlaySyncServer.java +++ b/server/src/main/java/dev/zontreck/playsync/PlaySyncServer.java @@ -11,9 +11,14 @@ import dev.zontreck.ariaslib.terminal.Banners; import dev.zontreck.ariaslib.util.FileIO; import dev.zontreck.ariaslib.util.Hashing; import dev.zontreck.eventsbus.Bus; +import dev.zontreck.eventsbus.EventDispatcher; import dev.zontreck.playsync.data.DataAccountant; import dev.zontreck.playsync.data.DataFragment; import dev.zontreck.playsync.data.Manifest; +import dev.zontreck.playsync.data.database.DatabaseConnection; +import dev.zontreck.playsync.data.database.Migrations; +import dev.zontreck.playsync.data.database.migrations.ChunksTable; +import dev.zontreck.playsync.data.database.migrations.ManifestsTable; import dev.zontreck.playsync.events.EventHandlers; import dev.zontreck.playsync.exceptions.UnsupportedAlgorithmException; import dev.zontreck.playsync.exceptions.UnsupportedIDException; @@ -22,6 +27,8 @@ import dev.zontreck.playsync.games.nintendo.ID6; import dev.zontreck.playsync.server.HTTPServer; import java.io.*; +import java.sql.Connection; +import java.sql.SQLException; import java.util.ArrayList; import java.util.List; @@ -36,12 +43,26 @@ public class PlaySyncServer { DEFAULT_ARGS.setArg(new IntegerArgument("port", 1588)); DEFAULT_ARGS.setArg(new StringArgument("dataDir", "data")); DEFAULT_ARGS.setArg(new StringArgument("hash", "MD5")); + DEFAULT_ARGS.setArg(new IntegerArgument("db_port", 3306)); + DEFAULT_ARGS.setArg(new StringArgument("db_host", "localhost")); + DEFAULT_ARGS.setArg(new StringArgument("db_name", "PlaySync")); + DEFAULT_ARGS.setArg(new StringArgument("db_user", "NSET\r")); + DEFAULT_ARGS.setArg(new StringArgument("db_pass", "NSET\r")); + } - Settings.PORT_NUMBER = (int) DEFAULT_ARGS.getArg("port").getValue(); - Settings.DATA_DIRECTORY = (String)DEFAULT_ARGS.getArg("dataDir").getValue(); - Settings.HASH_ALGORITHM = (String)DEFAULT_ARGS.getArg("hash").getValue(); - + public static void printUsage() + { + log("Usage: java -jar PlaySyncServer.jar --db_user= --db_pass= [options]"); + log(""); + log("--port=\t\t\tDefault: 1588\n", + "--dataDir=\t\tDefault: data\n", + "--hash=\t\t\tDefault: MD5, (valid: MD5, SHA256)\n", + "--db_port=\t\tDefault: 3306\n", + "--db_host=\t\tDefault: localhost\n", + "--db_user=\t\t(REQUIRED)\n", + "--db_name=\t\tDefault: PlaySync\n", + "--db_pass=\t\t(REQUIRED)\n"); } private static void log(String... args) @@ -74,19 +95,26 @@ public class PlaySyncServer { } public static void main(String[] args) { - log(Banners.generateBanner("PlaySync Server")); + log(Banners.generateBanner("Harbinger CDN Server")); + log("Version: "+PlaySyncServer.class.getPackage().getImplementationVersion() + "\n"); + Arguments active = ArgumentsParser.parseArguments(args, DEFAULT_ARGS); IntegerArgument port = (IntegerArgument) active.getArg("port"); StringArgument dataDir = (StringArgument) active.getArg("dataDir"); StringArgument hashing = (StringArgument) active.getArg("hash"); - - log("Registering EventHandlers"); - Bus.Register(EventHandlers.class, new EventHandlers()); - log("EventHandlers have been registered"); + IntegerArgument dbPort = (IntegerArgument) active.getArg("db_port"); + StringArgument dbHost = (StringArgument) active.getArg("db_host"); + StringArgument dbName = (StringArgument) active.getArg("db_name"); + StringArgument dbUser = (StringArgument) active.getArg("db_user"); + StringArgument dbPass = (StringArgument) active.getArg("db_pass"); + + + log("Parsing command line arguments..."); + if(active.hasArg("port")) Settings.PORT_NUMBER = port.getValue(); @@ -96,10 +124,72 @@ public class PlaySyncServer { if(active.hasArg("hash")) Settings.HASH_ALGORITHM = hashing.getValue(); + if(active.hasArg("db_port")) + Settings.DB_PORT = dbPort.getValue(); + + if(active.hasArg("db_host")) + Settings.DB_HOST = dbHost.getValue(); + + if(active.hasArg("db_name")) + Settings.DB_NAME = dbName.getValue(); + + if(active.hasArg("db_user")) + { + if(dbUser.getValue().equalsIgnoreCase("NSET\r")) + { + printUsage(); + + log("Argument: --db_user is required"); + System.exit(1); + } + + Settings.DB_USERNAME = dbUser.getValue(); + } + + if(active.hasArg("db_pass")) + { + if(dbPass.getValue().equalsIgnoreCase("NSET\r")) + { + log("Argument: --db_pass is required if the password is not blank"); + Settings.DB_PASSWORD = ""; + }else + Settings.DB_PASSWORD = dbPass.getValue(); + } + + log("Finished parsing command line options"); + + + log("Starting the EventDispatcher"); + EventDispatcher.Reset(); + EventDispatcher.Register(EventHandlers.class); + log("EventDispatcher has been started."); + + log("Port number set to: ", String.valueOf(Settings.PORT_NUMBER)); - log("Data will be loaded/stored in: ", Settings.DATA_DIRECTORY); log("Hashing algorithm set to: ", Settings.HASH_ALGORITHM); + log("Connecting to database..."); + Connection conn = null; + try { + conn = DatabaseConnection.getConnection(); + } catch (SQLException e) { + e.printStackTrace(); + log("\n\n"); + log(Banners.generateBanner("Invalid Credentials or DB Settings")); + System.exit(1); + } + log("Connection established"); + + log("Performing database migrations..."); + try { + Migrations.doMigration(conn); + } catch (SQLException e) { + e.printStackTrace(); + + log(Banners.generateBanner("Critical Failure when creating migrations table")); + System.exit(1); + } + File data = Settings.getDataFolder(); if(!data.exists()) { @@ -125,6 +215,7 @@ public class PlaySyncServer { */ mf.FileHash = Hashing.md5(fullFile); mf.GamePlatform = Platform.Nintendo; + mf.GameName = "Animal Crossing"; DataAccountant.DataTotal = fullFile.length; @@ -145,7 +236,7 @@ public class PlaySyncServer { { try { DataFragment frag = DataFragment.Create(dis); - if(frag.getSize()<1024) + if(frag.getSize()<512) { hasData=false; } @@ -182,7 +273,11 @@ public class PlaySyncServer { for(DataFragment frag : fragments) { - frag.Save(); + ChunksTable chunksTable = (ChunksTable)Migrations.Tables.get(ChunksTable.class); + + chunksTable.setChunk(frag); + + DataAccountant.ChunksWritten++; DataAccountant.ChunksRemain--; DataAccountant.updateCur(DataAccountant.ChunksWritten); diff --git a/server/src/main/java/dev/zontreck/playsync/Settings.java b/server/src/main/java/dev/zontreck/playsync/Settings.java index 37c2df3..b505a3b 100644 --- a/server/src/main/java/dev/zontreck/playsync/Settings.java +++ b/server/src/main/java/dev/zontreck/playsync/Settings.java @@ -9,6 +9,14 @@ public class Settings public static String DATA_DIRECTORY; public static String HASH_ALGORITHM; + public static int DB_PORT; + public static String DB_HOST; + public static String DB_USERNAME; + public static String DB_PASSWORD; + public static String DB_NAME; + + + public static final boolean DEBUG_MODE = true; diff --git a/server/src/main/java/dev/zontreck/playsync/data/DataFragment.java b/server/src/main/java/dev/zontreck/playsync/data/DataFragment.java index aa899c0..082a690 100644 --- a/server/src/main/java/dev/zontreck/playsync/data/DataFragment.java +++ b/server/src/main/java/dev/zontreck/playsync/data/DataFragment.java @@ -2,6 +2,8 @@ package dev.zontreck.playsync.data; import dev.zontreck.ariaslib.util.Hashing; import dev.zontreck.playsync.Settings; +import dev.zontreck.playsync.data.database.Migrations; +import dev.zontreck.playsync.data.database.migrations.ChunksTable; import dev.zontreck.playsync.exceptions.UnsupportedAlgorithmException; import javax.xml.crypto.Data; @@ -13,7 +15,7 @@ import java.nio.file.Path; */ public class DataFragment { - private byte[] data = new byte[1024]; + private byte[] data = new byte[512]; /** * Takes either 1024, or the remaining number of bytes, whichever is less @@ -22,7 +24,7 @@ public class DataFragment */ public static DataFragment Create(DataInputStream dis) throws IOException { DataFragment frag = new DataFragment(); - frag.data = dis.readNBytes(1024); + frag.data = dis.readNBytes(512); return frag; } @@ -30,32 +32,50 @@ public class DataFragment /** * Save the data fragment to its hash ID */ - public void Save() + public byte[] Save() { - Path chunks = Settings.getDataChunksFolder(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + try { - Path chunk = chunks.resolve(getHash() + ".bin"); - if(!chunks.toFile().exists()) chunks.toFile().mkdirs(); - - //DataAccountant.DataWritten += data.length; - if(chunk.toFile().exists()) { + if(((ChunksTable)Migrations.Tables.get(ChunksTable.class)).hasChunk(getHash())) + { DataAccountant.DataSkipped += data.length; - - return; } - DataOutputStream dos = new DataOutputStream(new FileOutputStream(chunk.toFile())); dos.writeInt(getSize()); dos.write(data); dos.close(); } catch (UnsupportedAlgorithmException e) { throw new RuntimeException(e); - } catch (FileNotFoundException e) { - throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } + + return baos.toByteArray(); + } + + /** + * Read from a byte array + * @param array Array to load as a data fragment + * @return The fragment of data + */ + public static DataFragment Read(byte[] array) + { + ByteArrayInputStream bais = new ByteArrayInputStream(array); + DataInputStream dis = new DataInputStream(bais); + + DataFragment fragment = new DataFragment(); + + try { + int count = dis.readInt(); + fragment.data = dis.readNBytes(count); + } catch (IOException e) { + throw new RuntimeException(e); + } + + return fragment; } /** diff --git a/server/src/main/java/dev/zontreck/playsync/data/Manifest.java b/server/src/main/java/dev/zontreck/playsync/data/Manifest.java index eb2a63a..bd403f6 100644 --- a/server/src/main/java/dev/zontreck/playsync/data/Manifest.java +++ b/server/src/main/java/dev/zontreck/playsync/data/Manifest.java @@ -19,6 +19,7 @@ public class Manifest public List Fragments = new ArrayList<>(); public String FileHash = ""; public ID6 GameID; + public String GameName; public Platform GamePlatform = Platform.Unknown; private static final ReentrantReadWriteLock LOCK = new ReentrantReadWriteLock(); @@ -56,6 +57,7 @@ public class Manifest DataOutputStream dos = new DataOutputStream(new FileOutputStream(manifest.toFile())); dos.write(GameID.asBytes()); dos.writeByte(GamePlatform.ordinal()); + dos.writeUTF(GameName); dos.writeInt(Fragments.size()); @@ -91,6 +93,7 @@ public class Manifest ret.GameID = ID6.fromBytes(dis.readNBytes(6)); ret.GamePlatform = Platform.fromByte(dis.readByte()); + ret.GameName = dis.readUTF(); ret.FileHash = hash; int count = dis.readInt(); for(int i=0;i,Migration> Tables = new HashMap<>(); + + + public static void createMigrationsTable(Connection connection) throws SQLException { + String createTableQuery = "CREATE TABLE IF NOT EXISTS " + MIGRATIONS_TABLE_NAME + " (" + + "table_name VARCHAR(255) PRIMARY KEY," + + "version INT NOT NULL" + + ")"; + + try (PreparedStatement statement = connection.prepareStatement(createTableQuery)) { + statement.executeUpdate(); + } + } + + public static int getTableVersion(Connection connection, String tableName) throws SQLException { + String selectQuery = "SELECT version FROM " + MIGRATIONS_TABLE_NAME + " WHERE table_name = ?"; + + try (PreparedStatement statement = connection.prepareStatement(selectQuery)) { + statement.setString(1, tableName); + try (ResultSet resultSet = statement.executeQuery()) { + if (resultSet.next()) { + return resultSet.getInt("version"); + } + } + } + // Default version if not found + return 0; + } + + /** + * Set the table version in the migrations table + * @param connection The DB connection to use + * @param tableName The table name to update + * @param version The new version to store + * @throws SQLException + */ + public static void setTableVersion(Connection connection, String tableName, int version) throws SQLException { + String updateQuery = "INSERT INTO " + MIGRATIONS_TABLE_NAME + " (table_name, version) VALUES (?, ?)" + + " ON DUPLICATE KEY UPDATE version = ?"; + + try (PreparedStatement statement = connection.prepareStatement(updateQuery)) { + statement.setString(1, tableName); + statement.setInt(2, version); + statement.setInt(3, version); + statement.executeUpdate(); + } + } + + public static void doMigration(Connection connection) throws SQLException { + int ver = 0; + try { + ver = getTableVersion(connection, MIGRATIONS_TABLE_NAME); + + }catch(SQLException e) + { + createMigrationsTable(connection); + setTableVersion(connection, MIGRATIONS_TABLE_NAME, 1); + + ver = getTableVersion(connection, MIGRATIONS_TABLE_NAME); + } + if(ver == 0) + { + createMigrationsTable(connection); + + setTableVersion(connection, MIGRATIONS_TABLE_NAME, 1); + } + + switch(ver) + { + default: + { + break; // nothing to do here yet + } + } + + EventDispatcher.Post(new MigrationEvent()); + } + + + /** + * Abstract class defining the functions that will need to be used by any table implementing migrations. + */ + public static abstract class Migration { + + /** + * Gets the name of the table associated with this migration. + * + * @return The name of the table. + */ + public abstract String getTableName(); + + /** + * Creates the table associated with this migration if it doesn't exist. + * + * @param connection The database connection. + * @throws SQLException if a database access error occurs or this method is called on a closed connection. + */ + public abstract void createTable(Connection connection) throws SQLException; + + /** + * Gets the current version of the table from the migrations table. + * + * @return The current version of the table. + * @throws SQLException if a database access error occurs or this method is called on a closed connection. + */ + public int getVersion() throws SQLException { + return Migrations.getTableVersion(DatabaseConnection.getConnection(), getTableName()); + } + + /** + * Sets the version of the table in the migrations table. + * + * @param version The version to set. + * @throws SQLException if a database access error occurs or this method is called on a closed connection. + */ + public void setVersion(int version) throws SQLException { + Migrations.setTableVersion(DatabaseConnection.getConnection(), getTableName(), version); + } + + /** + * This is used for the internal doMigrations function. It should return the current highest migration version for the table + * @return Current highest version + */ + public abstract int getCurrentTableVersion(); + + /** + * Used internally. + *

+ * This function executes migrations to bring the table to the current version. + * @throws SQLException + */ + public void doMigration() throws SQLException + { + int ver = getVersion(); + Connection conn = DatabaseConnection.getConnection(); + + if(ver==0) createTable(conn); + + while(ver < getCurrentTableVersion()) + { + migrate(ver+1); + + System.out.println("Migrate Table [" + getTableName() +"] from version " + ver + " to " + (ver+1)); + ver = getVersion(); + + } + + } + + /** + * Perform a migration specific to the table itself + * @param version + * @throws SQLException + */ + public abstract void migrate(int version) throws SQLException; + } +} \ No newline at end of file diff --git a/server/src/main/java/dev/zontreck/playsync/data/database/migrations/ChunksTable.java b/server/src/main/java/dev/zontreck/playsync/data/database/migrations/ChunksTable.java new file mode 100644 index 0000000..8ebd6dd --- /dev/null +++ b/server/src/main/java/dev/zontreck/playsync/data/database/migrations/ChunksTable.java @@ -0,0 +1,146 @@ +package dev.zontreck.playsync.data.database.migrations; + +import dev.zontreck.playsync.data.DataFragment; +import dev.zontreck.playsync.data.database.DatabaseConnection; +import dev.zontreck.playsync.data.database.Migrations; +import dev.zontreck.playsync.exceptions.UnsupportedAlgorithmException; + +import javax.sql.RowSet; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +public class ChunksTable extends Migrations.Migration { + @Override + public String getTableName() { + return "chunks"; + } + + @Override + public void createTable(Connection connection) throws SQLException { + String sql = "CREATE TABLE `chunks` (" + + " `Hash` varchar(255) NOT NULL," + + " `Data` blob NOT NULL," + + " PRIMARY KEY (`Hash`)," + + " UNIQUE KEY `Hash` (`Hash`)" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci"; + + try (PreparedStatement pstat = connection.prepareStatement(sql)) + { + pstat.executeUpdate(); + } + + setVersion(1); + } + + @Override + public int getCurrentTableVersion() { + return 1; + } + + @Override + public void migrate(int version) throws SQLException { + Connection conn = DatabaseConnection.getConnection(); + + switch(version) + { + case 1: + { + break; + } + } + } + + /** + * Query the database to check if the Chunk exists or not + * @param hash The chunk's hash value + * @return True if the chunk is present in the database + */ + public boolean hasChunk(String hash) + { + String sql = "SELECT * FROM `?`" + + " WHERE Hash='?';"; + + try(PreparedStatement pstat = DatabaseConnection.getConnection().prepareStatement(sql)) + { + pstat.setString(1, getTableName()); + pstat.setString(2, hash); + + ResultSet result = pstat.executeQuery(); + if(result.getRow() == 0 && !result.next()) + { + return false; + } else { + return true; + } + + + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + /** + * Get the chunk if it exists. + *
+ * If the chunk does not exist, returns null, otherwise, never null. + * @param hash The hash to check for + * @see ChunksTable#hasChunk(String) + * @return The deserialied DataFragment + */ + public DataFragment getChunk(String hash) + { + if(!hasChunk(hash)) return null; + String sql = "SELECT Data from `?`" + + " WHERE Hash='?';"; + + try (PreparedStatement pstat = DatabaseConnection.getConnection().prepareStatement(sql)) + { + pstat.setString(1, getTableName()); + pstat.setString(2, hash); + + ResultSet result = pstat.executeQuery(); + if(result.getRow()==0) result.next(); + byte[] blob = result.getBytes("Data"); + + return DataFragment.Read(blob); + + + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + /** + * Insert the data + * @param fragment The fragment to insert + */ + public void setChunk(DataFragment fragment) + { + try { + String hash = fragment.getHash(); + byte[] array = fragment.Save(); + + String sql = "INSERT INTO `?` (Hash, Data) VALUES (" + + "'?', ?" + + ");"; + + try(PreparedStatement pstat = DatabaseConnection.getConnection().prepareStatement(sql)) + { + pstat.setString(1, getTableName()); + pstat.setString(2, hash); + pstat.setBytes(3, array); + + pstat.executeUpdate(); + + } catch (SQLException e) { + throw new RuntimeException(e); + } + + } catch (UnsupportedAlgorithmException e) { + throw new RuntimeException(e); + } + + } +} diff --git a/server/src/main/java/dev/zontreck/playsync/data/database/migrations/ManifestsTable.java b/server/src/main/java/dev/zontreck/playsync/data/database/migrations/ManifestsTable.java new file mode 100644 index 0000000..fb612e3 --- /dev/null +++ b/server/src/main/java/dev/zontreck/playsync/data/database/migrations/ManifestsTable.java @@ -0,0 +1,73 @@ +package dev.zontreck.playsync.data.database.migrations; + +import dev.zontreck.playsync.data.database.DatabaseConnection; +import dev.zontreck.playsync.data.database.Migrations; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; + +public class ManifestsTable extends Migrations.Migration +{ + @Override + public String getTableName() { + return "manifests"; + } + + @Override + public void createTable(Connection connection) throws SQLException { + String sql = "CREATE TABLE `" + getTableName() + "` (" + + " `Name` varchar(255) NOT NULL," + + " `Data` blob NOT NULL," + + " PRIMARY KEY (`Name`)," + + " UNIQUE KEY `Name` (`Name`)" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;"; + + try (PreparedStatement pstat = connection.prepareStatement(sql)) + { + + pstat.executeUpdate(); + } + + setVersion(1); + } + + @Override + public int getCurrentTableVersion() { + return 3; + } + + @Override + public void migrate(int version) throws SQLException { + Connection conn = DatabaseConnection.getConnection(); + switch(version) + { + case 1: + { + String sql = "ALTER TABLE `" + getTableName() + "` " + + "CHANGE `Name` `Hash` VARCHAR(255) " + + "CHARACTER SET utf8mb4 " + + "COLLATE utf8mb4_general_ci NOT NULL;"; + + try(PreparedStatement pstat = conn.prepareStatement(sql)) + { + pstat.executeUpdate(); + } + setVersion(2); + break; + } + case 2: + { + String sql = "ALTER TABLE `manifests` ADD `GameTitle` " + + "VARCHAR(255) NOT NULL AFTER `Hash`; "; + + try(PreparedStatement pstat = conn.prepareStatement(sql)) + { + pstat.executeUpdate(); + } + setVersion(3); + break; + } + } + } +} diff --git a/server/src/main/java/dev/zontreck/playsync/events/EventHandlers.java b/server/src/main/java/dev/zontreck/playsync/events/EventHandlers.java index 7eded8e..4a1d67e 100644 --- a/server/src/main/java/dev/zontreck/playsync/events/EventHandlers.java +++ b/server/src/main/java/dev/zontreck/playsync/events/EventHandlers.java @@ -1,5 +1,34 @@ package dev.zontreck.playsync.events; +import dev.zontreck.ariaslib.util.Maps; +import dev.zontreck.eventsbus.annotations.EventSubscriber; +import dev.zontreck.eventsbus.annotations.SingleshotEvent; +import dev.zontreck.eventsbus.annotations.Subscribe; +import dev.zontreck.playsync.data.database.Migrations; +import dev.zontreck.playsync.data.database.migrations.ChunksTable; +import dev.zontreck.playsync.data.database.migrations.ManifestsTable; +import dev.zontreck.playsync.server.events.MigrationEvent; + +import java.sql.SQLException; + +@EventSubscriber public class EventHandlers { + @Subscribe(allowCancelled = false) + @SingleshotEvent + public static void onMigrations(MigrationEvent event) + { + System.out.println("Performing table migrations..."); + ManifestsTable manifests = new ManifestsTable(); + ChunksTable chunks = new ChunksTable(); + try { + manifests.doMigration(); + chunks.doMigration(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + + Migrations.Tables = Maps.of(new Maps.Entry<>(ManifestsTable.class, manifests), new Maps.Entry<>(ChunksTable.class, chunks)); + System.out.println("Table migrations completed..."); + } } diff --git a/server/src/main/java/dev/zontreck/playsync/server/events/HTTPRequestEvent.java b/server/src/main/java/dev/zontreck/playsync/server/events/HTTPRequestEvent.java index 98ec38b..e6e6ecc 100644 --- a/server/src/main/java/dev/zontreck/playsync/server/events/HTTPRequestEvent.java +++ b/server/src/main/java/dev/zontreck/playsync/server/events/HTTPRequestEvent.java @@ -1,8 +1,7 @@ package dev.zontreck.playsync.server.events; -import dev.zontreck.ariaslib.util.Lists; -import dev.zontreck.eventsbus.Cancellable; import dev.zontreck.eventsbus.Event; +import dev.zontreck.eventsbus.annotations.Cancellable; import dev.zontreck.playsync.exceptions.HTTPResponseLockedException; import dev.zontreck.playsync.server.HTTPResponseData; diff --git a/server/src/main/java/dev/zontreck/playsync/server/events/MigrationEvent.java b/server/src/main/java/dev/zontreck/playsync/server/events/MigrationEvent.java new file mode 100644 index 0000000..942a151 --- /dev/null +++ b/server/src/main/java/dev/zontreck/playsync/server/events/MigrationEvent.java @@ -0,0 +1,7 @@ +package dev.zontreck.playsync.server.events; + +import dev.zontreck.eventsbus.Event; + +public class MigrationEvent extends Event +{ +}