@kne/fastify-file-manager 3.0.1-alpha.1 → 3.0.1-alpha.3
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.
- package/libs/services/file-record.js +53 -21
- package/package.json +4 -2
|
@@ -13,6 +13,8 @@ module.exports = fp(async (fastify, fastifyOptions) => {
|
|
|
13
13
|
const { models, services } = fastify.fileManager;
|
|
14
14
|
const { Op } = fastify.sequelize.Sequelize;
|
|
15
15
|
|
|
16
|
+
const sanitizeFilename = filename => filename.replace(/[\\/:*?"<>|\0]/g, '_');
|
|
17
|
+
|
|
16
18
|
const detail = async ({ id, uuid, namespace }) => {
|
|
17
19
|
const file = await models.fileRecord.findOne({
|
|
18
20
|
where: { uuid: String(id || uuid).split('?')[0] }
|
|
@@ -25,14 +27,14 @@ module.exports = fp(async (fastify, fastifyOptions) => {
|
|
|
25
27
|
return file;
|
|
26
28
|
};
|
|
27
29
|
const uploadToFileSystem = async ({ id, file, namespace, options }) => {
|
|
28
|
-
const {
|
|
30
|
+
const { encoding, mimetype } = file;
|
|
31
|
+
const filename = sanitizeFilename(file.filename);
|
|
29
32
|
const hash = crypto.createHash('md5');
|
|
30
33
|
const extension = path.extname(filename);
|
|
31
34
|
const tmpPath = path.resolve(os.tmpdir(), `temp_${filename}_${crypto.randomBytes(6).toString('hex')}`);
|
|
32
35
|
let fileSize = 0;
|
|
33
36
|
if (file.file) {
|
|
34
37
|
const writeStream = fs.createWriteStream(tmpPath);
|
|
35
|
-
|
|
36
38
|
await new Promise((resolve, reject) => {
|
|
37
39
|
const cleanup = () => {
|
|
38
40
|
file.file.removeAllListeners();
|
|
@@ -74,8 +76,15 @@ module.exports = fp(async (fastify, fastifyOptions) => {
|
|
|
74
76
|
await fs.writeFile(tmpPath, buffer);
|
|
75
77
|
fileSize = buffer.byteLength;
|
|
76
78
|
} else if (file.filepath) {
|
|
79
|
+
const readStream = fs.createReadStream(file.filepath);
|
|
80
|
+
await new Promise((resolve, reject) => {
|
|
81
|
+
readStream.on('data', chunk => hash.update(chunk));
|
|
82
|
+
readStream.on('end', resolve);
|
|
83
|
+
readStream.on('error', reject);
|
|
84
|
+
});
|
|
77
85
|
await fs.copy(file.filepath, tmpPath);
|
|
78
86
|
const stat = await fs.stat(tmpPath);
|
|
87
|
+
|
|
79
88
|
fileSize = stat.size;
|
|
80
89
|
} else {
|
|
81
90
|
throw new Error('文件类型不支持');
|
|
@@ -118,16 +127,18 @@ module.exports = fp(async (fastify, fastifyOptions) => {
|
|
|
118
127
|
file.options = options;
|
|
119
128
|
await file.save();
|
|
120
129
|
return file;
|
|
121
|
-
})(() =>
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
130
|
+
})(() =>
|
|
131
|
+
models.fileRecord.create({
|
|
132
|
+
filename,
|
|
133
|
+
namespace: namespace || fastifyOptions.namespace,
|
|
134
|
+
encoding,
|
|
135
|
+
mimetype,
|
|
136
|
+
hash: digest,
|
|
137
|
+
size: fileSize,
|
|
138
|
+
storageType,
|
|
139
|
+
options
|
|
140
|
+
})
|
|
141
|
+
);
|
|
131
142
|
return Object.assign({}, outputFile.get({ plain: true }), { id: outputFile.uuid });
|
|
132
143
|
};
|
|
133
144
|
|
|
@@ -182,7 +193,10 @@ module.exports = fp(async (fastify, fastifyOptions) => {
|
|
|
182
193
|
}
|
|
183
194
|
|
|
184
195
|
const tempFile = {
|
|
185
|
-
filename
|
|
196
|
+
filename: sanitizeFilename(filename),
|
|
197
|
+
mimetype: response.headers.get('content-type'),
|
|
198
|
+
encoding: 'binary',
|
|
199
|
+
file: nodeStream
|
|
186
200
|
};
|
|
187
201
|
return await uploadToFileSystem({ id, file: tempFile, namespace, options });
|
|
188
202
|
};
|
|
@@ -217,7 +231,9 @@ module.exports = fp(async (fastify, fastifyOptions) => {
|
|
|
217
231
|
targetFile = await ossServices.downloadFile({ filename: targetFileName });
|
|
218
232
|
}
|
|
219
233
|
return Object.assign({}, file.get({ pain: true }), {
|
|
220
|
-
id: file.uuid,
|
|
234
|
+
id: file.uuid,
|
|
235
|
+
filePath: targetFileName,
|
|
236
|
+
targetFile
|
|
221
237
|
});
|
|
222
238
|
};
|
|
223
239
|
|
|
@@ -272,10 +288,14 @@ module.exports = fp(async (fastify, fastifyOptions) => {
|
|
|
272
288
|
});
|
|
273
289
|
|
|
274
290
|
const { count, rows } = await models.fileRecord.findAndCountAll({
|
|
275
|
-
where: queryFilter,
|
|
291
|
+
where: queryFilter,
|
|
292
|
+
offset: perPage * (currentPage - 1),
|
|
293
|
+
limit: perPage,
|
|
294
|
+
order: [['createdAt', 'desc']]
|
|
276
295
|
});
|
|
277
296
|
return {
|
|
278
|
-
pageData: rows.map(item => Object.assign({}, item.get({ plain: true }), { id: item.uuid })),
|
|
297
|
+
pageData: rows.map(item => Object.assign({}, item.get({ plain: true }), { id: item.uuid })),
|
|
298
|
+
totalCount: count
|
|
279
299
|
};
|
|
280
300
|
};
|
|
281
301
|
|
|
@@ -291,6 +311,10 @@ module.exports = fp(async (fastify, fastifyOptions) => {
|
|
|
291
311
|
|
|
292
312
|
const renameFile = async ({ id, filename }) => {
|
|
293
313
|
const file = await detail({ id });
|
|
314
|
+
filename = sanitizeFilename(filename);
|
|
315
|
+
if (!path.extname(filename) && path.extname(file.filename)) {
|
|
316
|
+
filename += path.extname(file.filename);
|
|
317
|
+
}
|
|
294
318
|
file.filename = filename;
|
|
295
319
|
await file.save();
|
|
296
320
|
};
|
|
@@ -320,7 +344,8 @@ module.exports = fp(async (fastify, fastifyOptions) => {
|
|
|
320
344
|
}
|
|
321
345
|
|
|
322
346
|
return Object.assign({}, file.get({ plain: true }), {
|
|
323
|
-
id: file.uuid,
|
|
347
|
+
id: file.uuid,
|
|
348
|
+
buffer
|
|
324
349
|
});
|
|
325
350
|
};
|
|
326
351
|
|
|
@@ -396,7 +421,8 @@ module.exports = fp(async (fastify, fastifyOptions) => {
|
|
|
396
421
|
const tmpPath = path.resolve(os.tmpdir(), `temp_${id}_${crypto.randomBytes(6).toString('hex')}`);
|
|
397
422
|
await compressing[type].uncompress(fileStream, tmpPath);
|
|
398
423
|
const files = await glob(globOptions, {
|
|
399
|
-
cwd: tmpPath,
|
|
424
|
+
cwd: tmpPath,
|
|
425
|
+
nodir: true
|
|
400
426
|
});
|
|
401
427
|
//将文件上传到文件系统
|
|
402
428
|
const fileList = [];
|
|
@@ -406,11 +432,17 @@ module.exports = fp(async (fastify, fastifyOptions) => {
|
|
|
406
432
|
const mimetype = MimeTypes.lookup(filepath) || 'application/octet-stream';
|
|
407
433
|
const file = await uploadToFileSystem({
|
|
408
434
|
file: {
|
|
409
|
-
filename,
|
|
410
|
-
|
|
435
|
+
filename,
|
|
436
|
+
mimetype,
|
|
437
|
+
encoding: 'binary',
|
|
438
|
+
filepath
|
|
439
|
+
},
|
|
440
|
+
filename,
|
|
441
|
+
namespace
|
|
411
442
|
});
|
|
412
443
|
fileList.push({
|
|
413
|
-
dir,
|
|
444
|
+
dir,
|
|
445
|
+
file
|
|
414
446
|
});
|
|
415
447
|
}
|
|
416
448
|
fs.remove(tmpPath).catch(console.error);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kne/fastify-file-manager",
|
|
3
|
-
"version": "3.0.1-alpha.
|
|
3
|
+
"version": "3.0.1-alpha.3",
|
|
4
4
|
"description": "用于管理静态文件上传查看等",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
"build:md": "npx @kne/md-doc",
|
|
9
9
|
"start:md": "npx @kne/md-doc --watch",
|
|
10
10
|
"prettier": "prettier --config .prettierrc --write '{libs/**/*,index}.{js,jsx,ts,tsx,json,css,scss}'",
|
|
11
|
-
"lint-staged": "npx lint-staged"
|
|
11
|
+
"lint-staged": "npx lint-staged",
|
|
12
|
+
"test": "mocha tests/**/*.test.js --timeout 30000"
|
|
12
13
|
},
|
|
13
14
|
"lint-staged": {
|
|
14
15
|
"{libs/**/*,index}.{js,jsx,ts,tsx,json,css,scss}": [
|
|
@@ -37,6 +38,7 @@
|
|
|
37
38
|
"@kne/fastify-sequelize": "^2.0.1",
|
|
38
39
|
"fastify": "^5.3.2",
|
|
39
40
|
"husky": "^9.0.11",
|
|
41
|
+
"mocha": "^11.7.5",
|
|
40
42
|
"prettier": "^3.2.5",
|
|
41
43
|
"qs": "^6.12.3",
|
|
42
44
|
"sqlite3": "^5.1.7"
|