1.精简插件下载方法

This commit is contained in:
xufeng 2022-04-09 15:24:53 +08:00
parent 4eaf4ef96f
commit 543346605a
2 changed files with 136 additions and 116 deletions

View File

@ -115,8 +115,8 @@ public class PluginManageController extends PluginManageView {
PluginJarInfo pluginJarInfoOld = PluginManager.getInstance().getPlugin(pluginJarInfo.getJarName());
if (pluginJarInfoOld != null) {
FileUtils.delete(pluginJarInfoOld.getFile());
PluginManager.getInstance().getPluginList().remove(pluginJarInfoOld);
}
PluginManager.getInstance().getPluginList().remove(pluginJarInfoOld);
PluginManager.getInstance().getPluginList().add(pluginJarInfo);
TooltipUtil.showToast("插件 " + dataRow.get("nameTableColumn") + " 下载完成");
PluginParser.parse(pluginJarInfo.getFile(), pluginJarInfo);

View File

@ -1,6 +1,7 @@
package com.xwintop.xJavaFxTool.services.index;
import cn.hutool.http.HttpStatus;
import cn.hutool.core.io.StreamProgress;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.xwintop.xJavaFxTool.AppException;
@ -16,21 +17,15 @@ import javafx.stage.Window;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import okio.*;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
@ -50,11 +45,11 @@ public class PluginManageService {
/**
* 当下载插件时模拟数种 UA
*/
public static final String[] OPTIONAL_UA_LIST = {
"Mozilla/5.0 (Windows NT 6.1; rv:51.0) Gecko/20100101 Firefox/51.0",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"
};
// public static final String[] OPTIONAL_UA_LIST = {
// "Mozilla/5.0 (Windows NT 6.1; rv:51.0) Gecko/20100101 Firefox/51.0",
// "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.0 Safari/537.36",
// "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"
// };
private PluginManageController pluginManageController;
@ -115,13 +110,13 @@ public class PluginManageService {
progressTask.setOnFailed(event -> {
Throwable e = event.getSource().getException();
if (e != null) {
log.error("", e);
log.error("下载插件失败", e);
FxAlerts.error(controllerWindow, "下载插件失败", e);
} else {
FxAlerts.error(controllerWindow, "下载失败", event.getSource().getMessage());
}
});
dialog.show();
dialog.showAndWait();
}
public void setIsEnableTableColumn(Integer index) {
@ -204,116 +199,141 @@ public class PluginManageService {
}
}
public File downloadPlugin(PluginJarInfo pluginJarInfo, BiConsumer<Long, Long> onProgressUpdate) throws IOException {
public void downloadPlugin(PluginJarInfo pluginJarInfo, BiConsumer<Long, Long> onProgressUpdate) throws IOException {
File file = pluginJarInfo.getFile();
FileUtils.forceMkdirParent(file);
OkHttpClient pluginDownloader = new OkHttpClient.Builder().addInterceptor(new PluginManageService.DownloadProgressInterceptor(onProgressUpdate)).build();
// 使用多个 UA 尝试下载
Throwable downloadFailure = null;
for (String ua : OPTIONAL_UA_LIST) {
try {
tryDownload(pluginJarInfo.getName(), pluginJarInfo.getDownloadUrl(), ua, file, pluginDownloader);
downloadFailure = null;
break;
} catch (Exception e) {
downloadFailure = e;
HttpResponse response = HttpUtil.createGet(pluginJarInfo.getDownloadUrl(), true).executeAsync();
long contentLength = response.contentLength();
response.writeBodyForFile(file, new StreamProgress() {
@Override
public void start() {
}
}
if (downloadFailure != null) {
if (downloadFailure instanceof IOException) {
throw (IOException) downloadFailure;
} else {
throw new IOException("插件 '" + pluginJarInfo.getName() + "' 下载失败 " + pluginJarInfo.getJarName(), downloadFailure);
@Override
public void progress(long progressSize) {
onProgressUpdate.accept(contentLength, progressSize);
}
}
@Override
public void finish() {
}
});
// 下载完毕
pluginJarInfo.setIsDownload(true);
pluginJarInfo.setIsEnable(true);
pluginJarInfo.setLocalVersionNumber(pluginJarInfo.getVersionNumber());
return file;
}
/**
* 尝试指定的 UA 进行下载如果下载失败则抛出异常
*
* @param pluginName 插件名称
* @param url 下载地址
* @param ua UA 字符串
* @param file 下载到的目标文件
* @throws IOException 如果下载失败
*/
private void tryDownload(String pluginName, String url, String ua, File file, OkHttpClient pluginDownloader) throws IOException {
Request request = new Request.Builder().header("User-Agent", ua).url(url).build();
try (Response response = pluginDownloader.newCall(request).execute()) {
if (response.code() != HttpStatus.HTTP_OK) {
throw new IOException("插件 '" + pluginName + "' 下载失败 : HTTP " + response.code());
}
// public File downloadPlugin(PluginJarInfo pluginJarInfo, BiConsumer<Long, Long> onProgressUpdate) throws IOException {
// File file = pluginJarInfo.getFile();
// FileUtils.forceMkdirParent(file);
// OkHttpClient pluginDownloader = new OkHttpClient.Builder().addInterceptor(new PluginManageService.DownloadProgressInterceptor(onProgressUpdate)).build();
// // 使用多个 UA 尝试下载
// Throwable downloadFailure = null;
// for (String ua : OPTIONAL_UA_LIST) {
// try {
// tryDownload(pluginJarInfo.getName(), pluginJarInfo.getDownloadUrl(), ua, file, pluginDownloader);
// downloadFailure = null;
// break;
// } catch (Exception e) {
// downloadFailure = e;
// }
// }
// if (downloadFailure != null) {
// if (downloadFailure instanceof IOException) {
// throw (IOException) downloadFailure;
// } else {
// throw new IOException("插件 '" + pluginJarInfo.getName() + "' 下载失败 " + pluginJarInfo.getJarName(), downloadFailure);
// }
// }
// // 下载完毕
// pluginJarInfo.setIsDownload(true);
// pluginJarInfo.setIsEnable(true);
// pluginJarInfo.setLocalVersionNumber(pluginJarInfo.getVersionNumber());
// return file;
// }
//
// /**
// * 尝试指定的 UA 进行下载如果下载失败则抛出异常
// *
// * @param pluginName 插件名称
// * @param url 下载地址
// * @param ua UA 字符串
// * @param file 下载到的目标文件
// * @throws IOException 如果下载失败
// */
// private void tryDownload(String pluginName, String url, String ua, File file, OkHttpClient pluginDownloader) throws IOException {
// Request request = new Request.Builder().header("User-Agent", ua).url(url).build();
// try (Response response = pluginDownloader.newCall(request).execute()) {
// if (response.code() != HttpStatus.HTTP_OK) {
// throw new IOException("插件 '" + pluginName + "' 下载失败 : HTTP " + response.code());
// }
//
// InputStream inputStream = Objects.requireNonNull(response.body()).byteStream();
// try (FileOutputStream outputStream = new FileOutputStream(file)) {
// IOUtils.copy(inputStream, outputStream);
// }
// }
// }
InputStream inputStream = Objects.requireNonNull(response.body()).byteStream();
try (FileOutputStream outputStream = new FileOutputStream(file)) {
IOUtils.copy(inputStream, outputStream);
}
}
}
private class DownloadProgressInterceptor implements Interceptor {
private BiConsumer<Long, Long> onProgressUpdate;
DownloadProgressInterceptor(BiConsumer<Long, Long> onProgressUpdate) {
this.onProgressUpdate = onProgressUpdate;
}
@Override
public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder()
.body(new PluginManageService.ProgressResponseBody(originalResponse.body(), onProgressUpdate)).build();
}
}
private static class ProgressResponseBody extends ResponseBody {
private final ResponseBody responseBody;
private BiConsumer<Long, Long> onProgressUpdate;
private BufferedSource bufferedSource;
ProgressResponseBody(ResponseBody responseBody, BiConsumer<Long, Long> onProgressUpdate) {
this.responseBody = responseBody;
this.onProgressUpdate = onProgressUpdate;
}
@Override
public MediaType contentType() {
return responseBody.contentType();
}
@Override
public long contentLength() {
return responseBody.contentLength();
}
@Override
public BufferedSource source() {
if (bufferedSource == null) {
bufferedSource = Okio.buffer(source(responseBody.source()));
}
return bufferedSource;
}
private Source source(Source source) {
return new ForwardingSource(source) {
long totalBytesRead = 0L;
@Override
public long read(Buffer sink, long byteCount) throws IOException {
long bytesRead = super.read(sink, byteCount);
// read() returns the number of bytes read, or -1 if this source is exhausted.
totalBytesRead += bytesRead != -1 ? bytesRead : 0;
onProgressUpdate.accept(totalBytesRead, responseBody.contentLength());
return bytesRead;
}
};
}
}
// private class DownloadProgressInterceptor implements Interceptor {
// private BiConsumer<Long, Long> onProgressUpdate;
//
// DownloadProgressInterceptor(BiConsumer<Long, Long> onProgressUpdate) {
// this.onProgressUpdate = onProgressUpdate;
// }
//
// @Override
// public Response intercept(Chain chain) throws IOException {
// Response originalResponse = chain.proceed(chain.request());
// return originalResponse.newBuilder()
// .body(new PluginManageService.ProgressResponseBody(originalResponse.body(), onProgressUpdate)).build();
// }
// }
//
// private static class ProgressResponseBody extends ResponseBody {
// private final ResponseBody responseBody;
//
// private BiConsumer<Long, Long> onProgressUpdate;
//
// private BufferedSource bufferedSource;
//
// ProgressResponseBody(ResponseBody responseBody, BiConsumer<Long, Long> onProgressUpdate) {
// this.responseBody = responseBody;
// this.onProgressUpdate = onProgressUpdate;
// }
//
// @Override
// public MediaType contentType() {
// return responseBody.contentType();
// }
//
// @Override
// public long contentLength() {
// return responseBody.contentLength();
// }
//
// @Override
// public BufferedSource source() {
// if (bufferedSource == null) {
// bufferedSource = Okio.buffer(source(responseBody.source()));
// }
// return bufferedSource;
// }
//
// private Source source(Source source) {
// return new ForwardingSource(source) {
// long totalBytesRead = 0L;
//
// @Override
// public long read(Buffer sink, long byteCount) throws IOException {
// long bytesRead = super.read(sink, byteCount);
// // read() returns the number of bytes read, or -1 if this source is exhausted.
// totalBytesRead += bytesRead != -1 ? bytesRead : 0;
// onProgressUpdate.accept(responseBody.contentLength(), totalBytesRead);
// return bytesRead;
// }
// };
// }
// }
}