@kne/fastify-file-manager 2.0.14 → 3.0.0-alpha.1

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.
@@ -27,13 +27,21 @@ module.exports = ({ DataTypes }) => {
27
27
  type: DataTypes.STRING,
28
28
  allowNull: false,
29
29
  comment: '存储类型:local本地文件系统,oss远程oss存储'
30
+ },
31
+ options: {
32
+ type: DataTypes.JSONB,
33
+ defaultValue: {},
34
+ comment: '扩展字段'
30
35
  }
31
36
  },
32
37
  options: {
33
38
  indexes: [
34
39
  {
35
40
  unique: true,
36
- fields: ['uuid', 'deleted_at']
41
+ fields: ['uuid'],
42
+ where: {
43
+ deleted_at: null
44
+ }
37
45
  },
38
46
  {
39
47
  fields: ['namespace']
@@ -6,12 +6,14 @@ const { NotFound } = require('http-errors');
6
6
  const os = require('node:os');
7
7
  const { Readable } = require('node:stream');
8
8
  const compressing = require('compressing');
9
+ const { glob } = require('glob');
10
+ const MimeTypes = require('mime-types');
9
11
 
10
- module.exports = fp(async (fastify, options) => {
12
+ module.exports = fp(async (fastify, fastifyOptions) => {
11
13
  const { models, services } = fastify.fileManager;
12
14
  const { Op } = fastify.sequelize.Sequelize;
13
15
 
14
- const detail = async ({ id, uuid }) => {
16
+ const detail = async ({ id, uuid, namespace }) => {
15
17
  const file = await models.fileRecord.findOne({
16
18
  where: { uuid: String(id || uuid).split('?')[0] }
17
19
  });
@@ -22,7 +24,7 @@ module.exports = fp(async (fastify, options) => {
22
24
 
23
25
  return file;
24
26
  };
25
- const uploadToFileSystem = async ({ id, file, namespace }) => {
27
+ const uploadToFileSystem = async ({ id, file, namespace, options }) => {
26
28
  const { filename, encoding, mimetype } = file;
27
29
  const hash = crypto.createHash('md5');
28
30
  const extension = path.extname(filename);
@@ -63,7 +65,7 @@ module.exports = fp(async (fastify, options) => {
63
65
  const digest = hash.digest('hex');
64
66
 
65
67
  let storageType;
66
- const ossServices = options.ossAdapter();
68
+ const ossServices = fastifyOptions.ossAdapter();
67
69
  if (typeof ossServices.uploadFile === 'function') {
68
70
  // 使用流上传到OSS
69
71
  const readStream = fs.createReadStream(tmpPath);
@@ -71,7 +73,7 @@ module.exports = fp(async (fastify, options) => {
71
73
  storageType = 'oss';
72
74
  } else {
73
75
  // 使用流写入本地文件
74
- const filepath = path.resolve(options.root, `${digest}${extension}`);
76
+ const filepath = path.resolve(fastifyOptions.root, `${digest}${extension}`);
75
77
  const writeStream = fs.createWriteStream(filepath);
76
78
  const readStream = fs.createReadStream(tmpPath);
77
79
  await new Promise((resolve, reject) => {
@@ -94,23 +96,25 @@ module.exports = fp(async (fastify, options) => {
94
96
  file.hash = digest;
95
97
  file.size = fileSize;
96
98
  file.storageType = storageType;
99
+ file.options = options;
97
100
  await file.save();
98
101
  return file;
99
102
  })(() =>
100
103
  models.fileRecord.create({
101
104
  filename,
102
- namespace: namespace || options.namespace,
105
+ namespace: namespace || fastifyOptions.namespace,
103
106
  encoding,
104
107
  mimetype,
105
108
  hash: digest,
106
109
  size: fileSize,
107
- storageType
110
+ storageType,
111
+ options
108
112
  })
109
113
  );
110
114
  return Object.assign({}, outputFile.get({ plain: true }), { id: outputFile.uuid });
111
115
  };
112
116
 
113
- const uploadFromUrl = async ({ id, url, filename: originFilename, namespace }) => {
117
+ const uploadFromUrl = async ({ id, url, filename: originFilename, namespace, options }) => {
114
118
  const response = await fetch(url);
115
119
  if (!response.ok) {
116
120
  throw new Error('下载文件失败');
@@ -166,13 +170,13 @@ module.exports = fp(async (fastify, options) => {
166
170
  encoding: 'binary',
167
171
  file: nodeStream
168
172
  };
169
- return await uploadToFileSystem({ id, file: tempFile, namespace });
173
+ return await uploadToFileSystem({ id, file: tempFile, namespace, options });
170
174
  };
171
175
 
172
176
  const getFileUrl = async ({ id, namespace }) => {
173
- const file = await detail({ id });
177
+ const file = await detail({ id, namespace });
174
178
  const extension = path.extname(file.filename);
175
- const ossServices = options.ossAdapter();
179
+ const ossServices = fastifyOptions.ossAdapter();
176
180
  if (file.storageType === 'oss' && typeof ossServices.getFileLink !== 'function') {
177
181
  throw new Error('ossAdapter未正确配置无法读取oss类型存储文件');
178
182
  }
@@ -180,17 +184,17 @@ module.exports = fp(async (fastify, options) => {
180
184
  return await ossServices.getFileLink({ filename: `${file.hash}${extension}` });
181
185
  }
182
186
 
183
- if (!(await fs.exists(`${options.root}/${file.hash}${extension}`))) {
187
+ if (!(await fs.exists(`${fastifyOptions.root}/${file.hash}${extension}`))) {
184
188
  throw new NotFound();
185
189
  }
186
- return `${options.prefix}/file/${file.hash}${extension}?filename=${file.filename}`;
190
+ return `${fastifyOptions.prefix}/file/${file.hash}${extension}?filename=${file.filename}`;
187
191
  };
188
192
 
189
- const getFileInfo = async ({ id }) => {
190
- const file = await detail({ id });
193
+ const getFileInfo = async ({ id, namespace }) => {
194
+ const file = await detail({ id, namespace });
191
195
  const extension = path.extname(file.filename);
192
196
  const targetFileName = `${file.hash}${extension}`;
193
- const ossServices = options.ossAdapter();
197
+ const ossServices = fastifyOptions.ossAdapter();
194
198
  if (file.storageType === 'oss' && typeof ossServices.downloadFile !== 'function') {
195
199
  throw new Error('ossAdapter未正确配置无法读取oss类型存储文件');
196
200
  }
@@ -205,8 +209,7 @@ module.exports = fp(async (fastify, options) => {
205
209
  });
206
210
  };
207
211
 
208
- const getFileList = async ({ filter = {}, currentPage, perPage }) => {
209
- // namespace: namespace || options.namespace
212
+ const getFileList = async ({ filter = {}, namespace, currentPage, perPage }) => {
210
213
  const queryFilter = {};
211
214
 
212
215
  if (filter?.filename) {
@@ -228,6 +231,9 @@ module.exports = fp(async (fastify, options) => {
228
231
  [Op.like]: `%${filter.namespace}%`
229
232
  };
230
233
  }
234
+ if (namespace) {
235
+ queryFilter.namespace = namespace;
236
+ }
231
237
 
232
238
  if (filter?.id) {
233
239
  queryFilter.uuid = filter.id;
@@ -281,15 +287,15 @@ module.exports = fp(async (fastify, options) => {
281
287
  await file.save();
282
288
  };
283
289
 
284
- const getFileBlob = async ({ id }) => {
285
- const file = await detail({ id });
290
+ const getFileBlob = async ({ id, namespace }) => {
291
+ const file = await detail({ id, namespace });
286
292
  if (!file) {
287
293
  throw new Error('文件不存在');
288
294
  }
289
295
 
290
296
  const extension = path.extname(file.filename);
291
297
  const targetFileName = `${file.hash}${extension}`;
292
- const ossServices = options.ossAdapter();
298
+ const ossServices = fastifyOptions.ossAdapter();
293
299
 
294
300
  let buffer;
295
301
  if (file.storageType === 'oss') {
@@ -298,7 +304,7 @@ module.exports = fp(async (fastify, options) => {
298
304
  }
299
305
  buffer = await ossServices.downloadFile({ filename: targetFileName });
300
306
  } else {
301
- const filePath = path.resolve(options.root, targetFileName);
307
+ const filePath = path.resolve(fastifyOptions.root, targetFileName);
302
308
  if (!(await fs.exists(filePath))) {
303
309
  throw new NotFound();
304
310
  }
@@ -314,14 +320,14 @@ module.exports = fp(async (fastify, options) => {
314
320
  const getFileReadStream = file => {
315
321
  const extension = path.extname(file.filename);
316
322
  const targetFileName = `${file.hash}${extension}`;
317
- const ossServices = options.ossAdapter();
323
+ const ossServices = fastifyOptions.ossAdapter();
318
324
  if (file.storageType === 'oss') {
319
325
  if (typeof ossServices.getFileStream !== 'function') {
320
326
  throw new Error('ossAdapter未正确配置无法读取oss类型存储文件');
321
327
  }
322
328
  return ossServices.getFileStream({ filename: targetFileName });
323
329
  } else {
324
- const filePath = path.resolve(options.root, targetFileName);
330
+ const filePath = path.resolve(fastifyOptions.root, targetFileName);
325
331
  return fs.createReadStream(filePath);
326
332
  }
327
333
  };
@@ -376,6 +382,46 @@ module.exports = fp(async (fastify, options) => {
376
382
  });
377
383
  };
378
384
 
385
+ //文件解压缩
386
+ const uncompressFile = async ({ id, type = 'zip', namespace, globOptions = '**/*' }) => {
387
+ const file = await detail({ id });
388
+ const fileStream = await getFileReadStream(file);
389
+ const tmpPath = path.resolve(os.tmpdir(), `temp_${id}_${crypto.randomBytes(6).toString('hex')}`);
390
+ await compressing[type].uncompress(fileStream, tmpPath);
391
+ const files = await glob(globOptions, {
392
+ cwd: tmpPath,
393
+ nodir: true
394
+ });
395
+ //将文件上传到文件系统
396
+ const fileList = await Promise.all(
397
+ files.map(async dir => {
398
+ const filepath = path.resolve(tmpPath, dir);
399
+ const filename = path.basename(dir);
400
+ const fileStream = fs.createReadStream(filepath);
401
+
402
+ const mimetype = MimeTypes.lookup(filepath) || 'application/octet-stream';
403
+ const file = await uploadToFileSystem({
404
+ file: {
405
+ filename,
406
+ mimetype,
407
+ encoding: 'binary',
408
+ file: fileStream
409
+ },
410
+ filename,
411
+ namespace
412
+ });
413
+ return {
414
+ dir,
415
+ file
416
+ };
417
+ })
418
+ );
419
+ //清除临时文件
420
+ await fs.remove(tmpPath);
421
+
422
+ return fileList;
423
+ };
424
+
379
425
  const getFileInstance = async ({ id, uuid }) => {
380
426
  return detail({ id, uuid });
381
427
  };
@@ -393,6 +439,7 @@ module.exports = fp(async (fastify, options) => {
393
439
  getFileReadStream,
394
440
  getCompressFileStream,
395
441
  getCompressFileBlob,
442
+ uncompressFile,
396
443
  getFileInstance, // 兼容之前api,后面可能会删掉
397
444
  fileRecord: {
398
445
  uploadToFileSystem,
@@ -407,6 +454,7 @@ module.exports = fp(async (fastify, options) => {
407
454
  getFileReadStream,
408
455
  getCompressFileStream,
409
456
  getCompressFileBlob,
457
+ uncompressFile,
410
458
  getFileInstance
411
459
  }
412
460
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kne/fastify-file-manager",
3
- "version": "2.0.14",
3
+ "version": "3.0.0-alpha.1",
4
4
  "description": "用于管理静态文件上传查看等",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -51,6 +51,8 @@
51
51
  "@fastify/static": "^8.1.1",
52
52
  "compressing": "^2.0.0",
53
53
  "fs-extra": "^11.2.0",
54
- "http-errors": "^2.0.0"
54
+ "glob": "^13.0.0",
55
+ "http-errors": "^2.0.0",
56
+ "mime-types": "^3.0.2"
55
57
  }
56
58
  }