@kne/fastify-file-manager 0.1.0
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/README.md +27 -0
- package/index.js +43 -0
- package/libs/.gitkeep +0 -0
- package/libs/controller.js +117 -0
- package/libs/service.js +83 -0
- package/models/file-manager.js +23 -0
- package/package.json +49 -0
package/README.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
|
|
2
|
+
# fastify-file-manager
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
### 描述
|
|
6
|
+
|
|
7
|
+
用于管理静态文件上传查看等
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### 安装
|
|
11
|
+
|
|
12
|
+
```shell
|
|
13
|
+
npm i --save @kne/fastify-file-manager
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
### 示例
|
|
17
|
+
|
|
18
|
+
#### 示例代码
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### API
|
|
23
|
+
|
|
24
|
+
| 属性名 | 说明 | 类型 | 默认值 |
|
|
25
|
+
|-----|----|----|-----|
|
|
26
|
+
| | | | |
|
|
27
|
+
|
package/index.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const fp = require('fastify-plugin');
|
|
2
|
+
const autoload = require('@fastify/autoload');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs-extra');
|
|
5
|
+
|
|
6
|
+
module.exports = fp(
|
|
7
|
+
async (fastify, options) => {
|
|
8
|
+
options = Object.assign(
|
|
9
|
+
{
|
|
10
|
+
root: path.join(process.cwd(), 'static'),
|
|
11
|
+
namespace: 'default',
|
|
12
|
+
prefix: '/static',
|
|
13
|
+
multipart: {},
|
|
14
|
+
static: {},
|
|
15
|
+
authenticateFileRead: async () => {},
|
|
16
|
+
authenticateFileMange: async () => {},
|
|
17
|
+
authenticateFileUpload: async () => {}
|
|
18
|
+
},
|
|
19
|
+
options
|
|
20
|
+
);
|
|
21
|
+
await fs.ensureDir(options.root);
|
|
22
|
+
await fastify.sequelize.addModels(path.resolve(__dirname, './models'));
|
|
23
|
+
|
|
24
|
+
fastify.register(require('@fastify/multipart'), options.multipart);
|
|
25
|
+
fastify.register(autoload, {
|
|
26
|
+
dir: path.resolve(__dirname, './libs'),
|
|
27
|
+
options
|
|
28
|
+
});
|
|
29
|
+
fastify.register(
|
|
30
|
+
require('@fastify/static'),
|
|
31
|
+
Object.assign({}, options.static, {
|
|
32
|
+
root: options.root,
|
|
33
|
+
prefix: options.prefix + '/file/',
|
|
34
|
+
index: false,
|
|
35
|
+
list: false
|
|
36
|
+
})
|
|
37
|
+
);
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: 'fastify-file-manager',
|
|
41
|
+
dependencies: ['fastify-sequelize']
|
|
42
|
+
}
|
|
43
|
+
);
|
package/libs/.gitkeep
ADDED
|
File without changes
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
const fp = require('fastify-plugin');
|
|
2
|
+
|
|
3
|
+
module.exports = fp(async (fastify, options) => {
|
|
4
|
+
fastify.post(
|
|
5
|
+
`${options.prefix}/upload`,
|
|
6
|
+
{
|
|
7
|
+
onRequest: [options.authenticateFileUpload]
|
|
8
|
+
},
|
|
9
|
+
async request => {
|
|
10
|
+
const file = await request.file();
|
|
11
|
+
if (!file) {
|
|
12
|
+
throw new Error('不能获取到上传文件');
|
|
13
|
+
}
|
|
14
|
+
//1. 保存到服务器目录 2.对接oss
|
|
15
|
+
return await fastify.fileManagerServices.uploadToFileSystem({ file, namespace: options.namespace });
|
|
16
|
+
}
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
fastify.get(
|
|
20
|
+
`${options.prefix}/file-url/:id`,
|
|
21
|
+
{
|
|
22
|
+
onRequest: [options.authenticateFileRead],
|
|
23
|
+
schema: {
|
|
24
|
+
params: {
|
|
25
|
+
type: 'object',
|
|
26
|
+
required: ['id'],
|
|
27
|
+
properties: {
|
|
28
|
+
id: { type: 'string' }
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
async request => {
|
|
34
|
+
const { id } = request.params;
|
|
35
|
+
return await fastify.fileManagerServices.getFileUrl({ id, namespace: options.namespace });
|
|
36
|
+
}
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
fastify.get(
|
|
40
|
+
`${options.prefix}/file-id/:id`,
|
|
41
|
+
{
|
|
42
|
+
onRequest: [options.authenticateFileRead],
|
|
43
|
+
schema: {
|
|
44
|
+
query: {
|
|
45
|
+
type: 'object',
|
|
46
|
+
properties: {
|
|
47
|
+
attachment: { type: 'boolean' },
|
|
48
|
+
filename: { type: 'string' }
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
params: {
|
|
52
|
+
type: 'object',
|
|
53
|
+
required: ['id'],
|
|
54
|
+
properties: {
|
|
55
|
+
id: { type: 'string' }
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
async (request, reply) => {
|
|
61
|
+
const { id } = request.params;
|
|
62
|
+
const { attachment, filename: targetFilename } = request.query;
|
|
63
|
+
const { targetFileName, filename } = await fastify.fileManagerServices.getFileInfo({
|
|
64
|
+
id,
|
|
65
|
+
namespace: options.namespace
|
|
66
|
+
});
|
|
67
|
+
return attachment ? reply.download(targetFileName, targetFilename || filename) : reply.sendFile(targetFileName);
|
|
68
|
+
}
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
fastify.get(
|
|
72
|
+
`${options.prefix}/file-list`,
|
|
73
|
+
{
|
|
74
|
+
onRequest: [options.authenticateFileMange],
|
|
75
|
+
schema: {
|
|
76
|
+
query: {}
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
async request => {
|
|
80
|
+
const { filter, perPage, currentPage } = Object.assign({}, request.query, {
|
|
81
|
+
perPage: 20,
|
|
82
|
+
currentPage: 1
|
|
83
|
+
});
|
|
84
|
+
return await fastify.fileManagerServices.getFileList({
|
|
85
|
+
filter,
|
|
86
|
+
namespace: options.namespace,
|
|
87
|
+
perPage,
|
|
88
|
+
currentPage
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
fastify.post(
|
|
94
|
+
`${options.prefix}/delete-file`,
|
|
95
|
+
{
|
|
96
|
+
onRequest: [options.authenticateFileMange],
|
|
97
|
+
schema: {
|
|
98
|
+
body: {
|
|
99
|
+
type: 'object',
|
|
100
|
+
required: ['id'],
|
|
101
|
+
properties: {
|
|
102
|
+
id: { type: 'string' }
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
async request => {
|
|
108
|
+
const { id } = request.body;
|
|
109
|
+
await fastify.fileManagerServices.deleteFile({ id, namespace: options.namespace });
|
|
110
|
+
return {};
|
|
111
|
+
}
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
fastify.get(`${options.prefix}`, async () => {
|
|
115
|
+
return 'living';
|
|
116
|
+
});
|
|
117
|
+
});
|
package/libs/service.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
const fp = require('fastify-plugin');
|
|
2
|
+
const fs = require('fs-extra');
|
|
3
|
+
const crypto = require('crypto');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
module.exports = fp(async (fastify, options) => {
|
|
7
|
+
const uploadToFileSystem = async ({ file, namespace }) => {
|
|
8
|
+
const { filename, encoding, mimetype } = file;
|
|
9
|
+
const buffer = await file.toBuffer();
|
|
10
|
+
const hash = crypto.createHash('md5');
|
|
11
|
+
hash.update(buffer);
|
|
12
|
+
const digest = hash.digest('hex');
|
|
13
|
+
const extension = path.extname(filename);
|
|
14
|
+
const filepath = path.resolve(options.root, `${digest}${extension}`);
|
|
15
|
+
await fs.writeFile(filepath, buffer);
|
|
16
|
+
console.log({
|
|
17
|
+
filename,
|
|
18
|
+
namespace,
|
|
19
|
+
encoding,
|
|
20
|
+
mimetype,
|
|
21
|
+
hash: digest,
|
|
22
|
+
size: buffer.byteLength
|
|
23
|
+
});
|
|
24
|
+
return await fastify.models.fileManager.create({
|
|
25
|
+
filename,
|
|
26
|
+
namespace,
|
|
27
|
+
encoding,
|
|
28
|
+
mimetype,
|
|
29
|
+
hash: digest,
|
|
30
|
+
size: buffer.byteLength
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const getFileUrl = async ({ id, namespace }) => {
|
|
35
|
+
const file = await fastify.models.fileManager.findByPk(id, {
|
|
36
|
+
where: { namespace }
|
|
37
|
+
});
|
|
38
|
+
if (!file) {
|
|
39
|
+
throw new Error('文件不存在');
|
|
40
|
+
}
|
|
41
|
+
const extension = path.extname(file.filename);
|
|
42
|
+
return `${options.prefix}/file/${file.hash}${extension}?filename=${file.filename}`;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const getFileInfo = async ({ id, namespace }) => {
|
|
46
|
+
const file = await fastify.models.fileManager.findByPk(id, {
|
|
47
|
+
where: { namespace }
|
|
48
|
+
});
|
|
49
|
+
if (!file) {
|
|
50
|
+
throw new Error('文件不存在');
|
|
51
|
+
}
|
|
52
|
+
const extension = path.extname(file.filename);
|
|
53
|
+
return Object.assign({}, file, {
|
|
54
|
+
targetFileName: `${file.hash}${extension}`
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const getFileList = async ({ filter, namespace, currentPage, perPage }) => {
|
|
59
|
+
const queryFilter = { namespace };
|
|
60
|
+
const { count, rows } = await fastify.models.fileManager.findAndCountAll({
|
|
61
|
+
where: queryFilter,
|
|
62
|
+
offset: currentPage * (currentPage - 1),
|
|
63
|
+
limit: perPage
|
|
64
|
+
});
|
|
65
|
+
return {
|
|
66
|
+
pageData: rows,
|
|
67
|
+
totalCount: count
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const deleteFile = async ({ id, namespace }) => {
|
|
72
|
+
const file = await fastify.models.fileManager.findByPk(id, {
|
|
73
|
+
where: { namespace }
|
|
74
|
+
});
|
|
75
|
+
if (!file) {
|
|
76
|
+
throw new Error('文件不存在');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
await file.destroy();
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
fastify.decorate('fileManagerServices', { uploadToFileSystem, getFileUrl, getFileInfo, getFileList, deleteFile });
|
|
83
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module.exports = (sequelize, DataTypes) => {
|
|
2
|
+
return sequelize.define('fileManager', {
|
|
3
|
+
id: {
|
|
4
|
+
type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, primaryKey: true
|
|
5
|
+
}, filename: {
|
|
6
|
+
type: DataTypes.STRING, allowNull: false
|
|
7
|
+
}, hash: {
|
|
8
|
+
type: DataTypes.STRING, allowNull: false
|
|
9
|
+
}, namespace: {
|
|
10
|
+
type: DataTypes.STRING, defaultValue: 'default'
|
|
11
|
+
}, size: {
|
|
12
|
+
type: DataTypes.INTEGER, allowNull: false
|
|
13
|
+
}, encoding: DataTypes.STRING, mimetype: DataTypes.STRING
|
|
14
|
+
}, {
|
|
15
|
+
indexes: [{
|
|
16
|
+
fields: ['namespace']
|
|
17
|
+
}, {
|
|
18
|
+
fields: ['filename']
|
|
19
|
+
}, {
|
|
20
|
+
fields: ['hash']
|
|
21
|
+
}]
|
|
22
|
+
});
|
|
23
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kne/fastify-file-manager",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "用于管理静态文件上传查看等",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"init": "husky",
|
|
8
|
+
"build:md": "npx @kne/md-doc",
|
|
9
|
+
"start:md": "npx @kne/md-doc --watch",
|
|
10
|
+
"prettier": "prettier --config .prettierrc --write '{libs/**/*,index}.{js,jsx,ts,tsx,json,css,scss}'",
|
|
11
|
+
"lint-staged": "npx lint-staged"
|
|
12
|
+
},
|
|
13
|
+
"lint-staged": {
|
|
14
|
+
"{libs/**/*,index}.{js,jsx,ts,tsx,json,css,scss}": [
|
|
15
|
+
"prettier --config .prettierrc --write",
|
|
16
|
+
"git add"
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"index.js",
|
|
21
|
+
"libs",
|
|
22
|
+
"models"
|
|
23
|
+
],
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/kne-union/fastify-file-manager.git"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [],
|
|
29
|
+
"author": "linzp",
|
|
30
|
+
"license": "ISC",
|
|
31
|
+
"bugs": {
|
|
32
|
+
"url": "https://github.com/kne-union/fastify-file-manager/issues"
|
|
33
|
+
},
|
|
34
|
+
"homepage": "https://github.com/kne-union/fastify-file-manager#readme",
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@kne/fastify-sequelize": "^0.1.3",
|
|
37
|
+
"fastify": "^4.27.0",
|
|
38
|
+
"husky": "^9.0.11",
|
|
39
|
+
"prettier": "^3.2.5",
|
|
40
|
+
"sqlite3": "^5.1.7"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@fastify/autoload": "^5.8.2",
|
|
44
|
+
"@fastify/multipart": "^8.2.0",
|
|
45
|
+
"@fastify/static": "^7.0.4",
|
|
46
|
+
"fastify-plugin": "^4.5.1",
|
|
47
|
+
"fs-extra": "^11.2.0"
|
|
48
|
+
}
|
|
49
|
+
}
|