Skip to content

Commit

Permalink
修复点×打断更新时会报错的问题
Browse files Browse the repository at this point in the history
  • Loading branch information
asforest committed Feb 22, 2025
1 parent e8ebf6a commit 48a9971
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 19 deletions.
13 changes: 5 additions & 8 deletions src/main/java/com/github/balloonupdate/mcpatch/client/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -170,15 +170,13 @@ static boolean AppMain(boolean graphicsMode, StartMethod startMethod, boolean en
window.destroy();

// 处理工作线程里的异常
Throwable ex1 = ex[0];
McpatchBusinessException ex1 = (McpatchBusinessException) ex[0];

if (ex1 != null) {
boolean a = ex[0] instanceof InterruptedException;
boolean b = ex[0] instanceof InterruptedIOException;
boolean c = ex[0] instanceof ClosedByInterruptException;

if (!a && !b && !c) {
boolean a = ex1.getCause() instanceof InterruptedException;
boolean b = ex1.getCause() instanceof ClosedByInterruptException;

if (!a && !b) {
// 打印异常日志
try {
Log.error(new McpatchBusinessException((Exception) ex1).toString());
Expand All @@ -191,9 +189,8 @@ static boolean AppMain(boolean graphicsMode, StartMethod startMethod, boolean en
if (graphicsMode) {
boolean sp = startMethod == StartMethod.Standalone;

String className = ex1 instanceof McpatchBusinessException ? "" : ex1.getClass().getName() + "\n";
String errMsg = ex1.getMessage() != null ? ex1.getMessage() : "<No Exception Message>";
String errMessage = BytesUtils.stringBreak(className + errMsg, 80, "\n");
String errMessage = BytesUtils.stringBreak(errMsg, 80, "\n");
String title = "发生错误 " + Env.getVersion();
String content = errMessage + "\n";
content += !sp ? "点击\"\"显示错误详情并停止启动Minecraft," : "点击\"\"显示错误详情并退出,";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ public boolean run() throws McpatchBusinessException {
return run2(server);
} catch (McpatchBusinessException e) {
throw e;
} catch (InterruptedException e) {
throw new McpatchBusinessException("BK", e);
} catch (Exception e) {
throw new McpatchBusinessException(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
import com.github.balloonupdate.mcpatch.client.data.Range;
import com.github.balloonupdate.mcpatch.client.exceptions.McpatchBusinessException;
import com.github.balloonupdate.mcpatch.client.logging.Log;
import com.github.balloonupdate.mcpatch.client.network.impl.AlistProtocol;
import com.github.balloonupdate.mcpatch.client.network.impl.HttpProtocol;
import com.github.balloonupdate.mcpatch.client.network.impl.McpatchProtocol;
import com.github.balloonupdate.mcpatch.client.network.impl.WebdavProtocol;
import com.github.balloonupdate.mcpatch.client.utils.RuntimeAssert;

import java.nio.channels.ClosedByInterruptException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -45,6 +47,8 @@ public Servers(AppConfig config) throws McpatchBusinessException {
servers.add(new McpatchProtocol(i, url, config));
} else if (url.startsWith("webdav")) {
servers.add(new WebdavProtocol(i, url, config));
} else if (url.startsWith("alist")) {
servers.add(new AlistProtocol(i, url, config));
} else {
throw new McpatchBusinessException("遇到无法识别的服务器链接:" + url);
}
Expand Down Expand Up @@ -90,6 +94,11 @@ private <T> T multipleAvailableServers(Retry<T, UpdatingServer> task) throws Mcp
try {
return task.runTask(s);
} catch (McpatchBusinessException e) {
// 用户打断了更新
if (e.getCause() instanceof ClosedByInterruptException) {
throw new McpatchBusinessException("用户打断了更新", (Exception) e.getCause());
}

// 记录一次错误
ex = e;

Expand All @@ -101,9 +110,7 @@ private <T> T multipleAvailableServers(Retry<T, UpdatingServer> task) throws Mcp
if (times > 1) {
try {
Thread.sleep(3);
} catch (InterruptedException e1) {
throw new RuntimeException(e1);
}
} catch (InterruptedException ignored) {}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,20 @@
import com.github.balloonupdate.mcpatch.client.config.AppConfig;
import com.github.balloonupdate.mcpatch.client.data.Range;
import com.github.balloonupdate.mcpatch.client.exceptions.McpatchBusinessException;
import com.github.balloonupdate.mcpatch.client.logging.Log;
import com.github.balloonupdate.mcpatch.client.network.UpdatingServer;
import okhttp3.OkHttpClient;
import okhttp3.Response;
import com.github.balloonupdate.mcpatch.client.utils.RuntimeAssert;
import okhttp3.*;
import org.json.JSONObject;

import java.io.IOException;
import java.net.ConnectException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class AlistProtocol implements UpdatingServer {
/**
Expand All @@ -32,7 +40,7 @@ public class AlistProtocol implements UpdatingServer {
OkHttpClient client;

/**
* 原始路径缓存 path -> raw_url
* 下载链接缓存 path -> raw_url
*/
HashMap<String, String> cache = new HashMap<>();

Expand All @@ -41,10 +49,33 @@ public AlistProtocol(int number, String url, AppConfig config) {
if (!url.endsWith("/")) {
url = url + "/";
}

// 去掉开头的 alist:// ,留下后面的部分
url = url.substring("alist://".length());

baseUrl = url;

// 创建 HTTP 客户端对象
OkHttpClient.Builder builder = new OkHttpClient.Builder();

// 忽略证书
if (config.ignoreSSLCertificate) {
HttpProtocol.IgnoreSSLCert ignore = new HttpProtocol.IgnoreSSLCert();

builder.sslSocketFactory(ignore.context.getSocketFactory(), ignore.trustManager);
}

client = builder
.connectTimeout(config.httpTimeout, TimeUnit.MILLISECONDS)
.readTimeout(config.httpTimeout, TimeUnit.MILLISECONDS)
.writeTimeout(config.httpTimeout, TimeUnit.MILLISECONDS)
.build();
}

@Override
public String requestText(String path, Range range, String desc) throws McpatchBusinessException {
String rawPath = cache.get(path);

return "";
}

Expand All @@ -67,8 +98,135 @@ public void close() throws Exception {
* @throws McpatchBusinessException 请求失败时
*/
Response request(String path, Range range, String desc) throws McpatchBusinessException {
String rawPath = cache.get(path);
// 检查输入参数,start不能大于end
boolean partial_file = range.start > 0 || range.end > 0;

if (partial_file) {
RuntimeAssert.isTrue(range.end >= range.start);
}

// 拼接 URL
String url = baseUrl + path;

// 构建请求
Request req = buildRequest(url, range, null, null);

try {
Response rsp = client.newCall(req).execute();
int code = rsp.code();

// 检查状态码
if ((!partial_file && (code < 200 || code >= 300)) || (partial_file && code != 206)) {
// 如果状态码不对,就考虑输出响应体内容,因为通常会包含一些服务端返回的错误信息,对排查问题很有帮助
String body = rsp.peekBody(300).string();

String content = String.format("服务器(%d)返回了 %d 而不是206: %s (%s)\n%s", number, code, path, desc, body);

throw new McpatchBusinessException(content);
}

// 检查content-length
long len = rsp.body().contentLength();

if (len == -1) {
throw new McpatchBusinessException(String.format("服务器(%d)没有返回 content-length 头:%s (%s)", number, path, desc));
}

if (range.len() > 0 && len != range.len()) {
String text = String.format("服务器(%d)返回的 content-length 头 %d 不等于 %d: %s", number, len, range.len(), path);

throw new McpatchBusinessException(text);
}

return rsp;
} catch (ConnectException e) {
throw new McpatchBusinessException("连接被拒绝,请检查网络。" + url, e);
} catch (SocketException e) {
throw new McpatchBusinessException("连接中断,请检查网络。" + url, e);
} catch (SocketTimeoutException e) {
throw new McpatchBusinessException("连接超市,请检查网络。" + url, e);
} catch (Exception e) {
throw new McpatchBusinessException(e);
}
}

/**
* 构建一个请求
* @param url 请求的 url
* @param range 请求的范围
* @param headers 额外的 headers
* @return 响应
*/
private Request buildRequest(String url, Range range, RequestBody body, Map<String, String> headers) {
Request.Builder req = new Request.Builder().url(url);

// 添加json响应请求
req.addHeader("Content-Type", "application/json");

// 只请求部分文件
if (range.len() > 0) {
req.addHeader("Range", String.format("bytes=%d-%d", range.start, range.end - 1));
}

// 添加额外headers
if (headers != null) {
for (Map.Entry<String, String> e : headers.entrySet())
req.addHeader(e.getKey(), e.getValue());
}

// 添加自定义headers
for (Map.Entry<String, String> e : config.httpHeaders.entrySet()) {
req.addHeader(e.getKey(), e.getValue());
}

// 添加body
if (body != null) {
req.setBody$okhttp(body);
}

return req.build();
}

/**
* 获取文件的原始链接
*/
String fetchDownloadLink(String filename) throws IOException, McpatchBusinessException {
if (cache.containsKey(filename))
return cache.get(filename);

String path = baseUrl + filename;

int split = path.indexOf("/", "https://".length());

path = path.substring(split);

Log.info("split: " + path);


String url = baseUrl + "api/fs/get";

String bodyText = String.format("\"path\": \"%s\",\"password\": \"\"", path);
RequestBody body = RequestBody.create(bodyText, MediaType.get("text/json"));

Request req = buildRequest(url, Range.Empty(), body, null);

Response rsp = client.newCall(req).execute();

if (!rsp.isSuccessful()) {
// 如果状态码不对,就考虑输出响应体内容,因为通常会包含一些服务端返回的错误信息,对排查问题很有帮助
String b = rsp.peekBody(300).string();

String content = String.format("服务器(%d)返回了 %d 而不是206: %s (%s)\n%s", number, rsp.code(), path, "请求原始下载链接", b);

throw new McpatchBusinessException(content);
}

JSONObject json = new JSONObject(rsp.body());

String rawUrl = (String) json.query("/data/raw_url");

cache.put(path, rawUrl);

throw new RuntimeException("还没有实现这个方法");
return rawUrl;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,6 @@ public McPatchWindow(int width, int height) {
window.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {

System.out.println("aaaaaaaaaaaaaaaaaaaaaaa");

if (onWindowClosing != null)
onWindowClosing.run(that);
else
Expand Down

0 comments on commit 48a9971

Please sign in to comment.