Fix: Bootstrap update and meta parsing
- Rewrite getLauncherMeta() to properly parse server meta response - Change downloadUpdate() fallback to JAR-only (not ZIP) to avoid JRE lock issues - Simplify downloadUpdateLegacy() to skip ZIP (which locks JRE files) - Add handling for AccessDeniedException when updating locked files - Improve error logging for meta parsing failures
This commit is contained in:
@@ -161,9 +161,9 @@ public class Bootstrap {
|
||||
List<Map<String, Object>> files = (List<Map<String, Object>>) meta.get("files");
|
||||
|
||||
if (files == null || files.isEmpty()) {
|
||||
// Мета пустая - fallback на старый метод
|
||||
log("Мета недоступна, используем старый метод");
|
||||
downloadUpdateLegacy(newVersion);
|
||||
// Мета пустая - fallback на JAR обновление
|
||||
log("Мета пустая, используем JAR обновление");
|
||||
downloadUpdateJar(newVersion);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -182,21 +182,29 @@ public class Bootstrap {
|
||||
|
||||
log("К скачиванию: " + toDownload.size() + ", к удалению: " + toDelete.size());
|
||||
|
||||
// 4. Удаляем лишние файлы
|
||||
// 4. Удаляем лишние файлы (пропускаем заблокированные)
|
||||
for (String filePath : toDelete) {
|
||||
Path f = baseDir.resolve(filePath);
|
||||
if (Files.exists(f)) {
|
||||
try {
|
||||
Files.delete(f);
|
||||
log("Удален: " + filePath);
|
||||
} catch (AccessDeniedException e) {
|
||||
log("Пропущен (заблокирован): " + filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Скачиваем новые/измененные файлы
|
||||
// 5. Скачиваем новые/измененные файлы (пропускаем заблокированные)
|
||||
String serverVersion = (String) diff.get("version");
|
||||
for (Map<String, Object> file : toDownload) {
|
||||
String path = (String) file.get("path");
|
||||
try {
|
||||
downloadLauncherFile(serverVersion, path);
|
||||
log("Скачан: " + path);
|
||||
} catch (AccessDeniedException e) {
|
||||
log("Пропущен (заблокирован): " + path);
|
||||
}
|
||||
}
|
||||
|
||||
// 6. Записываем новую версию
|
||||
@@ -205,9 +213,9 @@ public class Bootstrap {
|
||||
|
||||
} catch (Exception e) {
|
||||
log("Ошибка инкрементного обновления: " + e.getMessage());
|
||||
log("Fallback на старый метод...");
|
||||
// Fallback на старый метод
|
||||
downloadUpdateLegacy(newVersion);
|
||||
log("Fallback на JAR обновление...");
|
||||
// Fallback на JAR обновление (не ZIP!)
|
||||
downloadUpdateJar(newVersion);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,23 +234,61 @@ public class Bootstrap {
|
||||
while ((line = br.readLine()) != null) sb.append(line);
|
||||
}
|
||||
|
||||
// Парсим JSON вручную
|
||||
// Парсим JSON вручную - находим первую версию и её meta
|
||||
String json = sb.toString();
|
||||
int versionsStart = json.indexOf("\"versions\"");
|
||||
if (versionsStart == -1) throw new IOException("Нет versions в ответе");
|
||||
|
||||
int arrayStart = json.indexOf("[", versionsStart);
|
||||
int arrayEnd = json.indexOf("]", arrayStart);
|
||||
String versionsArray = json.substring(arrayStart + 1, arrayEnd);
|
||||
// Находим первый объект в массиве versions
|
||||
int versionsIdx = json.indexOf("\"versions\"");
|
||||
if (versionsIdx == -1) throw new IOException("Нет versions в ответе");
|
||||
|
||||
// Ищем первую версию
|
||||
int metaStart = versionsArray.indexOf("\"meta\"");
|
||||
if (metaStart == -1) throw new IOException("Нет meta в версии");
|
||||
// Находим начало массива
|
||||
int arrStart = json.indexOf("[", versionsIdx);
|
||||
if (arrStart == -1) throw new IOException("Нет массива versions");
|
||||
|
||||
int objStart = versionsArray.indexOf("{", metaStart);
|
||||
int objEnd = versionsArray.lastIndexOf("}");
|
||||
// Находим первый объект версии
|
||||
int verObjStart = json.indexOf("{", arrStart);
|
||||
if (verObjStart == -1) throw new IOException("Нет объектов версий");
|
||||
|
||||
String metaJson = versionsArray.substring(objStart, objEnd + 1);
|
||||
// Находим конец этого объекта (с учётом вложенности)
|
||||
int braceCount = 0;
|
||||
int verObjEnd = verObjStart;
|
||||
for (int i = verObjStart; i < json.length(); i++) {
|
||||
char c = json.charAt(i);
|
||||
if (c == '{') braceCount++;
|
||||
else if (c == '}') {
|
||||
braceCount--;
|
||||
if (braceCount == 0) {
|
||||
verObjEnd = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String firstVersionJson = json.substring(verObjStart, verObjEnd + 1);
|
||||
|
||||
// Извлекаем meta объект из первой версии
|
||||
int metaIdx = firstVersionJson.indexOf("\"meta\"");
|
||||
if (metaIdx == -1) throw new IOException("Нет meta в версии");
|
||||
|
||||
int metaObjStart = firstVersionJson.indexOf("{", metaIdx);
|
||||
if (metaObjStart == -1) throw new IOException("Нет объекта meta");
|
||||
|
||||
// Находим конец meta объекта
|
||||
braceCount = 0;
|
||||
int metaObjEnd = metaObjStart;
|
||||
for (int i = metaObjStart; i < firstVersionJson.length(); i++) {
|
||||
char c = firstVersionJson.charAt(i);
|
||||
if (c == '{') braceCount++;
|
||||
else if (c == '}') {
|
||||
braceCount--;
|
||||
if (braceCount == 0) {
|
||||
metaObjEnd = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String metaJson = firstVersionJson.substring(metaObjStart, metaObjEnd + 1);
|
||||
return parseMetaJson(metaJson);
|
||||
}
|
||||
|
||||
@@ -422,55 +468,12 @@ public class Bootstrap {
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback на старый метод (скачивание ZIP)
|
||||
// Fallback на JAR обновление (без ZIP, чтобы избежать блокировки JRE)
|
||||
private static void downloadUpdateLegacy(String newVersion) throws Exception {
|
||||
// Пробуем скачать ZIP
|
||||
String zipUrl = BASE_URL + "/launcher/download/zip/ZernMC-win-" + newVersion + ".zip";
|
||||
URL url = new URL(zipUrl);
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
conn.setRequestMethod("GET");
|
||||
|
||||
if (conn.getResponseCode() == 200) {
|
||||
Path tempZip = baseDir.resolve("update.zip");
|
||||
|
||||
try (InputStream in = conn.getInputStream();
|
||||
OutputStream out = new FileOutputStream(tempZip.toFile())) {
|
||||
byte[] buf = new byte[BUFFER_SIZE];
|
||||
int len;
|
||||
long total = 0;
|
||||
while ((len = in.read(buf)) > 0) {
|
||||
out.write(buf, 0, len);
|
||||
total += len;
|
||||
System.out.print("\rСкачано: " + (total/1024/1024) + " MB");
|
||||
}
|
||||
}
|
||||
log("ZIP скачан, распаковка...");
|
||||
|
||||
// Распаковываем ZIP
|
||||
java.util.zip.ZipFile zip = new java.util.zip.ZipFile(tempZip.toFile());
|
||||
java.util.Enumeration<? extends java.util.zip.ZipEntry> entries = zip.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
java.util.zip.ZipEntry entry = entries.nextElement();
|
||||
Path outPath = baseDir.resolve(entry.getName());
|
||||
if (entry.isDirectory()) {
|
||||
Files.createDirectories(outPath);
|
||||
} else {
|
||||
Files.createDirectories(outPath.getParent());
|
||||
try (InputStream is = zip.getInputStream(entry)) {
|
||||
Files.copy(is, outPath, StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
}
|
||||
}
|
||||
zip.close();
|
||||
Files.delete(tempZip);
|
||||
|
||||
Files.writeString(baseDir.resolve(VERSION_FILE), newVersion);
|
||||
log("Обновлено до v" + newVersion + " (ZIP метод)");
|
||||
} else {
|
||||
// Последний fallback - JAR
|
||||
log("Пропускаем ZIP обновление (может заблокировать JRE)...");
|
||||
log("Используем JAR обновление...");
|
||||
downloadUpdateJar(newVersion);
|
||||
}
|
||||
}
|
||||
|
||||
private static void downloadUpdateJar(String newVersion) throws Exception {
|
||||
URL url = new URL(BASE_URL + "/launcher/download/jar");
|
||||
|
||||
Reference in New Issue
Block a user