Skip to content

Commit eebdbe4

Browse files
committed
feat: refactor local storage
1 parent aa273b8 commit eebdbe4

15 files changed

Lines changed: 1502 additions & 205 deletions

src/layouts/default.tsx

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import { items, SidebarKeys } from "@/components/sidebar/Items.tsx";
1717
import { ThemeSwitch } from "@/components/button/ThemeSwitch.tsx";
1818
import { useSidebarStore } from "@/store/useSidebarStore";
1919
import { useSettingsStore } from "@/store/useSettingsStore";
20-
import { useTabStore } from "@/store/useTabStore";
2120
import { getFontSizeConfig } from "@/styles/fontSize";
2221

2322
function RootLayout({
@@ -26,7 +25,6 @@ function RootLayout({
2625
children: React.ReactNode;
2726
}) {
2827
const sidebarStore = useSidebarStore();
29-
const { initTab } = useTabStore();
3028
const navigate = useNavigate();
3129
const location = useLocation();
3230

@@ -66,17 +64,11 @@ function RootLayout({
6664
await useSettingsStore.getState().syncSettingsStore();
6765

6866
// 获取同步后的设置状态
69-
const editDataSaveLocal = useSettingsStore.getState().editDataSaveLocal;
7067
const expandSidebar = useSettingsStore.getState().expandSidebar;
7168

72-
if (editDataSaveLocal) {
73-
// 如果启用了本地存储,同步侧边栏状态
74-
setIsCollapsed(!expandSidebar);
75-
await sidebarStore.syncSidebarStore();
76-
} else {
77-
// 如果未启用本地存储,初始化默认标签页
78-
initTab();
79-
}
69+
// 本地存储始终启用,同步侧边栏状态
70+
setIsCollapsed(!expandSidebar);
71+
await sidebarStore.syncSidebarStore();
8072
};
8173

8274
init();

src/lib/historyStorage.ts

Lines changed: 54 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,13 @@
11
/**
22
* 历史记录存储管理器
3-
* 使用 IndexedDB 存储历史记录,性能优化版本
3+
* 使用新的存储管理器存储历史记录,性能优化版本
44
*/
55

6-
import localforage from 'localforage';
7-
import { HistoryItem } from '@/types/history';
6+
import { StorageManager } from "./storage/StorageManager";
87

9-
/**
10-
* 历史记录存储实例
11-
*/
12-
const historyStorage = localforage.createInstance({
13-
name: 'json-tools',
14-
storeName: 'histories',
15-
});
8+
import { HistoryItem } from "@/types/history";
169

10+
const storageManager = new StorageManager();
1711
const MAX_HISTORIES = 200; // 最大历史记录数量
1812

1913
/**
@@ -25,11 +19,13 @@ export class HistoryStorageManager {
2519
*/
2620
static async getAllHistories(): Promise<HistoryItem[]> {
2721
try {
28-
const keys = await historyStorage.keys();
22+
const keys = await storageManager.keys();
23+
const historyKeys = keys.filter((key) => key.startsWith("history_"));
2924
const items: HistoryItem[] = [];
3025

31-
for (const key of keys) {
32-
const item = await historyStorage.getItem<HistoryItem>(key);
26+
for (const key of historyKeys) {
27+
const item = await storageManager.get<HistoryItem>(key);
28+
3329
if (item) {
3430
items.push(item);
3531
}
@@ -38,7 +34,8 @@ export class HistoryStorageManager {
3834
// 按时间戳降序排序(最新的在前)
3935
return items.sort((a, b) => b.timestamp - a.timestamp);
4036
} catch (error) {
41-
console.error('获取历史记录失败:', error);
37+
console.error("获取历史记录失败:", error);
38+
4239
return [];
4340
}
4441
}
@@ -49,13 +46,22 @@ export class HistoryStorageManager {
4946
*/
5047
static async addHistory(history: HistoryItem): Promise<void> {
5148
try {
52-
// 保存新记录
53-
await historyStorage.setItem(history.key, history);
49+
// 保存新记录(立即保存,确保不丢失)
50+
await storageManager.set(history.key, history, { immediate: true });
5451

5552
// 检查并清理旧记录
5653
await this.cleanupOldHistories();
5754
} catch (error) {
58-
console.error('添加历史记录失败:', error);
55+
console.error("添加历史记录失败:", error);
56+
// 重试一次
57+
try {
58+
await storageManager.set(history.key, history, {
59+
immediate: true,
60+
retryCount: 3,
61+
});
62+
} catch (retryError) {
63+
console.error("重试添加历史记录失败:", retryError);
64+
}
5965
}
6066
}
6167

@@ -64,14 +70,16 @@ export class HistoryStorageManager {
6470
*/
6571
private static async cleanupOldHistories(): Promise<void> {
6672
try {
67-
const keys = await historyStorage.keys();
73+
const keys = await storageManager.keys();
74+
const historyKeys = keys.filter((key) => key.startsWith("history_"));
6875

69-
if (keys.length > MAX_HISTORIES) {
76+
if (historyKeys.length > MAX_HISTORIES) {
7077
// 按时间戳排序,删除最旧的记录
7178
const items: Array<{ key: string; timestamp: number }> = [];
7279

73-
for (const key of keys) {
74-
const item = await historyStorage.getItem<HistoryItem>(key);
80+
for (const key of historyKeys) {
81+
const item = await storageManager.get<HistoryItem>(key);
82+
7583
if (item) {
7684
items.push({ key: item.key, timestamp: item.timestamp });
7785
}
@@ -82,14 +90,15 @@ export class HistoryStorageManager {
8290

8391
// 删除超出数量的旧记录
8492
const toDelete = items.slice(0, items.length - MAX_HISTORIES);
93+
8594
for (const item of toDelete) {
86-
await historyStorage.removeItem(item.key);
95+
await storageManager.remove(item.key);
8796
}
8897

8998
console.log(`清理了 ${toDelete.length} 条历史记录`);
9099
}
91100
} catch (error) {
92-
console.error('清理历史记录失败:', error);
101+
console.error("清理历史记录失败:", error);
93102
}
94103
}
95104

@@ -98,9 +107,9 @@ export class HistoryStorageManager {
98107
*/
99108
static async removeHistory(key: string): Promise<void> {
100109
try {
101-
await historyStorage.removeItem(key);
110+
await storageManager.remove(key);
102111
} catch (error) {
103-
console.error('删除历史记录失败:', error);
112+
console.error("删除历史记录失败:", error);
104113
}
105114
}
106115

@@ -109,10 +118,16 @@ export class HistoryStorageManager {
109118
*/
110119
static async clearHistories(): Promise<void> {
111120
try {
112-
await historyStorage.clear();
113-
console.log('已清空所有历史记录');
121+
const keys = await storageManager.keys();
122+
const historyKeys = keys.filter((key) => key.startsWith("history_"));
123+
124+
for (const key of historyKeys) {
125+
await storageManager.remove(key);
126+
}
127+
128+
console.log("已清空所有历史记录");
114129
} catch (error) {
115-
console.error('清空历史记录失败:', error);
130+
console.error("清空历史记录失败:", error);
116131
}
117132
}
118133

@@ -121,10 +136,12 @@ export class HistoryStorageManager {
121136
*/
122137
static async getHistory(key: string): Promise<HistoryItem | null> {
123138
try {
124-
const item = await historyStorage.getItem<HistoryItem>(key);
139+
const item = await storageManager.get<HistoryItem>(key);
140+
125141
return item;
126142
} catch (error) {
127-
console.error('获取历史记录失败:', error);
143+
console.error("获取历史记录失败:", error);
144+
128145
return null;
129146
}
130147
}
@@ -143,7 +160,8 @@ export class HistoryStorageManager {
143160
item.content.toLowerCase().includes(lowerKeyword),
144161
);
145162
} catch (error) {
146-
console.error('搜索历史记录失败:', error);
163+
console.error("搜索历史记录失败:", error);
164+
147165
return [];
148166
}
149167
}
@@ -153,9 +171,12 @@ export class HistoryStorageManager {
153171
*/
154172
static async getCount(): Promise<number> {
155173
try {
156-
return await historyStorage.length();
174+
const keys = await storageManager.keys();
175+
176+
return keys.filter((key) => key.startsWith("history_")).length;
157177
} catch (error) {
158-
console.error('获取历史记录数量失败:', error);
178+
console.error("获取历史记录数量失败:", error);
179+
159180
return 0;
160181
}
161182
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/**
2+
* 数据完整性校验器
3+
* 提供数据校验和版本向量比较功能
4+
*/
5+
6+
import crypto from "crypto";
7+
8+
import { VersionVector } from "./types";
9+
10+
export class DataIntegrityChecker {
11+
/**
12+
* 计算数据的校验和
13+
*/
14+
static calculateChecksum(data: any): string {
15+
try {
16+
const json = JSON.stringify(data);
17+
const hash = crypto.createHash("sha256");
18+
19+
hash.update(json);
20+
21+
return hash.digest("hex");
22+
} catch (error) {
23+
console.error("计算校验和失败:", error);
24+
25+
return "";
26+
}
27+
}
28+
29+
/**
30+
* 验证数据完整性
31+
*/
32+
static validate(data: any, checksum: string): boolean {
33+
const calculated = this.calculateChecksum(data);
34+
35+
return calculated === checksum;
36+
}
37+
38+
/**
39+
* 比较版本向量
40+
* 返回: 1 (v1 > v2), -1 (v1 < v2), 0 (冲突)
41+
*/
42+
static compareVersions(v1: VersionVector, v2: VersionVector): number {
43+
const allKeys = new Set([...Object.keys(v1), ...Object.keys(v2)]);
44+
let greater = false;
45+
let lesser = false;
46+
47+
for (const key of allKeys) {
48+
const version1 = v1[key] || 0;
49+
const version2 = v2[key] || 0;
50+
51+
if (version1 > version2) {
52+
greater = true;
53+
} else if (version1 < version2) {
54+
lesser = true;
55+
}
56+
}
57+
58+
if (greater && !lesser) return 1;
59+
if (lesser && !greater) return -1;
60+
61+
return 0; // 并发冲突
62+
}
63+
64+
/**
65+
* 合并版本向量
66+
*/
67+
static mergeVersions(v1: VersionVector, v2: VersionVector): VersionVector {
68+
const merged: VersionVector = { ...v1 };
69+
70+
for (const key of Object.keys(v2)) {
71+
merged[key] = Math.max(merged[key] || 0, v2[key]);
72+
}
73+
74+
return merged;
75+
}
76+
77+
/**
78+
* 验证数据结构
79+
*/
80+
static validateStructure(data: any, schema?: any): boolean {
81+
if (data === null || data === undefined) {
82+
return false;
83+
}
84+
85+
// 如果提供了 schema,进行深度验证
86+
if (schema) {
87+
return this.validateAgainstSchema(data, schema);
88+
}
89+
90+
// 基本验证
91+
try {
92+
JSON.stringify(data);
93+
94+
return true;
95+
} catch (error) {
96+
return false;
97+
}
98+
}
99+
100+
/**
101+
* 根据验证模式验证数据
102+
*/
103+
private static validateAgainstSchema(data: any, schema: any): boolean {
104+
// 简单的 schema 验证实现
105+
// 可以根据需要扩展为更复杂的验证逻辑
106+
if (schema.type) {
107+
const dataType = Array.isArray(data) ? "array" : typeof data;
108+
109+
if (dataType !== schema.type) {
110+
return false;
111+
}
112+
}
113+
114+
if (schema.required && Array.isArray(schema.required)) {
115+
for (const field of schema.required) {
116+
if (!(field in data)) {
117+
return false;
118+
}
119+
}
120+
}
121+
122+
return true;
123+
}
124+
}

0 commit comments

Comments
 (0)