Skip to content

Commit 48a9971

Browse files
committed
修复点×打断更新时会报错的问题
1 parent e8ebf6a commit 48a9971

File tree

5 files changed

+180
-19
lines changed

5 files changed

+180
-19
lines changed

src/main/java/com/github/balloonupdate/mcpatch/client/Main.java

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -170,15 +170,13 @@ static boolean AppMain(boolean graphicsMode, StartMethod startMethod, boolean en
170170
window.destroy();
171171

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

175175
if (ex1 != null) {
176-
boolean a = ex[0] instanceof InterruptedException;
177-
boolean b = ex[0] instanceof InterruptedIOException;
178-
boolean c = ex[0] instanceof ClosedByInterruptException;
179-
180-
if (!a && !b && !c) {
176+
boolean a = ex1.getCause() instanceof InterruptedException;
177+
boolean b = ex1.getCause() instanceof ClosedByInterruptException;
181178

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

194-
String className = ex1 instanceof McpatchBusinessException ? "" : ex1.getClass().getName() + "\n";
195192
String errMsg = ex1.getMessage() != null ? ex1.getMessage() : "<No Exception Message>";
196-
String errMessage = BytesUtils.stringBreak(className + errMsg, 80, "\n");
193+
String errMessage = BytesUtils.stringBreak(errMsg, 80, "\n");
197194
String title = "发生错误 " + Env.getVersion();
198195
String content = errMessage + "\n";
199196
content += !sp ? "点击\"\"显示错误详情并停止启动Minecraft," : "点击\"\"显示错误详情并退出,";

src/main/java/com/github/balloonupdate/mcpatch/client/Work.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ public boolean run() throws McpatchBusinessException {
7575
return run2(server);
7676
} catch (McpatchBusinessException e) {
7777
throw e;
78+
} catch (InterruptedException e) {
79+
throw new McpatchBusinessException("BK", e);
7880
} catch (Exception e) {
7981
throw new McpatchBusinessException(e);
8082
}

src/main/java/com/github/balloonupdate/mcpatch/client/network/Servers.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
import com.github.balloonupdate.mcpatch.client.data.Range;
55
import com.github.balloonupdate.mcpatch.client.exceptions.McpatchBusinessException;
66
import com.github.balloonupdate.mcpatch.client.logging.Log;
7+
import com.github.balloonupdate.mcpatch.client.network.impl.AlistProtocol;
78
import com.github.balloonupdate.mcpatch.client.network.impl.HttpProtocol;
89
import com.github.balloonupdate.mcpatch.client.network.impl.McpatchProtocol;
910
import com.github.balloonupdate.mcpatch.client.network.impl.WebdavProtocol;
1011
import com.github.balloonupdate.mcpatch.client.utils.RuntimeAssert;
1112

13+
import java.nio.channels.ClosedByInterruptException;
1214
import java.nio.file.Path;
1315
import java.util.ArrayList;
1416
import java.util.List;
@@ -45,6 +47,8 @@ public Servers(AppConfig config) throws McpatchBusinessException {
4547
servers.add(new McpatchProtocol(i, url, config));
4648
} else if (url.startsWith("webdav")) {
4749
servers.add(new WebdavProtocol(i, url, config));
50+
} else if (url.startsWith("alist")) {
51+
servers.add(new AlistProtocol(i, url, config));
4852
} else {
4953
throw new McpatchBusinessException("遇到无法识别的服务器链接:" + url);
5054
}
@@ -90,6 +94,11 @@ private <T> T multipleAvailableServers(Retry<T, UpdatingServer> task) throws Mcp
9094
try {
9195
return task.runTask(s);
9296
} catch (McpatchBusinessException e) {
97+
// 用户打断了更新
98+
if (e.getCause() instanceof ClosedByInterruptException) {
99+
throw new McpatchBusinessException("用户打断了更新", (Exception) e.getCause());
100+
}
101+
93102
// 记录一次错误
94103
ex = e;
95104

@@ -101,9 +110,7 @@ private <T> T multipleAvailableServers(Retry<T, UpdatingServer> task) throws Mcp
101110
if (times > 1) {
102111
try {
103112
Thread.sleep(3);
104-
} catch (InterruptedException e1) {
105-
throw new RuntimeException(e1);
106-
}
113+
} catch (InterruptedException ignored) {}
107114
}
108115
}
109116
}

src/main/java/com/github/balloonupdate/mcpatch/client/network/impl/AlistProtocol.java

Lines changed: 163 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,20 @@
33
import com.github.balloonupdate.mcpatch.client.config.AppConfig;
44
import com.github.balloonupdate.mcpatch.client.data.Range;
55
import com.github.balloonupdate.mcpatch.client.exceptions.McpatchBusinessException;
6+
import com.github.balloonupdate.mcpatch.client.logging.Log;
67
import com.github.balloonupdate.mcpatch.client.network.UpdatingServer;
7-
import okhttp3.OkHttpClient;
8-
import okhttp3.Response;
8+
import com.github.balloonupdate.mcpatch.client.utils.RuntimeAssert;
9+
import okhttp3.*;
10+
import org.json.JSONObject;
911

12+
import java.io.IOException;
13+
import java.net.ConnectException;
14+
import java.net.SocketException;
15+
import java.net.SocketTimeoutException;
1016
import java.nio.file.Path;
1117
import java.util.HashMap;
18+
import java.util.Map;
19+
import java.util.concurrent.TimeUnit;
1220

1321
public class AlistProtocol implements UpdatingServer {
1422
/**
@@ -32,7 +40,7 @@ public class AlistProtocol implements UpdatingServer {
3240
OkHttpClient client;
3341

3442
/**
35-
* 原始路径缓存 path -> raw_url
43+
* 下载链接缓存 path -> raw_url
3644
*/
3745
HashMap<String, String> cache = new HashMap<>();
3846

@@ -41,10 +49,33 @@ public AlistProtocol(int number, String url, AppConfig config) {
4149
if (!url.endsWith("/")) {
4250
url = url + "/";
4351
}
52+
53+
// 去掉开头的 alist:// ,留下后面的部分
54+
url = url.substring("alist://".length());
55+
56+
baseUrl = url;
57+
58+
// 创建 HTTP 客户端对象
59+
OkHttpClient.Builder builder = new OkHttpClient.Builder();
60+
61+
// 忽略证书
62+
if (config.ignoreSSLCertificate) {
63+
HttpProtocol.IgnoreSSLCert ignore = new HttpProtocol.IgnoreSSLCert();
64+
65+
builder.sslSocketFactory(ignore.context.getSocketFactory(), ignore.trustManager);
66+
}
67+
68+
client = builder
69+
.connectTimeout(config.httpTimeout, TimeUnit.MILLISECONDS)
70+
.readTimeout(config.httpTimeout, TimeUnit.MILLISECONDS)
71+
.writeTimeout(config.httpTimeout, TimeUnit.MILLISECONDS)
72+
.build();
4473
}
4574

4675
@Override
4776
public String requestText(String path, Range range, String desc) throws McpatchBusinessException {
77+
String rawPath = cache.get(path);
78+
4879
return "";
4980
}
5081

@@ -67,8 +98,135 @@ public void close() throws Exception {
6798
* @throws McpatchBusinessException 请求失败时
6899
*/
69100
Response request(String path, Range range, String desc) throws McpatchBusinessException {
70-
String rawPath = cache.get(path);
101+
// 检查输入参数,start不能大于end
102+
boolean partial_file = range.start > 0 || range.end > 0;
103+
104+
if (partial_file) {
105+
RuntimeAssert.isTrue(range.end >= range.start);
106+
}
107+
108+
// 拼接 URL
109+
String url = baseUrl + path;
110+
111+
// 构建请求
112+
Request req = buildRequest(url, range, null, null);
113+
114+
try {
115+
Response rsp = client.newCall(req).execute();
116+
int code = rsp.code();
117+
118+
// 检查状态码
119+
if ((!partial_file && (code < 200 || code >= 300)) || (partial_file && code != 206)) {
120+
// 如果状态码不对,就考虑输出响应体内容,因为通常会包含一些服务端返回的错误信息,对排查问题很有帮助
121+
String body = rsp.peekBody(300).string();
122+
123+
String content = String.format("服务器(%d)返回了 %d 而不是206: %s (%s)\n%s", number, code, path, desc, body);
124+
125+
throw new McpatchBusinessException(content);
126+
}
127+
128+
// 检查content-length
129+
long len = rsp.body().contentLength();
130+
131+
if (len == -1) {
132+
throw new McpatchBusinessException(String.format("服务器(%d)没有返回 content-length 头:%s (%s)", number, path, desc));
133+
}
134+
135+
if (range.len() > 0 && len != range.len()) {
136+
String text = String.format("服务器(%d)返回的 content-length 头 %d 不等于 %d: %s", number, len, range.len(), path);
137+
138+
throw new McpatchBusinessException(text);
139+
}
140+
141+
return rsp;
142+
} catch (ConnectException e) {
143+
throw new McpatchBusinessException("连接被拒绝,请检查网络。" + url, e);
144+
} catch (SocketException e) {
145+
throw new McpatchBusinessException("连接中断,请检查网络。" + url, e);
146+
} catch (SocketTimeoutException e) {
147+
throw new McpatchBusinessException("连接超市,请检查网络。" + url, e);
148+
} catch (Exception e) {
149+
throw new McpatchBusinessException(e);
150+
}
151+
}
152+
153+
/**
154+
* 构建一个请求
155+
* @param url 请求的 url
156+
* @param range 请求的范围
157+
* @param headers 额外的 headers
158+
* @return 响应
159+
*/
160+
private Request buildRequest(String url, Range range, RequestBody body, Map<String, String> headers) {
161+
Request.Builder req = new Request.Builder().url(url);
162+
163+
// 添加json响应请求
164+
req.addHeader("Content-Type", "application/json");
165+
166+
// 只请求部分文件
167+
if (range.len() > 0) {
168+
req.addHeader("Range", String.format("bytes=%d-%d", range.start, range.end - 1));
169+
}
170+
171+
// 添加额外headers
172+
if (headers != null) {
173+
for (Map.Entry<String, String> e : headers.entrySet())
174+
req.addHeader(e.getKey(), e.getValue());
175+
}
176+
177+
// 添加自定义headers
178+
for (Map.Entry<String, String> e : config.httpHeaders.entrySet()) {
179+
req.addHeader(e.getKey(), e.getValue());
180+
}
181+
182+
// 添加body
183+
if (body != null) {
184+
req.setBody$okhttp(body);
185+
}
186+
187+
return req.build();
188+
}
189+
190+
/**
191+
* 获取文件的原始链接
192+
*/
193+
String fetchDownloadLink(String filename) throws IOException, McpatchBusinessException {
194+
if (cache.containsKey(filename))
195+
return cache.get(filename);
196+
197+
String path = baseUrl + filename;
198+
199+
int split = path.indexOf("/", "https://".length());
200+
201+
path = path.substring(split);
202+
203+
Log.info("split: " + path);
204+
205+
206+
String url = baseUrl + "api/fs/get";
207+
208+
String bodyText = String.format("\"path\": \"%s\",\"password\": \"\"", path);
209+
RequestBody body = RequestBody.create(bodyText, MediaType.get("text/json"));
210+
211+
Request req = buildRequest(url, Range.Empty(), body, null);
212+
213+
Response rsp = client.newCall(req).execute();
214+
215+
if (!rsp.isSuccessful()) {
216+
// 如果状态码不对,就考虑输出响应体内容,因为通常会包含一些服务端返回的错误信息,对排查问题很有帮助
217+
String b = rsp.peekBody(300).string();
218+
219+
String content = String.format("服务器(%d)返回了 %d 而不是206: %s (%s)\n%s", number, rsp.code(), path, "请求原始下载链接", b);
220+
221+
throw new McpatchBusinessException(content);
222+
}
223+
224+
JSONObject json = new JSONObject(rsp.body());
225+
226+
String rawUrl = (String) json.query("/data/raw_url");
227+
228+
cache.put(path, rawUrl);
71229

72-
throw new RuntimeException("还没有实现这个方法");
230+
return rawUrl;
73231
}
74232
}

src/main/java/com/github/balloonupdate/mcpatch/client/ui/McPatchWindow.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,6 @@ public McPatchWindow(int width, int height) {
5353
window.addWindowListener(new WindowAdapter() {
5454
@Override
5555
public void windowClosing(WindowEvent e) {
56-
57-
System.out.println("aaaaaaaaaaaaaaaaaaaaaaa");
58-
5956
if (onWindowClosing != null)
6057
onWindowClosing.run(that);
6158
else

0 commit comments

Comments
 (0)