/* * 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.workers; import static net.ftb.download.Locations.MODPACKXML; import static net.ftb.download.Locations.THIRDPARTYXML; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import com.google.common.collect.Lists; import net.ftb.data.ModPack; import net.ftb.data.Settings; import net.ftb.gui.LaunchFrame; import net.ftb.log.Logger; import net.ftb.util.AppUtils; import net.ftb.util.Benchmark; import net.ftb.util.DownloadUtils; import net.ftb.util.OSUtils; public class ModpackLoader extends Thread { private ArrayList<String> xmlFiles = Lists.newArrayList(); private boolean disableOtherLoader = false; private static int offset = 0; public ModpackLoader (ArrayList<String> xmlFiles, boolean disableOtherLoaders) { this.xmlFiles = xmlFiles; this.disableOtherLoader = disableOtherLoaders; } @Override public void run () { Benchmark.start("ModpackLoader"); ExecutorService executor = new ThreadPoolExecutor(4, 4, 5L, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(8), new ThreadPoolExecutor.CallerRunsPolicy()); for(String xmlFile : xmlFiles) { executor.submit(new XmlHtmlRunnable(xmlFile, offset)); offset = offset + 100; } executor.shutdown(); try { // 256 kbps connection speed uses ~280 seconds. Double that and warn user if initial pack data download fails if (!executor.awaitTermination(10 * 60, TimeUnit.SECONDS)) { Logger.logWarn("Impartial Modpack information. Please restart launcher to continue download"); } } catch (InterruptedException e) { Logger.logError("failed", e); } // everything added sort packs ModPack.sortPacks(); Benchmark.logBenchAs("ModpackLoader", "All modpack lists loaded"); LaunchFrame.checkDoneLoading(); } private class XmlHtmlRunnable implements Runnable { private String xmlFile; private int offset; public XmlHtmlRunnable (String xmlFile, int offset) { this.xmlFile = xmlFile; this.offset = offset; } @Override public void run () { handleXML(xmlFile, offset); } private void handleXML (String xmlFile, int offset) { boolean privatePack = !xmlFile.equalsIgnoreCase(MODPACKXML) && !xmlFile.equalsIgnoreCase(THIRDPARTYXML);// this is for stuff that is stored under privatepacks on the repo boolean isThirdParty = !xmlFile.equalsIgnoreCase(THIRDPARTYXML); File modPackFile = new File(OSUtils.getCacheStorageLocation(), "ModPacks" + File.separator + xmlFile); try { modPackFile.getParentFile().mkdirs(); String s = DownloadUtils.getStaticCreeperhostLink(xmlFile); DownloadUtils.downloadToFile(new URL(s), modPackFile); Benchmark.logBenchAs("ModpackLoader", "Modpack Loader " + s.replace(".creeperrepo.net/FTB2/static", "").replace(".cursecdn.com/FTB2/static", "")); } catch (IOException e) { Logger.logWarn("Failed to load modpacks, loading from backup", e); } Logger.logInfo("Loading modpack information for " + xmlFile + "..."); InputStream modPackStream = null; try { modPackStream = new FileInputStream(modPackFile); if (Settings.getSettings().getDebugLauncher()) { Logger.logDebug(xmlFile + " MD5: " + DownloadUtils.fileMD5(modPackFile) + " Size: " + modPackFile.length()); } } catch (IOException e) { Logger.logWarn("Failed to read modpack file - falling back to direct download", e); } if (modPackStream == null) { try { modPackStream = new URL(DownloadUtils.getStaticCreeperhostLink(xmlFile)).openStream(); } catch (IOException e) { Logger.logError("Completely unable to download the modpack file - check your connection", e); } } if (modPackStream != null) { Document doc; try { doc = AppUtils.getXML(modPackStream); } catch (Exception e) { Logger.logError("Exception reading modpack file", e); return; } if (doc == null) { Logger.logError("Error: could not load modpack data!"); return; } NodeList modPacks = doc.getElementsByTagName("modpack"); ArrayList<ModPack> mp = Lists.newArrayList(); // ATT: this is not thread safe. Only one thread can run rest of the code! // proper fix: ModPack.add() should assign indexes for modpacks for(int i = 0; i < modPacks.getLength(); i++) { Node modPackNode = modPacks.item(i); NamedNodeMap modPackAttr = modPackNode.getAttributes(); try { if (modPackAttr.getNamedItem("author") != null) { isThirdParty = !modPackAttr.getNamedItem("author").getTextContent().equalsIgnoreCase("the teamnt"); } Logger.logDebug("Adding pack " + (offset + i) + " (" + modPackAttr.getNamedItem("name").getTextContent() + ")"); mp.add(new ModPack(modPackAttr.getNamedItem("name").getTextContent(), modPackAttr.getNamedItem("author").getTextContent(), modPackAttr.getNamedItem("version").getTextContent(), modPackAttr.getNamedItem("logo").getTextContent(), modPackAttr.getNamedItem("url").getTextContent(), modPackAttr.getNamedItem("image").getTextContent(), modPackAttr.getNamedItem("dir").getTextContent(), modPackAttr.getNamedItem("mcVersion").getTextContent(), modPackAttr.getNamedItem("serverPack").getTextContent(), modPackAttr.getNamedItem("description") == null ? null : modPackAttr.getNamedItem("description").getTextContent().replace("\\n", "\n"), modPackAttr.getNamedItem("mods") != null ? modPackAttr.getNamedItem("mods").getTextContent() : "", modPackAttr.getNamedItem("oldVersions") != null ? modPackAttr.getNamedItem("oldVersions").getTextContent() : "", modPackAttr.getNamedItem("animation") != null ? modPackAttr.getNamedItem("animation").getTextContent() : "", modPackAttr.getNamedItem("maxPermSize") != null ? modPackAttr.getNamedItem("maxPermSize").getTextContent() : "", offset + i, (isThirdParty && !privatePack) ? (modPackAttr.getNamedItem("private") != null) : privatePack, xmlFile, modPackAttr.getNamedItem("bundledMap") != null, modPackAttr.getNamedItem("customTP") != null, modPackAttr.getNamedItem("minJRE") != null ? modPackAttr.getNamedItem("minJRE").getTextContent() : "1.6", isThirdParty, modPackAttr.getNamedItem("minLaunchSpec") == null ? 0 : Integer.parseInt(modPackAttr.getNamedItem("minLaunchSpec").getTextContent()), modPackAttr.getNamedItem("warning") == null ? null : modPackAttr.getNamedItem("warning").getTextContent().replace("\\n", "\n"), modPackAttr.getNamedItem("customMCVersions") == null ? null : modPackAttr.getNamedItem("customMCVersions").getTextContent())); } catch (Exception e) { Logger.logError("Error while updating modpack info", e); } } ModPack.addPacks(mp); try { modPackStream.close(); } catch (IOException e) {} } } } }