package net.minecraft.launcher.updater;
import net.minecraft.launcher.Launcher;
import net.minecraft.launcher.OperatingSystem;
import net.minecraft.launcher.events.RefreshedVersionsListener;
import net.minecraft.launcher.updater.download.DownloadJob;
import net.minecraft.launcher.updater.download.Downloadable;
import net.minecraft.launcher.versions.CompleteVersion;
import net.minecraft.launcher.versions.ReleaseType;
import net.minecraft.launcher.versions.Version;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.swing.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
import java.io.IOException;
import java.net.Proxy;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ThreadPoolExecutor;
public class VersionManager {
private final VersionList localVersionList;
private final VersionList remoteVersionList;
private final ThreadPoolExecutor executorService = new ExceptionalThreadPoolExecutor(8);
private final List<RefreshedVersionsListener> refreshedVersionsListeners = Collections.synchronizedList(new ArrayList());
private final Object refreshLock = new Object();
private boolean isRefreshing;
public VersionManager(VersionList localVersionList, VersionList remoteVersionList) {
this.localVersionList = localVersionList;
this.remoteVersionList = remoteVersionList;
}
public void refreshVersions() throws IOException {
synchronized (this.refreshLock) {
this.isRefreshing = true;
}
try {
Launcher.getInstance().println("Refreshing local version list...");
this.localVersionList.refreshVersions();
Launcher.getInstance().println("Refreshing remote version list...");
this.remoteVersionList.refreshVersions();
} catch (IOException ex) {
synchronized (this.refreshLock) {
this.isRefreshing = false;
}
throw ex;
}
Launcher.getInstance().println("Refresh complete.");
synchronized (this.refreshLock) {
this.isRefreshing = false;
}
final List listeners = new ArrayList(this.refreshedVersionsListeners);
for (Iterator iterator = listeners.iterator(); iterator.hasNext(); ) {
RefreshedVersionsListener listener = (RefreshedVersionsListener) iterator.next();
if (!listener.shouldReceiveEventsInUIThread()) {
listener.onVersionsRefreshed(this);
iterator.remove();
}
}
if (!listeners.isEmpty())
SwingUtilities.invokeLater(new Runnable() {
public void run() {
for (RefreshedVersionsListener listener : (List<RefreshedVersionsListener>) listeners)
listener.onVersionsRefreshed(VersionManager.this);
}
});
}
public List<VersionSyncInfo> getVersions() {
return getVersions(null);
}
public List<VersionSyncInfo> getVersions(VersionFilter filter) {
synchronized (this.refreshLock) {
if (this.isRefreshing) return new ArrayList();
}
List result = new ArrayList();
Object lookup = new HashMap();
Map counts = new EnumMap(ReleaseType.class);
for (ReleaseType type : ReleaseType.values()) {
counts.put(type, Integer.valueOf(0));
}
for (Version version : this.localVersionList.getVersions()) {
if ((version.getType() != null) && (version.getUpdatedTime() != null) && (
(filter == null) || ((filter.getTypes().contains(version.getType())) && (((Integer) counts.get(version.getType())).intValue() < filter.getMaxCount())))) {
VersionSyncInfo syncInfo = getVersionSyncInfo(version, this.remoteVersionList.getVersion(version.getId()));
((Map) lookup).put(version.getId(), syncInfo);
result.add(syncInfo);
}
}
for (Version version : this.remoteVersionList.getVersions()) {
if ((version.getType() != null) && (version.getUpdatedTime() != null) &&
(!((Map) lookup).containsKey(version.getId())) && (
(filter == null) || ((filter.getTypes().contains(version.getType())) && (((Integer) counts.get(version.getType())).intValue() < filter.getMaxCount())))) {
VersionSyncInfo syncInfo = getVersionSyncInfo(this.localVersionList.getVersion(version.getId()), version);
((Map) lookup).put(version.getId(), syncInfo);
result.add(syncInfo);
if (filter != null)
counts.put(version.getType(), Integer.valueOf(((Integer) counts.get(version.getType())).intValue() + 1));
}
}
if (result.isEmpty()) {
for (Version version : this.localVersionList.getVersions()) {
if ((version.getType() != null) && (version.getUpdatedTime() != null)) {
VersionSyncInfo syncInfo = getVersionSyncInfo(version, this.remoteVersionList.getVersion(version.getId()));
((Map) lookup).put(version.getId(), syncInfo);
result.add(syncInfo);
}
}
}
Collections.sort(result, new Comparator() {
public int compare(Object a, Object b) {
Version aVer = ((VersionSyncInfo) a).getLatestVersion();
Version bVer = ((VersionSyncInfo) b).getLatestVersion();
if ((aVer.getReleaseTime() != null) && (bVer.getReleaseTime() != null)) {
return bVer.getReleaseTime().compareTo(aVer.getReleaseTime());
}
return bVer.getUpdatedTime().compareTo(aVer.getUpdatedTime());
}
});
return result;
}
public VersionSyncInfo getVersionSyncInfo(Version version) {
return getVersionSyncInfo(version.getId());
}
public VersionSyncInfo getVersionSyncInfo(String name) {
return getVersionSyncInfo(this.localVersionList.getVersion(name), this.remoteVersionList.getVersion(name));
}
public VersionSyncInfo getVersionSyncInfo(Version localVersion, Version remoteVersion) {
boolean installed = localVersion != null;
boolean upToDate = installed;
if ((installed) && (remoteVersion != null)) {
upToDate = !remoteVersion.getUpdatedTime().after(localVersion.getUpdatedTime());
}
if ((localVersion instanceof CompleteVersion)) {
upToDate &= this.localVersionList.hasAllFiles((CompleteVersion) localVersion, OperatingSystem.getCurrentPlatform());
}
return new VersionSyncInfo(localVersion, remoteVersion, installed, upToDate);
}
public List<VersionSyncInfo> getInstalledVersions() {
List result = new ArrayList();
for (Version version : this.localVersionList.getVersions()) {
if ((version.getType() != null) && (version.getUpdatedTime() != null)) {
VersionSyncInfo syncInfo = getVersionSyncInfo(version, this.remoteVersionList.getVersion(version.getId()));
result.add(syncInfo);
}
}
return result;
}
public VersionList getRemoteVersionList() {
return this.remoteVersionList;
}
public VersionList getLocalVersionList() {
return this.localVersionList;
}
public CompleteVersion getLatestCompleteVersion(VersionSyncInfo syncInfo) throws IOException {
if (syncInfo.getLatestSource() == VersionSyncInfo.VersionSource.REMOTE) {
CompleteVersion result = null;
IOException exception = null;
try {
result = this.remoteVersionList.getCompleteVersion(syncInfo.getLatestVersion());
} catch (IOException e) {
exception = e;
try {
result = this.localVersionList.getCompleteVersion(syncInfo.getLatestVersion());
} catch (IOException localIOException1) {
}
}
if (result != null) {
return result;
}
throw exception;
}
return this.localVersionList.getCompleteVersion(syncInfo.getLatestVersion());
}
public DownloadJob downloadVersion(VersionSyncInfo syncInfo, DownloadJob job) throws IOException {
if (!(this.localVersionList instanceof LocalVersionList))
throw new IllegalArgumentException("Cannot download if local repo isn't a LocalVersionList");
if (!(this.remoteVersionList instanceof RemoteVersionList))
throw new IllegalArgumentException("Cannot download if local repo isn't a RemoteVersionList");
CompleteVersion version = getLatestCompleteVersion(syncInfo);
File baseDirectory = ((LocalVersionList) this.localVersionList).getBaseDirectory();
Proxy proxy = ((RemoteVersionList) this.remoteVersionList).getProxy();
/* if ((!syncInfo.isInstalled()) || (!syncInfo.isUpToDate())) {
job.addDownloadables(version.getRequiredDownloadables(OperatingSystem.getCurrentPlatform(), proxy, baseDirectory, false));
}*/
job.addDownloadables(version.getRequiredDownloadables(OperatingSystem.getCurrentPlatform(), proxy, baseDirectory, false));
String jarFile = "versions/" + version.getId() + "/" + version.getId() + ".jar";
job.addDownloadables(new Downloadable[]{new Downloadable(proxy, new URL("https://s3.amazonaws.com/Minecraft.Download/" + jarFile), new File(baseDirectory, jarFile), false)});
return job;
}
public DownloadJob downloadResources(DownloadJob job) throws IOException {
File baseDirectory = ((LocalVersionList) this.localVersionList).getBaseDirectory();
job.addDownloadables(getResourceFiles(((RemoteVersionList) this.remoteVersionList).getProxy(), baseDirectory));
return job;
}
private Set<Downloadable> getResourceFiles(Proxy proxy, File baseDirectory) {
Set result = new HashSet();
try {
String nextMarker = null;
long start = System.nanoTime();
do {
String query = nextMarker != null ? "?marker=" + nextMarker : "";
URL resourceUrl = new URL("https://s3.amazonaws.com/Minecraft.Resources/" + query);
System.out.println("resourceUrl = " + resourceUrl);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(resourceUrl.openConnection(proxy).getInputStream());
NodeList nodeLst = doc.getElementsByTagName("Contents");
for (int i = 0; i < nodeLst.getLength(); i++) {
Node node = nodeLst.item(i);
if (node.getNodeType() == 1) {
Element element = (Element) node;
String key = element.getElementsByTagName("Key").item(0).getChildNodes().item(0).getNodeValue();
String etag = element.getElementsByTagName("ETag") != null ? element.getElementsByTagName("ETag").item(0).getChildNodes().item(0).getNodeValue() : "-";
long size = Long.parseLong(element.getElementsByTagName("Size").item(0).getChildNodes().item(0).getNodeValue());
if (size > 0L) {
File file = new File(baseDirectory, "assets/" + key);
if (etag.length() > 1) {
etag = Downloadable.getEtag(etag);
if ((file.isFile()) && (file.length() == size)) {
String localMd5 = Downloadable.getMD5(file);
if (localMd5.equals(etag)) continue;
}
}
//result.add(new Downloadable(proxy, new URL("https://s3.amazonaws.com/Minecraft.Resources/" + key), file, false));
Downloadable downloadable = new Downloadable(proxy, new URL("https://s3.amazonaws.com/Minecraft.Resources/" + key), file, false);
downloadable.setExpectedSize(size);
result.add(downloadable);
} else {
nextMarker = key;
}
}
}
if ("false".equals(doc.getElementsByTagName("IsTruncated").item(0).getTextContent()))
nextMarker = null;
}
while (nextMarker != null);
long end = System.nanoTime();
long delta = end - start;
Launcher.getInstance().println("Delta time to compare resources: " + delta / 1000000L + " ms ");
} catch (Exception ex) {
Launcher.getInstance().println("Couldn't download resources", ex);
}
return result;
}
public ThreadPoolExecutor getExecutorService() {
return this.executorService;
}
public void addRefreshedVersionsListener(RefreshedVersionsListener listener) {
this.refreshedVersionsListeners.add(listener);
}
public void removeRefreshedVersionsListener(RefreshedVersionsListener listener) {
this.refreshedVersionsListeners.remove(listener);
}
}