Skip to content

Commit 8615a8e

Browse files
committed
✨ Load .prg file from old version
1 parent 69e5524 commit 8615a8e

File tree

2 files changed

+60
-23
lines changed

2 files changed

+60
-23
lines changed

app/src/core/Project.tsx

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -228,29 +228,33 @@ export class Project extends EventEmitter<{
228228
if (!(await this.fs.exists(this.uri))) {
229229
return;
230230
}
231-
const fileContent = await this.fs.read(this.uri);
232-
const reader = new ZipReader(new Uint8ArrayReader(fileContent));
233-
const entries = await reader.getEntries();
234-
let serializedStageObjects: any[] = [];
235-
for (const entry of entries) {
236-
if (entry.filename === "stage.msgpack") {
237-
const stageRawData = await entry.getData!(new Uint8ArrayWriter());
238-
serializedStageObjects = this.decoder.decode(stageRawData) as any[];
239-
// console.log(JSON.stringify(serializedStageObjects, null, 2));
240-
} else if (entry.filename.startsWith("attachments/")) {
241-
const match = entry.filename.trim().match(/^attachments\/([a-zA-Z0-9-]+)\.([a-zA-Z0-9]+)$/);
242-
if (!match) {
243-
console.warn("[Project] 附件文件名不符合规范: %s", entry.filename);
244-
continue;
231+
try {
232+
const fileContent = await this.fs.read(this.uri);
233+
const reader = new ZipReader(new Uint8ArrayReader(fileContent));
234+
const entries = await reader.getEntries();
235+
let serializedStageObjects: any[] = [];
236+
for (const entry of entries) {
237+
if (entry.filename === "stage.msgpack") {
238+
const stageRawData = await entry.getData!(new Uint8ArrayWriter());
239+
serializedStageObjects = this.decoder.decode(stageRawData) as any[];
240+
// console.log(JSON.stringify(serializedStageObjects, null, 2));
241+
} else if (entry.filename.startsWith("attachments/")) {
242+
const match = entry.filename.trim().match(/^attachments\/([a-zA-Z0-9-]+)\.([a-zA-Z0-9]+)$/);
243+
if (!match) {
244+
console.warn("[Project] 附件文件名不符合规范: %s", entry.filename);
245+
continue;
246+
}
247+
const uuid = match[1];
248+
const ext = match[2];
249+
const type = mime.getType(ext) || "application/octet-stream";
250+
const attachment = await entry.getData!(new BlobWriter(type));
251+
this.attachments.set(uuid, attachment);
245252
}
246-
const uuid = match[1];
247-
const ext = match[2];
248-
const type = mime.getType(ext) || "application/octet-stream";
249-
const attachment = await entry.getData!(new BlobWriter(type));
250-
this.attachments.set(uuid, attachment);
251253
}
254+
this.stage = deserialize(serializedStageObjects, this);
255+
} catch (e) {
256+
console.warn(e);
252257
}
253-
this.stage = deserialize(serializedStageObjects, this);
254258
this.state = ProjectState.Saved;
255259
}
256260

app/src/core/service/GlobalMenu.tsx

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@ import NodeDetailsWindow from "@/sub/NodeDetailsWindow";
2020
import SettingsWindow from "@/sub/SettingsWindow";
2121
import { getDeviceId } from "@/utils/otherApi";
2222
import { deserialize, serialize } from "@graphif/serializer";
23+
import { Decoder } from "@msgpack/msgpack";
2324
import { getVersion } from "@tauri-apps/api/app";
2425
import { appCacheDir, dataDir, join } from "@tauri-apps/api/path";
2526
import { getCurrentWindow } from "@tauri-apps/api/window";
2627
import { open, save } from "@tauri-apps/plugin-dialog";
27-
import { readTextFile, writeTextFile } from "@tauri-apps/plugin-fs";
28+
import { readFile, writeTextFile } from "@tauri-apps/plugin-fs";
2829
import { open as shellOpen } from "@tauri-apps/plugin-shell";
2930
import { useAtom } from "jotai";
3031
import {
@@ -609,8 +610,14 @@ export async function onOpenFile(uri?: URI, source: string = "unknown") {
609610
uri = URI.file(path);
610611
}
611612
let upgraded: ReturnType<typeof ProjectUpgrader.convertVAnyToN1> extends Promise<infer T> ? T : never;
612-
if (uri.fsPath.endsWith(".json")) {
613-
const content = await readTextFile(uri.fsPath);
613+
614+
// 读取文件内容并判断格式
615+
const fileData = await readFile(uri.fsPath);
616+
617+
// 检查是否是以 '{' 开头的 JSON 文件
618+
if (fileData[0] === 0x7b) {
619+
// 0x7B 是 '{' 的 ASCII 码
620+
const content = new TextDecoder().decode(fileData);
614621
const json = JSON.parse(content);
615622
const t = performance.now();
616623
upgraded = await toast
@@ -630,6 +637,32 @@ export async function onOpenFile(uri?: URI, source: string = "unknown") {
630637
toast.info("您正在尝试导入旧版的文件!稍后如果点击了保存文件,文件会保存为相同文件夹内的 .prg 后缀的文件");
631638
uri = uri.with({ path: uri.path.replace(/\.json$/, ".prg") });
632639
}
640+
// 检查是否是以 0x91 0x86 开头的 msgpack 数据
641+
if (fileData.length >= 2 && fileData[0] === 0x84 && fileData[1] === 0xa7) {
642+
const decoder = new Decoder();
643+
const decodedData = decoder.decode(fileData);
644+
if (typeof decodedData !== "object" || decodedData === null) {
645+
throw new Error("msgpack 解码结果不是有效的对象");
646+
}
647+
const t = performance.now();
648+
upgraded = await toast
649+
.promise(ProjectUpgrader.convertVAnyToN1(decodedData as Record<string, any>, uri), {
650+
loading: "正在转换旧版项目文件...",
651+
success: () => {
652+
const time = performance.now() - t;
653+
Telemetry.event("转换vany->n1", { time, length: fileData.length });
654+
return `转换成功,耗时 ${time}ms`;
655+
},
656+
error: (e) => {
657+
Telemetry.event("转换vany->n1报错", { error: String(e) });
658+
return `转换失败,已发送错误报告,可在群内联系开发者\n${String(e)}`;
659+
},
660+
})
661+
.unwrap();
662+
toast.info("您正在尝试导入旧版的文件!稍后如果点击了保存文件,文件会保存为相同文件夹内的 .prg 后缀的文件");
663+
uri = uri.with({ path: uri.path.replace(/\.json$/, ".prg") });
664+
}
665+
633666
if (store.get(projectsAtom).some((p) => p.uri.toString() === uri.toString())) {
634667
store.set(activeProjectAtom, store.get(projectsAtom).find((p) => p.uri.toString() === uri.toString())!);
635668
store.get(activeProjectAtom)?.loop();

0 commit comments

Comments
 (0)