@kne/fastify-file-manager 2.0.7 → 2.0.9
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 +86 -21
- package/package.json +2 -1
|
@@ -5,6 +5,7 @@ const path = require('node:path');
|
|
|
5
5
|
const { NotFound } = require('http-errors');
|
|
6
6
|
const os = require('node:os');
|
|
7
7
|
const { Readable } = require('node:stream');
|
|
8
|
+
const compressing = require('compressing');
|
|
8
9
|
|
|
9
10
|
module.exports = fp(async (fastify, options) => {
|
|
10
11
|
const { models, services } = fastify.fileManager;
|
|
@@ -29,7 +30,7 @@ module.exports = fp(async (fastify, options) => {
|
|
|
29
30
|
const writeStream = fs.createWriteStream(tmpPath);
|
|
30
31
|
let fileSize = 0;
|
|
31
32
|
if (file.file) {
|
|
32
|
-
file.file.on('data',
|
|
33
|
+
file.file.on('data', chunk => {
|
|
33
34
|
hash.update(chunk); // 更新哈希
|
|
34
35
|
writeStream.write(chunk); // 写入文件
|
|
35
36
|
fileSize += chunk.length; // 更新文件大小
|
|
@@ -73,14 +74,12 @@ module.exports = fp(async (fastify, options) => {
|
|
|
73
74
|
const writeStream = fs.createWriteStream(filepath);
|
|
74
75
|
const readStream = fs.createReadStream(tmpPath);
|
|
75
76
|
await new Promise((resolve, reject) => {
|
|
76
|
-
readStream.pipe(writeStream)
|
|
77
|
-
.on('finish', resolve)
|
|
78
|
-
.on('error', reject);
|
|
77
|
+
readStream.pipe(writeStream).on('finish', resolve).on('error', reject);
|
|
79
78
|
});
|
|
80
79
|
storageType = 'local';
|
|
81
80
|
}
|
|
82
81
|
|
|
83
|
-
|
|
82
|
+
//清除临时文件
|
|
84
83
|
await fs.remove(tmpPath);
|
|
85
84
|
|
|
86
85
|
const outputFile = await (async create => {
|
|
@@ -128,12 +127,28 @@ module.exports = fp(async (fastify, options) => {
|
|
|
128
127
|
nodeStream.emit('error', err);
|
|
129
128
|
}
|
|
130
129
|
};
|
|
131
|
-
readChunk()
|
|
130
|
+
readChunk().catch(err => {
|
|
131
|
+
throw err;
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
let filename = path.basename(url).split('?')[0];
|
|
135
|
+
|
|
136
|
+
const contentDisposition = response.headers.get('content-disposition');
|
|
137
|
+
|
|
138
|
+
if (contentDisposition) {
|
|
139
|
+
const filenameMatch = contentDisposition.match(/filename="?(.+)"?/i);
|
|
140
|
+
if (filenameMatch && filenameMatch[1]) {
|
|
141
|
+
filename = filenameMatch[1];
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const searchParams = new URLSearchParams(url.split('?')[1]);
|
|
146
|
+
if (searchParams.get('filename')) {
|
|
147
|
+
filename = searchParams.get('filename');
|
|
148
|
+
}
|
|
149
|
+
|
|
132
150
|
const tempFile = {
|
|
133
|
-
filename:
|
|
134
|
-
mimetype: response.headers.get('content-type'),
|
|
135
|
-
encoding: 'binary',
|
|
136
|
-
file: nodeStream
|
|
151
|
+
filename, mimetype: response.headers.get('content-type'), encoding: 'binary', file: nodeStream
|
|
137
152
|
};
|
|
138
153
|
return await uploadToFileSystem({ id, file: tempFile, namespace });
|
|
139
154
|
};
|
|
@@ -208,7 +223,7 @@ module.exports = fp(async (fastify, options) => {
|
|
|
208
223
|
await models.fileRecord.destroy({
|
|
209
224
|
where: {
|
|
210
225
|
uuid: {
|
|
211
|
-
[Op.in]: ids.map(
|
|
226
|
+
[Op.in]: ids.map(str => str.split('?')[0])
|
|
212
227
|
}
|
|
213
228
|
}
|
|
214
229
|
});
|
|
@@ -249,27 +264,71 @@ module.exports = fp(async (fastify, options) => {
|
|
|
249
264
|
});
|
|
250
265
|
};
|
|
251
266
|
|
|
252
|
-
const
|
|
253
|
-
const file = await detail({ id });
|
|
254
|
-
|
|
267
|
+
const getFileReadStream = file => {
|
|
255
268
|
const extension = path.extname(file.filename);
|
|
256
269
|
const targetFileName = `${file.hash}${extension}`;
|
|
257
270
|
const ossServices = options.ossAdapter();
|
|
258
|
-
|
|
259
271
|
if (file.storageType === 'oss') {
|
|
260
272
|
if (typeof ossServices.getFileStream !== 'function') {
|
|
261
273
|
throw new Error('ossAdapter未正确配置无法读取oss类型存储文件');
|
|
262
274
|
}
|
|
263
|
-
return
|
|
275
|
+
return ossServices.getFileStream({ filename: targetFileName });
|
|
264
276
|
} else {
|
|
265
277
|
const filePath = path.resolve(options.root, targetFileName);
|
|
266
|
-
if (!(await fs.exists(filePath))) {
|
|
267
|
-
throw new NotFound();
|
|
268
|
-
}
|
|
269
278
|
return fs.createReadStream(filePath);
|
|
270
279
|
}
|
|
271
280
|
};
|
|
272
281
|
|
|
282
|
+
const getFileStream = async ({ id }) => {
|
|
283
|
+
const file = await detail({ id });
|
|
284
|
+
return getFileReadStream(file);
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
const getCompressFileStream = async ({ ids, type = 'zip' }) => {
|
|
288
|
+
const fileList = await models.fileRecord.findAll({
|
|
289
|
+
where: {
|
|
290
|
+
uuid: {
|
|
291
|
+
[Op.in]: ids.map(str => str.split('?')[0])
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
const tmpPath = path.resolve(os.tmpdir(), `temp_compress_file_${crypto.randomBytes(6).toString('hex')}`);
|
|
296
|
+
await fs.mkdir(tmpPath);
|
|
297
|
+
const files = [];
|
|
298
|
+
for (const file of fileList) {
|
|
299
|
+
const filepath = path.resolve(tmpPath, file.filename);
|
|
300
|
+
const writeStream = fs.createWriteStream(filepath);
|
|
301
|
+
const fileStream = getFileReadStream(file);
|
|
302
|
+
fileStream.pipe(writeStream);
|
|
303
|
+
await new Promise((resolve, reject) => {
|
|
304
|
+
writeStream.on('finish', resolve);
|
|
305
|
+
writeStream.on('error', reject);
|
|
306
|
+
});
|
|
307
|
+
files.push(filepath);
|
|
308
|
+
}
|
|
309
|
+
const compressStream = new compressing[type].Stream();
|
|
310
|
+
files.forEach(filepath => {
|
|
311
|
+
compressStream.addEntry(path.resolve(filepath));
|
|
312
|
+
});
|
|
313
|
+
compressStream.on('error', () => {
|
|
314
|
+
fs.remove(tmpPath);
|
|
315
|
+
});
|
|
316
|
+
compressStream.on('end', () => {
|
|
317
|
+
fs.remove(tmpPath);
|
|
318
|
+
});
|
|
319
|
+
return compressStream;
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
const getCompressFileBlob = async (...args) => {
|
|
323
|
+
const compressStream = await getCompressFileStream(...args);
|
|
324
|
+
const chunks = [];
|
|
325
|
+
return new Promise((resolve, reject) => {
|
|
326
|
+
compressStream.on('data', chunk => chunks.push(chunk));
|
|
327
|
+
compressStream.on('end', () => resolve(Buffer.concat(chunks)));
|
|
328
|
+
compressStream.on('error', reject);
|
|
329
|
+
});
|
|
330
|
+
};
|
|
331
|
+
|
|
273
332
|
const getFileInstance = async ({ id, uuid }) => {
|
|
274
333
|
return detail({ id, uuid });
|
|
275
334
|
};
|
|
@@ -283,8 +342,11 @@ module.exports = fp(async (fastify, options) => {
|
|
|
283
342
|
deleteFiles,
|
|
284
343
|
renameFile,
|
|
285
344
|
getFileBlob,
|
|
286
|
-
getFileStream,
|
|
287
|
-
|
|
345
|
+
getFileStream,
|
|
346
|
+
getFileReadStream,
|
|
347
|
+
getCompressFileStream,
|
|
348
|
+
getCompressFileBlob,
|
|
349
|
+
getFileInstance, // 兼容之前api,后面可能会删掉
|
|
288
350
|
fileRecord: {
|
|
289
351
|
uploadToFileSystem,
|
|
290
352
|
uploadFromUrl,
|
|
@@ -295,6 +357,9 @@ module.exports = fp(async (fastify, options) => {
|
|
|
295
357
|
renameFile,
|
|
296
358
|
getFileBlob,
|
|
297
359
|
getFileStream,
|
|
360
|
+
getFileReadStream,
|
|
361
|
+
getCompressFileStream,
|
|
362
|
+
getCompressFileBlob,
|
|
298
363
|
getFileInstance
|
|
299
364
|
}
|
|
300
365
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kne/fastify-file-manager",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.9",
|
|
4
4
|
"description": "用于管理静态文件上传查看等",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"@fastify/multipart": "^9.0.3",
|
|
51
51
|
"@fastify/static": "^8.1.1",
|
|
52
|
+
"compressing": "^2.0.0",
|
|
52
53
|
"fs-extra": "^11.2.0",
|
|
53
54
|
"http-errors": "^2.0.0"
|
|
54
55
|
}
|