From 9da3e668a8f0e2a9b984f45d93fa4f147416bd75 Mon Sep 17 00:00:00 2001 From: marc barbier Date: Thu, 8 Jul 2021 14:23:07 +0200 Subject: [PATCH] refactor global fin a tester --- ...tyChecker.java => CurseUpdateManager.java} | 107 ++++++-------- .../src/downloader/Database.java | 99 ++++--------- .../src/downloader/DirectUpdateManager.java | 31 ++++ ModsListDownloader/src/downloader/Main.java | 6 +- .../src/downloader/ModUpdater.java | 136 ++++++++++++++++++ .../src/downloader/helper/ArchiveHelper.java | 19 +++ .../src/downloader/helper/SlugHelper.java | 16 +++ 7 files changed, 278 insertions(+), 136 deletions(-) rename ModsListDownloader/src/downloader/{IntegrityChecker.java => CurseUpdateManager.java} (61%) create mode 100644 ModsListDownloader/src/downloader/DirectUpdateManager.java create mode 100644 ModsListDownloader/src/downloader/ModUpdater.java create mode 100644 ModsListDownloader/src/downloader/helper/SlugHelper.java diff --git a/ModsListDownloader/src/downloader/IntegrityChecker.java b/ModsListDownloader/src/downloader/CurseUpdateManager.java similarity index 61% rename from ModsListDownloader/src/downloader/IntegrityChecker.java rename to ModsListDownloader/src/downloader/CurseUpdateManager.java index eb8a578..07f19db 100644 --- a/ModsListDownloader/src/downloader/IntegrityChecker.java +++ b/ModsListDownloader/src/downloader/CurseUpdateManager.java @@ -8,51 +8,39 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.SortedMap; import java.util.TreeMap; -import java.util.zip.ZipFile; -public class IntegrityChecker { - public String[] fileList; - public SortedMap installedMods; - public File modsMap; +import downloader.helper.ArchiveHelper; +import downloader.helper.SlugHelper; + +public class CurseUpdateManager { + private SortedMap installedMods; - @SuppressWarnings("unchecked") - public IntegrityChecker() + public CurseUpdateManager() { - fileList = new File("mods").list(); - modsMap = new File("mods/modsMap.sav"); - if(modsMap.exists()) - { - try { - ObjectInputStream ois = new ObjectInputStream(new FileInputStream(modsMap)); - installedMods = (SortedMap) ois.readObject(); - if(installedMods == null)installedMods = new TreeMap<>(); - ois.close(); - } catch (Exception e) { - installedMods = new TreeMap<>(); - modsMap.delete(); - } - }else { - try { - modsMap.createNewFile(); - } catch (IOException e) { - e.printStackTrace(); - } - } - try { - ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(modsMap)); - oos.writeObject(installedMods); - oos.close(); - } catch (IOException e) { - Log.e("SAV", "erreur pas de sauvegarde"); - System.exit(1); - } + loadModMapFromFile(); } + @SuppressWarnings("unchecked") + private void loadModMapFromFile() { + File modsMapFile = new File("mods/modsMap.sav"); + if(modsMapFile.exists()) + { + try { + ObjectInputStream ois = new ObjectInputStream(new FileInputStream(modsMapFile)); + installedMods = (SortedMap) ois.readObject(); + ois.close(); + } catch (Exception e) { + modsMapFile.delete(); + } + if(installedMods == null)installedMods = new TreeMap<>(); + } + this.updateFile(); + } + public boolean checkAndDelete(File modToDownload, int modid) { String alredyInstalledName = installedMods.get(modid).toLowerCase(); File alredyInstalledMods= null; - //on cherche le fichier local affin de ne pas voir d'erreur avec la casse File dir = new File("mods/"); for(String fileName : dir.list()) @@ -60,8 +48,10 @@ public class IntegrityChecker { if(fileName.equalsIgnoreCase(alredyInstalledName)) { alredyInstalledMods = new File("mods/"+fileName); + break; } } + if(alredyInstalledMods == null) { Log.e("IntegrityChecker", "alredy installed mod not found ("+alredyInstalledName+")"); installedMods.remove(modid); @@ -70,16 +60,14 @@ public class IntegrityChecker { } if (alredyInstalledMods.exists()) { - try { - //si sa balance une exception sa veut dire que le jar n'est pas lisible - new ZipFile(alredyInstalledMods).close(); - } catch (IOException e) { - Log.i("integrityChecker","Corruption detected redownloading"); + //we only check if the jar file still works + if(ArchiveHelper.checkJarIntegrity(alredyInstalledMods)) { alredyInstalledMods.delete(); installedMods.remove(modid); updateFile(); return false; } + if(!modToDownload.getAbsolutePath().equalsIgnoreCase(alredyInstalledMods.getAbsolutePath())) { alredyInstalledMods.delete(); @@ -94,37 +82,25 @@ public class IntegrityChecker { { installedMods.put(modid, modToDownload.getName()); updateFile(); - Log.i("interessting", modToDownload.getName()); + Log.i("CurseUpdater","existing file detected adding it to the register: " + modToDownload.getName()); + return true; } } return false; } - + /** + * @return true == file ok + */ public boolean checkAndDelete(File modToDownload, String slug) { if (modToDownload.exists()) { - try { - //si sa balance une exception sa veut dire que le jar n'est pas lisible - new ZipFile(modToDownload).close(); - } catch (IOException e) { - Log.i("integrityChecker","Corruption detected redownloading"); - modToDownload.delete(); + if (ArchiveHelper.checkJarIntegrity(modToDownload)) { + return true; + } else { + SlugHelper.deleteBySlug(slug); return false; } - - for (String s : fileList) { - if (s.contains(slug)) { - if (!modToDownload.getName().contains(s)) { - new File(s).delete(); - Log.i("integrityChecker","Corruption detected redownloading"); - return false; - } - return true; - } - } - return false; - } return false; } @@ -147,12 +123,15 @@ public class IntegrityChecker { private void updateFile() { + File modsMap = new File("mods/modsMap.sav"); try { - modsMap.delete(); + if(modsMap.exists())modsMap.delete(); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(modsMap)); oos.writeObject(installedMods); oos.close(); - } catch (IOException e) {} + } catch (IOException e) { + Log.e("SAV", "erreur pas de sauvegarde"); + } } } diff --git a/ModsListDownloader/src/downloader/Database.java b/ModsListDownloader/src/downloader/Database.java index 9b8987f..10b6a35 100644 --- a/ModsListDownloader/src/downloader/Database.java +++ b/ModsListDownloader/src/downloader/Database.java @@ -4,6 +4,7 @@ import java.io.File; import java.net.MalformedURLException; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.Arrays; import com.google.gson.Gson; @@ -13,7 +14,6 @@ import downloader.helper.HttpHelper; public class Database { DBConnector connector; - IntegrityChecker integrityChecker; Gson gson; @@ -25,18 +25,15 @@ public class Database { //database hs System.exit(1); } - - integrityChecker = new IntegrityChecker(); this.gson = new Gson(); } private int findProjectBySlug(String slug, int ptype) { - int modID = -1; - ResultSet rs = this.connector.executeRequest("select projectid from projects where type =" + ptype + " and slug =\"" + - slug.trim().toLowerCase() + "\""); + int pjId = -1; + ResultSet rs = this.connector.executeRequest("select projectid from projects where type =" + ptype + " and slug LIKE \"%" + slug.trim().toLowerCase() + "\"%"); try { if (rs.next()) { - modID = rs.getInt("projectid"); + pjId = rs.getInt("projectid"); } else { Log.e("DB", "not found " + slug); return -1; @@ -45,14 +42,14 @@ public class Database { e.printStackTrace(); return -1; } - return modID; + return pjId; } - private int findModBySlug(String slug) { + public int findModBySlug(String slug) { return findProjectBySlug(slug, 0); } - private ProjectInfo getProjectInfo(int projectId) { + public ProjectInfo getProjectInfo(int projectId) { ResultSet rs = this.connector.executeRequest( "select slug, name, description from projects where projectid = " + projectId + " and type = 0"); try { @@ -62,59 +59,14 @@ public class Database { return null; } - public boolean fetchMod(String string) { - String name = string.split("/")[5]; - int modID = findModBySlug(name); - if (modID == -1) { - Log.e("DB", "could not find mod id"); - return false; - } - ProjectInfo pj = getProjectInfo(modID); - if (pj == null) - return false; + public ForgeSvcFile fetchMod(ProjectInfo pj, int modID) { CurseForgeModFile modfile = new CurseForgeModFile(pj, modID, -1, false); - ForgeSvcFile file = getLastestFile("1.12.2", modfile); - if (file != null) { - try { - boolean upToDate; - String downloadUrl = file.getDownloadUrl(modID); - if (Main.verbose) - Log.i("MOD", "checking " + pj.getName().replace(" ", "-")); - if (this.integrityChecker.isModIdKnown(modID)) { - if (Main.verbose) - Log.i("DB", "found " + name); - upToDate = this.integrityChecker - .checkAndDelete(new File("mods/" + HttpHelper.getFileNameFromURL(downloadUrl)), modID); - } else { - Log.i("DB", "NEW MOD DETECTED " + modID); - upToDate = this.integrityChecker.checkAndDelete( - new File("mods/" + HttpHelper.getFileNameFromURL(downloadUrl)), pj.getSlug()); - } - if (!upToDate) { - if (Main.verbose) - Log.i("MOD", "downloading " + pj.getName().replace(" ", "-")); - if (!Main.checkingonly) - HttpHelper.readFileFromUrlToFolder(downloadUrl, "mods"); - if (Main.verbose) - Log.i("MOD", "download finished"); - if (!this.integrityChecker.isModIdKnown(modID) && !Main.checkingonly) { - this.integrityChecker.addModsToTheList(HttpHelper.getFileNameFromURL(downloadUrl), modID); - if (Main.verbose) - Log.i("DB", "added a mod to the registry"); - } - } - return true; - } catch (MalformedURLException e) { - e.printStackTrace(); - } - } else { - Log.e("DB", "no file in server"); - } - return false; + return getLastestFile(modfile); } - public ForgeSvcFile getLastestFile(String minecraftVer, CurseForgeModFile mod) { - String jsonProject, projectUrl = "https://addons-ecs.forgesvc.net/api/v2/addon/" + mod.getProjectID(); + public ForgeSvcFile getLastestFile(CurseForgeModFile mod) { + String jsonProject; + String projectUrl = "https://addons-ecs.forgesvc.net/api/v2/addon/" + mod.getProjectID(); try { jsonProject = HttpHelper.readStringFromUrl(projectUrl); if (jsonProject.equals("error")) @@ -123,16 +75,23 @@ public class Database { e.printStackTrace(); return null; } - ForgeSvcEntry entry = (ForgeSvcEntry)this.gson.fromJson(jsonProject, ForgeSvcEntry.class); - byte b; - int i; - ForgeSvcFile[] arrayOfForgeSvcFile; - for (i = (arrayOfForgeSvcFile = entry.getFiles()).length, b = 0; b < i; ) { - ForgeSvcFile f = arrayOfForgeSvcFile[b]; - if (f.getGameVersion().equals(minecraftVer)) - return f; - b++; + ForgeSvcEntry entry = this.gson.fromJson(jsonProject, ForgeSvcEntry.class); + ForgeSvcFile[] arrayOfForgeSvcFile = fileterGameVersion(entry.getFiles()); + + + if(arrayOfForgeSvcFile.length == 0) return null; + + //on par du pricipe qu'un id plus élevé => version plus récente + ForgeSvcFile latest = arrayOfForgeSvcFile[0]; + for (int i = 1; i < arrayOfForgeSvcFile.length; i++) { + if( arrayOfForgeSvcFile[i].getProjectFileId() > latest.getProjectFileId() ) { + latest = arrayOfForgeSvcFile[i]; + } } - return null; + return latest; + } + + private ForgeSvcFile[] fileterGameVersion(ForgeSvcFile[] arrayOfForgeSvcFile) { + return Arrays.stream(arrayOfForgeSvcFile).filter(x -> x.getGameVersion().equals(Main.mcVersion)).toArray(ForgeSvcFile[]::new); } } diff --git a/ModsListDownloader/src/downloader/DirectUpdateManager.java b/ModsListDownloader/src/downloader/DirectUpdateManager.java new file mode 100644 index 0000000..8575e61 --- /dev/null +++ b/ModsListDownloader/src/downloader/DirectUpdateManager.java @@ -0,0 +1,31 @@ +package downloader; + +import java.io.File; + +import downloader.helper.ArchiveHelper; +import downloader.helper.SlugHelper; + +public class DirectUpdateManager { + + /** + * @param filename + * @param slug + * @return upToDate + */ + public boolean checkAndDelete(String filename, String slug) { + File mod = new File("mods/"+filename); + + if (!mod.isFile()) { + mod.delete(); + return false; + } + + if (!mod.exists()) { + SlugHelper.deleteBySlug(slug); + return false; + } else { + return ArchiveHelper.checkJarIntegrity(mod); + } + + } +} diff --git a/ModsListDownloader/src/downloader/Main.java b/ModsListDownloader/src/downloader/Main.java index f0a9503..4b07e7a 100644 --- a/ModsListDownloader/src/downloader/Main.java +++ b/ModsListDownloader/src/downloader/Main.java @@ -12,13 +12,15 @@ public class Main { public static boolean verbose; public static boolean checkingonly; public static Integer threadNb; - private static Database db; + public static String mcVersion; public static void main(String[] args) { + this.mcVersion = "1.12.2"; + checkModsDirectory(); new DatabaseVersionManager().updateIfNeeded(); - db = new Database(); interpretArgs(args); + new ModUpdater().update(); } public static void checkModsDirectory() { diff --git a/ModsListDownloader/src/downloader/ModUpdater.java b/ModsListDownloader/src/downloader/ModUpdater.java new file mode 100644 index 0000000..2380199 --- /dev/null +++ b/ModsListDownloader/src/downloader/ModUpdater.java @@ -0,0 +1,136 @@ +package downloader; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.net.MalformedURLException; + +import downloader.forgeSvc.ForgeSvcFile; +import downloader.helper.HttpHelper; + +public class ModUpdater { + private DirectUpdateManager directUpdateManager; + private CurseUpdateManager curseUpdateManager; + private Database db; + + public ModUpdater() { + this.db = new Database(); + this.directUpdateManager = new DirectUpdateManager(); + this.curseUpdateManager = new CurseUpdateManager(); + } + + public void update() { + File modsList = new File("modpack.txt"); + + if(modsList.exists() && modsList.isFile()) { + Log.e("Updater", "[ERROR]no mod file found exiting..."); + System.exit(1); + } + + //parse and download + try { + BufferedReader in = new BufferedReader(new FileReader(modsList)); + while (in.ready()) { + String line = in.readLine(); + if (!isAComment(line)) { + if(line.startsWith("direct=")) + { + handleDirectDownload(line); + } else if (line.startsWith("del=")) { + String[] delete = line.split("del="); + new File(delete[1]).delete(); + } + else { + if (line.split("/").length >= 5) { + handleCurseDownload(line); + } + } + } + } + in.close(); + Log.i("Main", "finished"); + + } catch( IOException e ) { + e.printStackTrace(); + System.exit(1); + } + } + + public void handleDirectDownload(String line) { + String url = line.replaceFirst("direct=.*@", ""); + String filename=extractNameFromLink(line); + + //le slug est une nom de mods qui se trouve dans le nom du fichier + String slug = extractSlugFromLink(line); + //on check si le mods est pas déja installé et si il est a jours + boolean upToDate = directUpdateManager.checkAndDelete(filename, slug); + if(!upToDate) + { + Log.i("main","downloading "+ filename); + try { + HttpHelper.readFileFromUrlToFolder(url,"mods",filename); + Log.i("main","done"); + } catch (MalformedURLException e) { + Log.e("ModUpdater", "could not update mod, error while downloading"); + } + } + } + + public void handleCurseDownload(String line) { + String name = line.split("/")[5]; + int modID = db.findModBySlug(name); + ProjectInfo pj = db.getProjectInfo(modID); + ForgeSvcFile svc = db.fetchMod(pj, modID); + + if (svc != null) { + try { + boolean upToDate; + String downloadUrl = svc.getDownloadUrl(modID); + + Log.i("MOD", "checking " + pj.getName().replace(" ", "-")); + if (this.curseUpdateManager.isModIdKnown(modID)) { + Log.i("DB", "found " + name); + upToDate = this.curseUpdateManager.checkAndDelete(new File("mods/" + HttpHelper.getFileNameFromURL(downloadUrl)), modID); + } + else { + Log.i("DB", "NEW MOD DETECTED " + modID); + upToDate = this.curseUpdateManager.checkAndDelete(new File("mods/" + HttpHelper.getFileNameFromURL(downloadUrl)), pj.getSlug()); + } + + if (!upToDate) { + Log.i("MOD", "downloading " + pj.getName().replace(" ", "-")); + + HttpHelper.readFileFromUrlToFolder(downloadUrl, "mods"); + + Log.i("MOD", "download finished"); + if (!this.curseUpdateManager.isModIdKnown(modID)) { + this.curseUpdateManager.addModsToTheList(HttpHelper.getFileNameFromURL(downloadUrl), modID); + Log.i("DB", "added a mod to the registry"); + } + } + } catch (MalformedURLException e) { + e.printStackTrace(); + } + } else { + Log.e("DB", "no file in server"); + } + } + + public static boolean isAComment(String line) + { + return line.startsWith("//"); + } + + private static String extractSlugFromLink(String line) { + char[] chars = new char[line.length()-line.indexOf(";")-"direct=".length()+1]; + line.getChars("direct=".length(), line.indexOf(";"), chars, 0); + return new String(chars); + } + + private static String extractNameFromLink(String line) { + char[] chars = new char[line.indexOf("@")-line.indexOf(";")]; + line.getChars(line.indexOf(";")+1, line.indexOf("@"), chars, 0); + return new String(chars); + } +} diff --git a/ModsListDownloader/src/downloader/helper/ArchiveHelper.java b/ModsListDownloader/src/downloader/helper/ArchiveHelper.java index 65934ae..916ad85 100644 --- a/ModsListDownloader/src/downloader/helper/ArchiveHelper.java +++ b/ModsListDownloader/src/downloader/helper/ArchiveHelper.java @@ -5,10 +5,13 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.util.jar.JarFile; import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream; import org.apache.commons.compress.utils.IOUtils; +import downloader.Log; + public class ArchiveHelper { private ArchiveHelper(){} @@ -20,4 +23,20 @@ public class ArchiveHelper { IOUtils.copy(input, output); return decompressedFile; } + + /** + * @param mod + * @return true = fichier bon + */ + public static boolean checkJarIntegrity(File mod) { + try { + //si sa balance une exception sa veut dire que le jar n'est pas lisible + new JarFile(mod).close(); + } catch (IOException e) { + Log.i("integrityChecker","Corruption detected redownloading"); + mod.delete(); + return false; + } + return true; + } } diff --git a/ModsListDownloader/src/downloader/helper/SlugHelper.java b/ModsListDownloader/src/downloader/helper/SlugHelper.java new file mode 100644 index 0000000..9986b4a --- /dev/null +++ b/ModsListDownloader/src/downloader/helper/SlugHelper.java @@ -0,0 +1,16 @@ +package downloader.helper; + +import java.io.File; + +public class SlugHelper { + + public static void deleteBySlug(String slug) { + File modFolder = new File("mods"); + File[] mods = modFolder.listFiles(); + for( File mod : mods) { + if(mod.getName().toLowerCase().contains((slug.toLowerCase()))) { + mod.delete(); + } + } + } +}