Skip to content

Commit

Permalink
✨ 兼容tm的储存导入导出
Browse files Browse the repository at this point in the history
  • Loading branch information
CodFrm committed Dec 2, 2022
1 parent 6960b6c commit 2eed348
Show file tree
Hide file tree
Showing 9 changed files with 98 additions and 28 deletions.
2 changes: 1 addition & 1 deletion pkg/filesystem/filesystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export interface File {
updatetime: number;
}

type ReadType = "string" | "blob" | "base64";
type ReadType = "string" | "blob";
export interface FileReader {
// 读取文件内容
read(type?: ReadType): Promise<any>;
Expand Down
2 changes: 1 addition & 1 deletion src/app/service/script/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export default class ScriptController {
}

// 安装或者更新脚本
public upsert(script: Script) {
public upsert(script: Script): Promise<{ id: number }> {
return this.dispatchEvent("upsert", script);
}

Expand Down
13 changes: 10 additions & 3 deletions src/pages/import/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
} from "@App/app/repo/scripts";
import { Subscribe } from "@App/app/repo/subscribe";
import ScriptController from "@App/app/service/script/controller";
import ValueController from "@App/app/service/value/controller";

type ScriptData = ScriptBackupData & {
script?: Script & { oldScript?: Script };
Expand All @@ -45,6 +46,7 @@ function App() {
const [installNum, setInstallNum] = useState([0, 0]);
const [loading, setLoading] = useState(true);
const scriptCtrl = IoC.instance(ScriptController) as ScriptController;
const valueCtrl = IoC.instance(ValueController) as ValueController;
const syncCtrl = IoC.instance(SynchronizeController) as SynchronizeController;
const url = new URL(window.location.href);
const uuid = url.searchParams.get("uuid") || "";
Expand Down Expand Up @@ -118,14 +120,19 @@ function App() {
onClick={async () => {
setLoading(true);
const result = scripts.map(async (item) => {
let resp = true;
const ok = true;
if (item.install && !item.error) {
resp = await scriptCtrl.upsert(item.script!);
const resp = await scriptCtrl.upsert(item.script!);
// 导入数据
const { data } = item.storage;
Object.keys(data).forEach((key) => {
valueCtrl.setValue(resp.id, key, data[key]);
});
}
setInstallNum((prev) => {
return [prev[0] + 1, prev[1]];
});
return Promise.resolve(resp);
return Promise.resolve(ok);
});
await Promise.all(result);
setLoading(false);
Expand Down
18 changes: 13 additions & 5 deletions src/pkg/backup/backup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,28 +51,30 @@ describe("backup", () => {
resources: [
{
meta: { name: "test1", mimetype: "text/plain" },
base64: "aGVsbG8gd29ybGQ=",
base64: "data:text/plain;base64,aGVsbG8gd29ybGQ=",
source: "hello world",
},
],
requires: [
{
meta: { name: "test2", mimetype: "text/plain" },
base64: "aGVsbG8gd29ybGQ=",
base64: "data:text/plain;base64,aGVsbG8gd29ybGQ=",
source: "hello world",
},
],
requiresCss: [
{
meta: { name: "test3", mimetype: "text/plain" },
base64: "aGVsbG8gd29ybGQ=",
meta: { name: "test3", mimetype: "application/javascript" },
base64: "data:application/javascript;base64,aGVsbG8gd29ybGQ=",
source: "hello world",
},
],
storage: {
ts: 1,
data: {
data: 1,
num: 1,
str: "data",
bool: false,
},
},
},
Expand All @@ -99,7 +101,13 @@ describe("backup", () => {
],
} as unknown as BackupData;
await new BackupExport(fs).export(data);
expect(data.script[0].storage.data.num).toEqual("n1");
expect(data.script[0].storage.data.str).toEqual("sdata");
expect(data.script[0].storage.data.bool).toEqual("bfalse");
const resp = await new BackupImport(fs).parse();
data.script[0].storage.data.num = 1;
data.script[0].storage.data.str = "data";
data.script[0].storage.data.bool = false;
expect(resp).toEqual(data);
});
});
13 changes: 7 additions & 6 deletions src/pkg/backup/export.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import FileSystem from "@Pkg/filesystem/filesystem";
import crypto from "crypto-js";
import ResourceManager from "@App/app/service/resource/manager";
import { base64ToBlob } from "../utils/script";
import { toStorageValueStr } from "../utils/utils";
import {
BackupData,
ResourceBackup,
Expand Down Expand Up @@ -39,9 +39,13 @@ export default class BackupExport {
).write(JSON.stringify(script.options));
// 写入脚本storage.json
// 不想兼容tm的导出规则了,直接写入storage.json
const storage = { ...script.storage };
Object.keys(storage.data).forEach((key: string) => {
storage.data[key] = toStorageValueStr(storage.data[key]);
});
await (
await this.fs.create(`${name}.storage.json`)
).write(JSON.stringify(script.storage));
).write(JSON.stringify(storage));
// 写入脚本资源文件
await this.writeResource(name, script.resources, "resources");
await this.writeResource(name, script.requires, "requires");
Expand All @@ -58,10 +62,7 @@ export default class BackupExport {
const results: Promise<void>[] = resources.map(async (item) => {
// md5是tm的导出规则
const md5 = crypto.MD5(`${type}{val.meta.url}`).toString();
if (
item.meta.mimetype?.startsWith("text/") ||
ResourceManager.textContentTypeMap.has(item.meta.mimetype || "")
) {
if (item.source) {
await (
await this.fs.create(`${name}.user.js-${md5}-${item.meta.name}`)
).write(item.source!);
Expand Down
28 changes: 20 additions & 8 deletions src/pkg/backup/import.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import LoggerCore from "@App/app/logger/core";
import Logger from "@App/app/logger/logger";
import ResourceManager from "@App/app/service/resource/manager";
import FileSystem, { File } from "@Pkg/filesystem/filesystem";
import { isText } from "../utils/istextorbinary";
import { blobToBase64 } from "../utils/script";
import { parseStorageValue } from "../utils/utils";
import {
BackupData,
ResourceBackup,
Expand Down Expand Up @@ -99,6 +101,9 @@ export default class BackupImport {
const data = <ValueStorage>(
JSON.parse(await (await this.fs.open(file)).read())
);
Object.keys(data.data).forEach((dataKey) => {
data.data[dataKey] = parseStorageValue(data.data[dataKey]);
});
map.get(key)!.storage = data;
return Promise.resolve(true);
});
Expand Down Expand Up @@ -162,14 +167,21 @@ export default class BackupImport {
return Promise.resolve(false);
}
const resource = map.get(info.key)![info.type][info.index];
resource.base64 = await (await this.fs.open(file)).read("base64");
if (
resource.meta &&
(resource.meta.mimetype?.startsWith("text/") ||
ResourceManager.textContentTypeMap.has(resource.meta.mimetype || ""))
) {
resource.base64 = await blobToBase64(
await (await this.fs.open(file)).read("blob")
);
if (resource.meta) {
// 存在meta
resource.source = await (await this.fs.open(file)).read();
// 替换base64前缀
if (resource.meta.mimetype) {
resource.base64 = resource.base64.replace(
/^data:.*?;base64,/,
`data:${resource.meta.mimetype};base64,`
);
}
if (isText(await (await this.fs.open(file)).read("blob"))) {
resource.source = await (await this.fs.open(file)).read();
}
}
return Promise.resolve(true);
});
Expand Down
5 changes: 3 additions & 2 deletions src/pkg/backup/struct.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/* eslint-disable camelcase */
import { Metadata } from "@App/app/repo/scripts";

export type ResourceMeta = {
name: string;
Expand All @@ -10,12 +9,14 @@ export type ResourceMeta = {

export type ResourceBackup = {
meta: ResourceMeta;
// text数据
source?: string;
// 二进制数据
base64: string;
};

export type ValueStorage = {
data: { [key: string]: string };
data: { [key: string]: any };
ts: number;
};

Expand Down
4 changes: 2 additions & 2 deletions src/pkg/utils/script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,10 +151,10 @@ export function copySubscribe(sub: Subscribe, old: Subscribe): Subscribe {
return ret;
}

export function blobToBase64(blob: Blob): Promise<string | null> {
export function blobToBase64(blob: Blob): Promise<string> {
return new Promise((resolve) => {
const reader = new FileReader();
reader.onloadend = () => resolve(<string | null>reader.result);
reader.onloadend = () => resolve(<string>reader.result);
reader.readAsDataURL(blob);
});
}
Expand Down
41 changes: 41 additions & 0 deletions src/pkg/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,47 @@ export function valueType(val: any) {
}
}

export function toStorageValueStr(val: any): string {
switch (typeof val) {
case "string":
return `s${val}`;
case "number":
return `n${val.toString()}`;
case "boolean":
return `b${val ? "true" : "false"}`;
default:
try {
return `o${JSON.stringify(val)}`;
} catch (e) {
return "";
}
}
}

export function parseStorageValue(str: string): any {
if (str === "") {
return undefined;
}
const t = str[0];
const s = str.substring(1);
switch (t) {
case "b":
return s === "true";
case "n":
return parseFloat(s);
case "o":
try {
return JSON.parse(s);
} catch (e) {
return str;
}
case "s":
return s;
default:
return str;
}
}

// 尝试重新链接和超时通知
export function tryConnect(
message: MessageInternal,
Expand Down

0 comments on commit 2eed348

Please sign in to comment.