@ian2018cs/agenthub 0.1.44 → 0.1.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,78 @@
1
+ /**
2
+ * image-storage.js — 图片文件系统持久化存储
3
+ *
4
+ * 存储路径: data/images/{userUuid}/{hash前2字符}/{sha256hash}.{ext}
5
+ * 按内容 hash 去重:同一用户同内容图片只存一份文件。
6
+ */
7
+
8
+ import crypto from 'crypto';
9
+ import { promises as fs } from 'fs';
10
+ import path from 'path';
11
+
12
+ const DATA_DIR = process.env.DATA_DIR || path.join(process.cwd(), 'data');
13
+ const IMAGES_DIR = path.join(DATA_DIR, 'images');
14
+
15
+ /**
16
+ * 计算 buffer 的 SHA-256 hex
17
+ */
18
+ function computeHash(buffer) {
19
+ return crypto.createHash('sha256').update(buffer).digest('hex');
20
+ }
21
+
22
+ /**
23
+ * 构建图片文件的绝对路径
24
+ */
25
+ function buildImagePath(userUuid, fileHash, fileExt) {
26
+ const prefix = fileHash.substring(0, 2);
27
+ return path.join(IMAGES_DIR, userUuid, prefix, `${fileHash}.${fileExt}`);
28
+ }
29
+
30
+ /**
31
+ * 保存图片到文件系统(按内容 hash 去重)
32
+ * @param {string} userUuid
33
+ * @param {Buffer} buffer - 图片原始二进制
34
+ * @param {string} ext - 扩展名(不含点,如 'png')
35
+ * @returns {Promise<{fileHash: string, alreadyExisted: boolean}>}
36
+ */
37
+ async function saveImage(userUuid, buffer, ext) {
38
+ const fileHash = computeHash(buffer);
39
+ const filePath = buildImagePath(userUuid, fileHash, ext);
40
+
41
+ try {
42
+ await fs.access(filePath);
43
+ return { fileHash, alreadyExisted: true };
44
+ } catch {
45
+ // 文件不存在,写入
46
+ }
47
+
48
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
49
+ await fs.writeFile(filePath, buffer);
50
+ return { fileHash, alreadyExisted: false };
51
+ }
52
+
53
+ /**
54
+ * 获取图片文件的绝对路径
55
+ */
56
+ function getImagePath(userUuid, fileHash, fileExt) {
57
+ return buildImagePath(userUuid, fileHash, fileExt);
58
+ }
59
+
60
+ /**
61
+ * 删除图片文件(忽略不存在的情况)
62
+ */
63
+ async function deleteImageFile(userUuid, fileHash, fileExt) {
64
+ const filePath = buildImagePath(userUuid, fileHash, fileExt);
65
+ try {
66
+ await fs.unlink(filePath);
67
+ } catch (err) {
68
+ if (err.code !== 'ENOENT') throw err;
69
+ }
70
+ }
71
+
72
+ export {
73
+ IMAGES_DIR,
74
+ computeHash,
75
+ saveImage,
76
+ getImagePath,
77
+ deleteImageFile,
78
+ };