Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollback to official source when any errors occur in the image #6636

Open
wants to merge 4 commits into
base: v3_openjdk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.SocketException;
import java.net.UnknownHostException;

public class DownloadMirror {
public static final int DOWNLOAD_CLASS_LIBRARIES = 0;
Expand All @@ -24,6 +26,15 @@ public class DownloadMirror {
"https://bmclapi2.bangbang93.com",
"https://bmclapi2.bangbang93.com/assets"
};
private boolean mirroredFailed;

private DownloadMirror() {
this.mirroredFailed = false;
}

public static DownloadMirror getInstance() {
return new DownloadMirror();
}

/**
* Download a file with the current mirror. If the file is missing on the mirror,
Expand All @@ -35,14 +46,23 @@ public class DownloadMirror {
* @param buffer The shared buffer
* @param monitor The download monitor.
*/
public static void downloadFileMirrored(int downloadClass, String urlInput, File outputFile,
public void downloadFileMirrored(int downloadClass, String urlInput, File outputFile,
@Nullable byte[] buffer, Tools.DownloaderFeedback monitor) throws IOException {
try {
DownloadUtils.downloadFileMonitored(getMirrorMapping(downloadClass, urlInput),
outputFile, buffer, monitor);
return;
}catch (FileNotFoundException e) {
Log.w("DownloadMirror", "Cannot find the file on the mirror", e);
if (shouldNotRollback()) {
try {
DownloadUtils.downloadFileMonitored(getMirrorMapping(downloadClass, urlInput),
outputFile, buffer, monitor);
return;
} catch (FileNotFoundException | SocketException
/* Connection Reset and java.net.ConnectException */ e) {
Log.w("DownloadMirror", "Cannot find the file on the mirror", e);
} catch (HttpException | UnknownHostException e) {
Log.w("DownloadMirror", "Cannot find the file on the mirror", e);
if (e instanceof UnknownHostException ||
((HttpException) e).getHttpErrorCode() >= 500) {
this.mirroredFailed = true;
}
}
Log.i("DownloadMirror", "Falling back to default source");
}
DownloadUtils.downloadFileMonitored(urlInput, outputFile, buffer, monitor);
Expand All @@ -56,13 +76,22 @@ public static void downloadFileMirrored(int downloadClass, String urlInput, File
* @param urlInput The original (Mojang) URL for the download
* @param outputFile The output file for the download
*/
public static void downloadFileMirrored(int downloadClass, String urlInput, File outputFile) throws IOException {
try {
DownloadUtils.downloadFile(getMirrorMapping(downloadClass, urlInput),
outputFile);
return;
}catch (FileNotFoundException e) {
Log.w("DownloadMirror", "Cannot find the file on the mirror", e);
public void downloadFileMirrored(int downloadClass, String urlInput, File outputFile) throws IOException {
if (shouldNotRollback()) {
try {
DownloadUtils.downloadFile(getMirrorMapping(downloadClass, urlInput),
outputFile);
return;
} catch (FileNotFoundException | SocketException
/* Connection Reset and java.net.ConnectException */ e) {
Log.w("DownloadMirror", "Cannot find the file on the mirror", e);
} catch (HttpException | UnknownHostException e) {
Log.w("DownloadMirror", "Cannot find the file on the mirror", e);
if (e instanceof UnknownHostException ||
((HttpException) e).getHttpErrorCode() >= 500) {
this.mirroredFailed = true;
}
}
Log.i("DownloadMirror", "Falling back to default source");
}
DownloadUtils.downloadFile(urlInput, outputFile);
Expand All @@ -78,7 +107,7 @@ public static void downloadFileMirrored(int downloadClass, String urlInput, File
*/
public static long getContentLengthMirrored(int downloadClass, String urlInput) throws IOException {
long length = DownloadUtils.getContentLength(getMirrorMapping(downloadClass, urlInput));
if(length < 1) {
if (length < 1) {
Log.w("DownloadMirror", "Unable to get content length from mirror");
Log.i("DownloadMirror", "Falling back to default source");
return DownloadUtils.getContentLength(urlInput);
Expand All @@ -95,6 +124,10 @@ public static boolean isMirrored() {
return !LauncherPreferences.PREF_DOWNLOAD_SOURCE.equals("default");
}

private boolean shouldNotRollback() {
return !LauncherPreferences.PREF_ROLLBACK_OFFICIAL_IF_FAIL || !mirroredFailed;
}

private static String[] getMirrorSettings() {
switch (LauncherPreferences.PREF_DOWNLOAD_SOURCE) {
case "bmclapi": return MIRROR_BMCLAPI;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package net.kdt.pojavlaunch.mirrors;

import java.io.IOException;

public class HttpException extends IOException {
private final int httpErrorCode;

public HttpException(String msg, int httpErrorCode) {
super(msg);
this.httpErrorCode = httpErrorCode;
}

public final int getHttpErrorCode() {
return this.httpErrorCode;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public class LauncherPreferences {
public static String PREF_DOWNLOAD_SOURCE = "default";
public static boolean PREF_SKIP_NOTIFICATION_PERMISSION_CHECK = false;
public static boolean PREF_VSYNC_IN_ZINK = true;
public static boolean PREF_ROLLBACK_OFFICIAL_IF_FAIL = false;


public static void loadPreferences(Context ctx) {
Expand Down Expand Up @@ -109,6 +110,7 @@ public static void loadPreferences(Context ctx) {
PREF_VERIFY_MANIFEST = DEFAULT_PREF.getBoolean("verifyManifest", true);
PREF_SKIP_NOTIFICATION_PERMISSION_CHECK = DEFAULT_PREF.getBoolean(PREF_KEY_SKIP_NOTIFICATION_CHECK, false);
PREF_VSYNC_IN_ZINK = DEFAULT_PREF.getBoolean("vsync_in_zink", true);
PREF_ROLLBACK_OFFICIAL_IF_FAIL = DEFAULT_PREF.getBoolean("downloadRollback", false);

String argLwjglLibname = "-Dorg.lwjgl.opengl.libname=";
for (String arg : JREUtils.parseJavaArguments(PREF_CUSTOM_JAVA_ARGS)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public class MinecraftDownloader {
private File mSourceJarFile; // The source client JAR picked during the inheritance process
private File mTargetJarFile; // The destination client JAR to which the source will be copied to.
private boolean mUseFileCounter; // Whether a file counter or a size counter should be used for progress
private DownloadMirror mDownloader;

private static final ThreadLocal<byte[]> sThreadLocalDownloadBuffer = new ThreadLocal<>();

Expand Down Expand Up @@ -93,6 +94,7 @@ private void downloadGame(Activity activity, JMinecraftVersionList.Version verIn
mInternetUsageCounter = new AtomicLong(0);
mDownloaderThreadException = new AtomicReference<>(null);
mUseFileCounter = false;
mDownloader = DownloadMirror.getInstance();

if(!downloadAndProcessMetadata(activity, verInfo, versionName)) {
throw new RuntimeException(activity.getString(R.string.exception_failed_to_unpack_jre17));
Expand Down Expand Up @@ -176,7 +178,7 @@ private File downloadGameJson(JMinecraftVersionList.Version verInfo) throws IOEx
DownloadUtils.ensureSha1(targetFile, LauncherPreferences.PREF_VERIFY_MANIFEST ? verInfo.sha1 : null, () -> {
ProgressLayout.setProgress(ProgressLayout.DOWNLOAD_MINECRAFT, 0,
R.string.newdl_downloading_metadata, targetFile.getName());
DownloadMirror.downloadFileMirrored(DownloadMirror.DOWNLOAD_CLASS_METADATA, verInfo.url, targetFile);
mDownloader.downloadFileMirrored(DownloadMirror.DOWNLOAD_CLASS_METADATA, verInfo.url, targetFile);
return null;
});
}catch (DownloadUtils.SHA1VerificationException e) {
Expand All @@ -194,7 +196,7 @@ private JAssets downloadAssetsIndex(JMinecraftVersionList.Version verInfo) throw
DownloadUtils.ensureSha1(targetFile, assetIndex.sha1, ()-> {
ProgressLayout.setProgress(ProgressLayout.DOWNLOAD_MINECRAFT, 0,
R.string.newdl_downloading_metadata, targetFile.getName());
DownloadMirror.downloadFileMirrored(DownloadMirror.DOWNLOAD_CLASS_METADATA, assetIndex.url, targetFile);
mDownloader.downloadFileMirrored(DownloadMirror.DOWNLOAD_CLASS_METADATA, assetIndex.url, targetFile);
return null;
});
return Tools.GLOBAL_GSON.fromJson(Tools.read(targetFile), JAssets.class);
Expand Down Expand Up @@ -428,7 +430,7 @@ private void verifyFileSha1() throws Exception {
private void downloadFile() throws Exception {
try {
DownloadUtils.ensureSha1(mTargetPath, mTargetSha1, () -> {
DownloadMirror.downloadFileMirrored(mDownloadClass, mTargetUrl, mTargetPath,
mDownloader.downloadFileMirrored(mDownloadClass, mTargetUrl, mTargetPath,
getLocalBuffer(), this);
return null;
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import java.util.concurrent.Callable;

import net.kdt.pojavlaunch.*;
import net.kdt.pojavlaunch.mirrors.HttpException;

import org.apache.commons.io.*;

@SuppressWarnings("IOStreamConstructor")
Expand All @@ -21,7 +23,6 @@ public static void download(String url, OutputStream os) throws IOException {
}

public static void download(URL url, OutputStream os) throws IOException {
InputStream is = null;
try {
// System.out.println("Connecting: " + url.toString());
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
Expand All @@ -30,21 +31,15 @@ public static void download(URL url, OutputStream os) throws IOException {
conn.setDoInput(true);
conn.connect();
if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
throw new IOException("Server returned HTTP " + conn.getResponseCode()
+ ": " + conn.getResponseMessage());
throw new HttpException("Server returned HTTP " + conn.getResponseCode()
+ ": " + conn.getResponseMessage(), conn.getResponseCode());
}
is = conn.getInputStream();
IOUtils.copy(is, os);
} catch (IOException e) {
throw new IOException("Unable to download from " + url, e);
} finally {
if (is != null) {
try {
is.close();
} catch (Exception e) {
e.printStackTrace();
}
try (InputStream is = conn.getInputStream()) {
IOUtils.copy(is, os);
}
} catch (IOException e) {
Log.w("DownloadUtils", "Unable to download from " + url, e);
throw e;
}
}

Expand Down
2 changes: 2 additions & 0 deletions app_pojavlauncher/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,8 @@
<string name="preference_gyro_invert_y_axis_description">Invert the vertical axis.</string>
<string name="preference_gyro_smoothing_title">Enable gyroscope smoothing</string>
<string name="preference_gyro_smoothing_description">Reduce jitter in exchange of latency.</string>
<string name="preference_download_rollback_title">Rollback to official mirror</string>
<string name="preference_download_rollback_description">Roll back the official source when the mirror source experiences server failure.</string>

<string name="preference_back_title">Back to the last screen</string>
<string name="unnamed">Unnamed</string>
Expand Down
6 changes: 6 additions & 0 deletions app_pojavlauncher/src/main/res/xml/pref_misc.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@
android:title="@string/preference_download_source_title"
android:summary="@string/preference_download_source_description"
app2:useSimpleSummaryProvider="true"/>

<SwitchPreference
android:defaultValue="false"
android:key="downloadRollback"
android:title="@string/preference_download_rollback_title"
android:summary="@string/preference_download_rollback_description"/>
<SwitchPreference
android:defaultValue="true"
android:key="verifyManifest"
Expand Down