diff --git a/Server/src/main/java/net/simon987/server/FileUtils.java b/Server/src/main/java/net/simon987/server/FileUtils.java new file mode 100644 index 0000000..f00684a --- /dev/null +++ b/Server/src/main/java/net/simon987/server/FileUtils.java @@ -0,0 +1,192 @@ +package net.simon987.server; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +public class FileUtils { + + private static final int BUFFER_SIZE = 1024; + private static final String STR_ENCODING = "UTF-8"; + private static final String DATE_FORMAT = "yyyyMMddHHmmss"; + private static final String FILE_TYPE = ".zip"; + private static final Path ROOT_DIR; + private static final String DIR_NAME = "history"; + public static final Path DIR_PATH; + + static { + ROOT_DIR = Paths.get(".").normalize(); + DIR_PATH = ROOT_DIR.resolve(DIR_NAME); + } + + //Private constructor + private FileUtils() { + + } + + /** + * Creates a new stamp containing the current date and time + * + * @return date and time stamp + */ + private static String getDateTimeStamp() { + Date millisToDate = new Date(System.currentTimeMillis()); + SimpleDateFormat f = new SimpleDateFormat(DATE_FORMAT); + return f.format(millisToDate); + } + + /** + * Created a directory if none exists with the specified name + * + * @param name folder to create + * @return true is the file exists or create operation is successful + */ + public static boolean prepDirectory(Path directory) { + File file = directory.toFile(); + + //If the directory exists or the directory created successfully return true + if(file.exists() || file.mkdir()) { + return true; + + } else { + System.out.println("Error creating directory: " + file.toString()); + return false; + } + } + + /** + * Converts a file into an array of bytes + * + * @param fileName the file to be converted into bytes + * @return the byte array of the given file + */ + public static byte[] bytifyFile(Path path) { + byte[] bytes = null; + + try { + bytes = Files.readAllBytes(path); + + } catch (IOException e) { + System.out.println("Failed to extract bytes from: " + path); + e.printStackTrace(); + } + + return bytes; + } + + /** + * Takes in a file that had been converted to a byte[] to be written to a new + * zip file + * + * @param payload + * contains data in byte array form to be written, typically a file + * that has been converted with bytifyFile() + * @throws IOException + * if an error occurs during the write process + */ + public static void writeSaveToZip(String name, byte[] data) throws IOException { + + String newFile = DIR_PATH.resolve(getDateTimeStamp() + FILE_TYPE).toString(); + FileOutputStream output = new FileOutputStream(newFile); + ZipOutputStream stream = new ZipOutputStream(output); + byte[] buffer = new byte[BUFFER_SIZE]; + ByteArrayInputStream bais = new ByteArrayInputStream(buffer); + + while ((bais.read(buffer)) > -1) { + // File name + ZipEntry entry = new ZipEntry(name); + // Set to start of next entry in the stream. + stream.putNextEntry(entry); + // Data to write. + stream.write(data); + // Close the current entry. + stream.closeEntry(); + } + + stream.close(); + output.close(); + } + + public static void cleanHistory(int size) { + + + File[] files = new File(DIR_PATH.toString()).listFiles(); + File[] sorted = new File[size]; + + File nextSortedFile = null; + File currentFile = null; + boolean changed = false; + + for(int i = 0; i < files.length / 2; i++) { + currentFile = files[i]; + files[i] = files[files.length - i - 1]; + files[files.length - i - 1] = currentFile; + } + + currentFile = null; + + for(int f = 0; f < files.length; f++) { + changed = false; + long dirFile = Long.parseLong(files[f].getName().substring(0, (files[f].getName().length() -4))); + + if(f < size && sorted[f] == null) { + sorted[f] = files[f]; + + } else { + + for(int s = 0; s < sorted.length; s++) { + + long sortedFile = Long.parseLong(sorted[s].getName().substring(0, (sorted[s].getName().length() -4))); + + if(dirFile > sortedFile) { + + if(s == sorted.length - 1) { + sorted[s] = files[f]; + + } else if(nextSortedFile == null) { + nextSortedFile = sorted[s]; + sorted[s] = files[f]; + + } else { + currentFile = sorted[s]; + sorted[s] = nextSortedFile; + nextSortedFile = currentFile; + } + + nextSortedFile = null; + currentFile = null; + changed = true; + } + } + + if(changed == false) { + files[f].delete(); + } + + } + } + + } + + /** + * Converts a byte array into human readable format using the provided encoding + * + * @param bytes + * data to be encoded to String + * @return a String containing the encoded bytes + */ + public static String byteArrAsString(byte[] bytes) throws UnsupportedEncodingException { + return new String(bytes, STR_ENCODING); + } +} diff --git a/Server/src/main/java/net/simon987/server/GameServer.java b/Server/src/main/java/net/simon987/server/GameServer.java index 68fcd24..03effd9 100644 --- a/Server/src/main/java/net/simon987/server/GameServer.java +++ b/Server/src/main/java/net/simon987/server/GameServer.java @@ -22,8 +22,9 @@ import java.util.ArrayList; public class GameServer implements Runnable { public final static GameServer INSTANCE = new GameServer(); - - private GameUniverse gameUniverse; + private final static String SAVE_JSON = "save.json"; + + private GameUniverse gameUniverse; private GameEventDispatcher eventDispatcher; private PluginManager pluginManager; @@ -146,6 +147,11 @@ public class GameServer implements Runnable { if (gameUniverse.getTime() % config.getInt("save_interval") == 0) { save(new File("save.json")); } + + // Clean up history files + if(gameUniverse.getTime() % config.getInt("clean_interval") == 0) { + FileUtils.cleanHistory(config.getInt("history_size")); + } socketServer.tick(); @@ -159,6 +165,18 @@ public class GameServer implements Runnable { */ public void save(File file) { + boolean dirExists = FileUtils.prepDirectory(FileUtils.DIR_PATH); + + if (new File(new File(SAVE_JSON).getAbsolutePath()).exists() && dirExists) { + byte[] data = FileUtils.bytifyFile(new File(SAVE_JSON).toPath()); + try { + FileUtils.writeSaveToZip(SAVE_JSON, data); + } catch (IOException e) { + System.out.println("Failed to write " + SAVE_JSON + " to zip file"); + e.printStackTrace(); + } + } + try { FileWriter fileWriter = new FileWriter(file); diff --git a/config.properties b/config.properties index ba20075..56d4be3 100644 --- a/config.properties +++ b/config.properties @@ -4,7 +4,10 @@ mysql_user=mar mysql_pass=mar # MySQL address mysql_url=jdbc:mysql://localhost:3306/mar?useSSL=false +# File management save_interval=5 +clean_interval=10 +history_size=10 # Web server port webSocket_port=8887 webSocket_host=0.0.0.0