/* * This file is part of FTB Launcher. * * Copyright © 2012-2016, FTB Launcher Contributors <https://github.com/Slowpoke101/FTBLaunch/> * FTB Launcher is licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.ftb.tools; import static com.google.common.net.HttpHeaders.CACHE_CONTROL; import static net.ftb.download.Locations.MODPACKS; import static net.ftb.download.Locations.PRIVATEPACKS; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.concurrent.ExecutionException; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.border.EmptyBorder; import net.ftb.data.ModPack; import net.ftb.data.Settings; import net.ftb.gui.LaunchFrame; import net.ftb.gui.dialogs.ModpackUpdateDialog; import net.ftb.log.Logger; import net.ftb.util.AppUtils; import net.ftb.util.DownloadUtils; import net.ftb.util.ErrorUtils; import net.ftb.util.FTBFileUtils; import net.ftb.util.ModPackUtil; import net.ftb.util.OSUtils; import net.ftb.util.TrackerUtils; @SuppressWarnings("serial") public class ModManager extends JDialog { public static boolean update = false, backupCFG = false, backupSave = false, erroneous = false, upToDate = false; private static String curVersion = ""; private JPanel contentPane; private double downloadedPerc; private final JProgressBar progressBar; private final JLabel label; private static String sep = File.separator; public static ModManagerWorker worker; private static File baseDynamic; public class ModManagerWorker extends SwingWorker<Boolean, Void> { @Override protected Boolean doInBackground () { try { if (!upToDate()) { String installPath = OSUtils.getCacheStorageLocation(); ModPack pack = ModPack.getSelectedPack(); pack.setUpdated(true); File modPackZip = new File(installPath, "ModPacks" + sep + pack.getDir() + sep + pack.getUrl()); if (modPackZip.exists()) { FTBFileUtils.delete(modPackZip); // Also clear out the "default mods" cache entry, if any, to force it to update when next requested ModPackUtil.clearDefaultModFiles(pack); } File animationGif = new File(OSUtils.getCacheStorageLocation(), "ModPacks" + sep + pack.getDir() + sep + pack.getAnimation()); if (animationGif.exists()) { FTBFileUtils.delete(animationGif); } String dynamicLoc = OSUtils.getCacheStorageLocation(); baseDynamic = new File(dynamicLoc, "ModPacks" + sep + pack.getDir() + sep); // clearModsFolder(pack); erroneous = !downloadModPack(pack.getUrl(), pack.getDir()); } } catch (IOException e) { Logger.logError("Error while updating modpack", e); } return true; } public String downloadUrl (String filename, String urlString) throws Exception { boolean failed = false; BufferedInputStream in = null; FileOutputStream fout; HttpURLConnection connection = null; String md5 = ""; int amount = 0, startAmount = -1, modPackSize = 0, count, steps = 0; int retryCount = 5; try { fout = new FileOutputStream(filename); } catch (IOException e) { Logger.logError("Failed opening output file: " + filename, e); return null; } do { try { failed = false; startAmount = amount; if (amount > 0) { Logger.logInfo("Resuming download from offset " + Integer.toString(amount)); } URL url_ = new URL(urlString); byte data[] = new byte[1024]; SwingUtilities.invokeLater(new Runnable() { public void run () { progressBar.setMaximum(10000); } }); connection = (HttpURLConnection)url_.openConnection(); connection.setRequestProperty(CACHE_CONTROL, "no-transform"); connection.setAllowUserInteraction(true); connection.setConnectTimeout(14000); connection.setReadTimeout(20000); if (amount > 0) { connection.setRequestProperty("Range", "bytes=" + amount + "-"); } connection.connect(); md5 = AppUtils.downloadString(new URL("http://ftnt.fr.nf/MD5/" + ModPack.getSelectedPack().getDir() + "/" + curVersion + ".md5")); in = new BufferedInputStream(connection.getInputStream()); if (modPackSize == 0) { modPackSize = connection.getContentLength(); } else { if (amount + connection.getContentLength() != modPackSize) { throw new IOException("Resume failed"); } else { Logger.logInfo("Resume started sucessfully"); } } while ((count = in.read(data, 0, 1024)) != -1) { fout.write(data, 0, count); if (count > 0) { retryCount = 5; } downloadedPerc += (count * 1.0 / modPackSize) * 100; amount += count; steps++; if (steps > 100) { steps = 0; final String txt = (amount / 1024) + "Kb / " + (modPackSize / 1024) + "Kb"; final int perc = (int)downloadedPerc * 100; SwingUtilities.invokeLater(new Runnable() { public void run () { progressBar.setValue(perc); label.setText(txt); } }); } } } catch (MalformedURLException e) { Logger.logError("Error while downloading modpack", e); failed = true; } catch (IOException e) { Logger.logError("Error while downloading modpack", e); failed = true; } try { if (in != null) { in.close(); } if (connection != null) { connection.disconnect(); } } catch (IOException e) { Logger.logWarn("Error while downloading modpack", e); } } while (amount < modPackSize && (amount > startAmount || retryCount-- > 0)); try { if (fout != null) { fout.flush(); fout.close(); } } catch (IOException e) { Logger.logWarn("Error while downloading modpack", e); } if (failed) { throw new Exception("Modpack download failed"); } return md5; } protected boolean downloadModPack (String modPackName, String dir) { Logger.logInfo("Downloading Mod Pack"); TrackerUtils.sendPageView("net/ftb/tools/ModManager.java", "Modpacks / " + modPackName + " / " + curVersion.replace('_', '.')); String dynamicLoc = OSUtils.getCacheStorageLocation(); String installPath = Settings.getSettings().getInstallPath(); ModPack pack = ModPack.getSelectedPack(); // clearModsFolder(pack); String baseLink = (pack.isPrivatePack() ? PRIVATEPACKS + dir + "/" + curVersion + "/" : MODPACKS + dir + "/" + curVersion + "/"); baseDynamic = new File(dynamicLoc, "ModPacks" + sep + dir + sep); Logger.logDebug("pack dir: " + dir); Logger.logDebug("dynamicLoc: " + dynamicLoc); Logger.logDebug("installPath: " + installPath); Logger.logDebug("baseLink: " + baseLink); baseDynamic.mkdirs(); String md5 = ""; try { File packFile = new File(baseDynamic, modPackName); if (!dir.equals("mojang_vanilla") && (!packFile.exists() || !DownloadUtils.backupIsValid(packFile, baseLink + modPackName))) { try { new File(baseDynamic, modPackName).createNewFile(); md5 = downloadUrl(baseDynamic.getPath() + sep + modPackName, DownloadUtils.getCreeperhostLink(baseLink + modPackName)); } catch (IOException e) { Logger.logWarn("Error while downloading modpack", e); } String animation = pack.getAnimation(); File animationFile = new File(baseDynamic.getPath() + sep + animation); if (!animation.equalsIgnoreCase("empty") && !animationFile.exists()) { downloadUrl(baseDynamic.getPath() + sep + animation, DownloadUtils.getCreeperhostLink(baseLink + animation)); } } } catch (Exception e) { ErrorUtils.tossError("Error while downloading modpack", e); return false; } try { if (!dir.equals("mojang_vanilla") && ((md5 == null || md5.isEmpty()) ? DownloadUtils.backupIsValid(new File(baseDynamic, modPackName), baseLink + modPackName) : DownloadUtils.isValid(new File(baseDynamic, modPackName), md5))) { Logger.logDebug("Extracting pack."); Logger.logDebug("Purging mods, coremods, instMods"); clearModsFolder(pack); FTBFileUtils.delete(new File(installPath, dir + "/minecraft/coremods")); FTBFileUtils.delete(new File(installPath, dir + "/instMods/")); boolean saveExists = false; if (pack.getBundledMap()) { try { if (new File(installPath, dir + "/minecraft/saves").exists()) { saveExists = true; FTBFileUtils.delete(new File(installPath, dir + "/minecraft/saves.ftbtmp")); FTBFileUtils.copyFolder(new File(installPath, dir + "/minecraft/saves"), new File(installPath, dir + "/minecraft/saves.ftbtmp"), true); } } catch (Exception e) { Logger.logError("error backing up map", e); } } Logger.logDebug("Extracting pack."); if (!FTBFileUtils.extractZipTo(baseDynamic.getPath() + sep + modPackName, baseDynamic.getPath())) { ErrorUtils.tossError("Error unzipping modpack!!!"); return false; } if (pack.getBundledMap() && saveExists) { try { if (new File(installPath, dir + "/minecraft/saves").exists() && new File(installPath, dir + "/minecraft/saves.ftbtmp").exists()) { FTBFileUtils.delete(new File(installPath, dir + "/minecraft/saves")); } if (new File(installPath, dir + "/minecraft/saves.ftbtmp").exists()) { FTBFileUtils.copyFolder(new File(installPath, dir + "/minecraft/saves.ftbtmp"), new File(installPath, dir + "/minecraft/saves"), true); FTBFileUtils.delete(new File(installPath, dir + "/minecraft/saves.ftbtmp")); } } catch (Exception e) { Logger.logError("error restoring map", e); } } File version = new File(installPath, dir + sep + "version"); BufferedWriter out = new BufferedWriter(new FileWriter(version)); out.write(curVersion.replace("_", ".")); out.flush(); out.close(); Logger.logDebug("Pack extracted, version tagged."); return true; } else if (!dir.equals("mojang_vanilla")) { ErrorUtils.tossError("Error downloading modpack!!!"); return false; } else { File version = new File(installPath, dir + sep + "version"); BufferedWriter out = new BufferedWriter(new FileWriter(version)); out.write(curVersion.replace("_", ".")); out.flush(); out.close(); Logger.logDebug("Vanilla version tagged."); return true; } } catch (IOException e) { Logger.logError("Error while extracting modpack", e); } return false; } } /** * Create the frame. */ public ModManager (JFrame owner, Boolean model) { super(owner, model); setResizable(false); setTitle("Downloading..."); setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); setBounds(100, 100, 313, 138); contentPane = new JPanel(); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); setContentPane(contentPane); contentPane.setLayout(null); progressBar = new JProgressBar(); progressBar.setBounds(10, 63, 278, 22); contentPane.add(progressBar); JLabel lblDownloadingModPack = new JLabel("<html><body><center>Downloading mod pack...<br/>Please Wait</center></body></html>"); lblDownloadingModPack.setHorizontalAlignment(SwingConstants.CENTER); lblDownloadingModPack.setBounds(0, 5, 313, 30); contentPane.add(lblDownloadingModPack); label = new JLabel(""); label.setHorizontalAlignment(SwingConstants.CENTER); label.setBounds(0, 42, 313, 14); contentPane.add(label); addWindowListener(new WindowAdapter() { @Override public void windowOpened (WindowEvent arg0) { worker = new ModManagerWorker() { @Override protected void done () { try { get(); } catch (InterruptedException e) { Logger.logDebug("Swingworker Exception", e); } catch (ExecutionException e) { Logger.logDebug("Swingworker Exception", e.getCause()); } setVisible(false); super.done(); } }; worker.execute(); } }); } private boolean upToDate () throws IOException { ModPack pack = ModPack.getSelectedPack(); File version = new File(Settings.getSettings().getInstallPath(), pack.getDir() + sep + "version"); if (!version.exists()) { version.getParentFile().mkdirs(); version.createNewFile(); curVersion = (Settings.getSettings().getPackVer().equalsIgnoreCase("recommended version") ? pack.getVersion() : Settings.getSettings().getPackVer()).replace(".", "_"); return false; } BufferedReader in = new BufferedReader(new FileReader(version)); String line = in.readLine(); in.close(); int currentVersion, requestedVersion; currentVersion = (line != null) ? Integer.parseInt(line.replace(".", "")) : 0; if (!Settings.getSettings().getPackVer().equalsIgnoreCase("recommended version") && !Settings.getSettings().getPackVer().equalsIgnoreCase("newest version")) { requestedVersion = Integer.parseInt(Settings.getSettings().getPackVer().trim().replace(".", "")); if (requestedVersion != currentVersion) { Logger.logInfo("Modpack is out of date."); curVersion = (Settings.getSettings().getPackVer().equalsIgnoreCase("recommended version") ? pack.getVersion() : Settings.getSettings().getPackVer()).replace(".", "_"); return false; } else { Logger.logInfo("Modpack is up to date."); return true; } } else if (Integer.parseInt(pack.getVersion().replace(".", "")) != currentVersion) { Logger.logInfo("Modpack is out of date."); if (LaunchFrame.allowVersionChange) { curVersion = (Settings.getSettings().getPackVer().equalsIgnoreCase("recommended version") ? pack.getVersion().replace(".", "_") : Settings.getSettings().getPackVer()).replace(".", "_"); return false; } ModpackUpdateDialog p = new ModpackUpdateDialog(LaunchFrame.getInstance(), true); p.setVisible(true); if (!update) { return true; } if (backupCFG) { File destination = new File(OSUtils.getCacheStorageLocation(), "backups" + sep + pack.getDir() + sep + "config_backup"); if (destination.exists()) { FTBFileUtils.delete(destination); } FTBFileUtils.copyFolder(new File(Settings.getSettings().getInstallPath(), pack.getDir() + sep + "minecraft" + sep + "config"), destination); } if (backupSave) { File destination = new File(OSUtils.getCacheStorageLocation(), "backups" + sep + pack.getDir() + sep + "saves_backup"); if (destination.exists()) { FTBFileUtils.delete(destination); } FTBFileUtils.copyFolder(new File(Settings.getSettings().getInstallPath(), pack.getDir() + sep + "minecraft" + sep + "saves"), destination); } curVersion = pack.getVersion().replace(".", "_"); return false; } else { Logger.logInfo("Modpack is up to date."); return true; } } public static void cleanUp () { ModPack pack = ModPack.getSelectedPack(); File tempFolder = new File(OSUtils.getCacheStorageLocation(), "ModPacks" + sep + pack.getDir() + sep); for(String file : tempFolder.list()) { if (!file.equals(pack.getLogoName()) && !file.equals(pack.getImageName()) && !file.equals("version") && !file.equals(pack.getAnimation())) { try { if (file.endsWith(".zip")) { Logger.logDebug("retaining modpack file: " + tempFolder + File.separator + file); } else { FTBFileUtils.delete(new File(tempFolder, file)); } } catch (IOException e) { Logger.logError(e.getMessage(), e); } } } } public static void clearModsFolder (ModPack pack) { File modsFolder = new File(Settings.getSettings().getInstallPath(), pack.getDir() + File.separator + "minecraft" + File.separator + "mods"); clearFolder(modsFolder); Logger.logInfo("Mods Folder: " + modsFolder.toString()); File dyn = new File(baseDynamic.getPath(), "minecraft" + File.separator + "mods"); Logger.logInfo("Dynamic Folder: " + dyn); clearFolder(dyn); } public static void clearFolder (File folder) { if (folder.exists()) { for(String file : folder.list()) { if (new File(folder, file).isDirectory()) { clearFolder(new File(folder, file)); } if (file.toLowerCase().endsWith(".zip") || file.toLowerCase().endsWith(".jar") || file.toLowerCase().endsWith(".disabled") || file.toLowerCase().endsWith(".litemod")) { try { boolean b = FTBFileUtils.delete(new File(folder, file)); if (!b) { Logger.logInfo("Error deleting " + file); } } catch (IOException e) { Logger.logWarn(e.getMessage(), e); } } } } } }