-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.js
executable file
·292 lines (264 loc) · 9.64 KB
/
server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
#!/usr/bin/env node
const express = require('express');
const cors = require('cors');
const fs = require('fs');
const path = require('path');
const swaggerUi = require('swagger-ui-express');
const swaggerJsdoc = require('swagger-jsdoc');
const _ = require('lodash');
const yargs = require('yargs'); // Import yargs for argument parsing
const setupSwagger = require("./swagger"); // Thêm lodash
const app = express();
// Use yargs to parse command-line arguments
const argv = yargs
.option('port', {
alias: 'p',
type: 'number',
default: 3000, // Default port
description: 'Port to run the server on'
})
.option('data-path', {
alias: 'd',
type: 'string',
default: './data', // Default data path
description: 'Path to the data folder'
})
.help()
.argv;
const PORT = argv.port;
const dataFolder = argv.dataPath;
app.use(cors())
// Middleware để parse JSON từ request
app.use(express.json());
// Kiểm tra folder lưu dữ liệu chính, tạo nếu chưa có
if (!fs.existsSync(dataFolder)) {
fs.mkdirSync(dataFolder);
}
// Thiết lập Swagger
setupSwagger(app, PORT);
// Hàm để tạo versionId theo định dạng yyyymmddhhmmss
function generateVersionId() {
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
const day = String(now.getDate()).padStart(2, '0');
const hour = String(now.getHours()).padStart(2, '0');
const minute = String(now.getMinutes()).padStart(2, '0');
const second = String(now.getSeconds()).padStart(2, '0');
return `${year}${month}${day}${hour}${minute}${second}`;
}
// Hàm lấy nội dung file mới nhất trong folder của key
function getLatestFileContent(folderPath) {
if (fs.existsSync(folderPath)) {
const files = fs.readdirSync(folderPath).filter(file => file.endsWith('.json'));
// Sắp xếp các file theo thứ tự giảm dần (mới nhất trước)
files.sort((a, b) => b.localeCompare(a));
if (files.length > 0) {
const latestFile = files[0]; // File mới nhất
const latestFilePath = path.join(folderPath, latestFile);
const content = JSON.parse(fs.readFileSync(latestFilePath, 'utf8'));
return content;
}
}
return null; // Không có file nào
}
/**
* @swagger
* /config-builder/{key}:
* get:
* summary: Get all data by key
* description: Retrieve all data entries for a specified key.
* parameters:
* - in: path
* name: key
* required: true
* description: The key for which to retrieve data.
* schema:
* type: string
* responses:
* 200:
* description: List of data entries
* 404:
* description: Folder or data not found
*/
app.post('/config-builder', (req, res) => {
const { key, data } = req.body;
const folderPath = path.join(dataFolder, key);
const versionId = generateVersionId(); // Tạo version mới
const fileName = `${versionId}.json`;
const filePath = path.join(folderPath, fileName);
// Tạo folder nếu chưa tồn tại
if (!fs.existsSync(folderPath)) {
fs.mkdirSync(folderPath);
}
// Lấy nội dung file mới nhất và so sánh với dữ liệu mới
const latestContent = getLatestFileContent(folderPath);
if (latestContent && _.isEqual(latestContent.data, data)) {
return res.status(400).json({ message: 'Dữ liệu đã tồn tại, không có thay đổi' });
}
// Lưu dữ liệu vào file trong folder tương ứng
fs.writeFileSync(filePath, JSON.stringify({ key, data }, null, 2), 'utf8');
res.status(201).json({ message: 'Dữ liệu đã được lưu', folder: key, versionId });
});
/**
* @swagger
* /config-builder/{key}:
* get:
* summary: Get all data by key
* description: Retrieve all data entries for a specified key.
* parameters:
* - in: path
* name: key
* required: true
* description: The key for which to retrieve data.
* schema:
* type: string
* responses:
* 200:
* description: List of data entries
* 404:
* description: Folder or data not found
*/
app.get('/config-builder/:key', (req, res) => {
const { key } = req.params;
const folderPath = path.join(dataFolder, key);
if (fs.existsSync(folderPath)) {
const files = fs.readdirSync(folderPath);
const data = files.map(file => {
const filePath = path.join(folderPath, file);
const content = fs.readFileSync(filePath, 'utf8');
return { versionId: file.replace('.json', ''), content: JSON.parse(content) };
});
console.log(`GET /config-builder/${key}: Trả về ${files.length} phiên bản`);
res.json(data);
} else {
console.log(`GET /config-builder/${key}: Không tìm thấy folder`);
res.status(404).json({ message: 'Không tìm thấy folder hoặc dữ liệu' });
}
});
/**
* @swagger
* /config-builder/{key}/latest:
* get:
* summary: Get latest version of data by key
* description: Retrieve the latest version of data for a specified key.
* parameters:
* - in: path
* name: key
* required: true
* description: The key for which to retrieve the latest version.
* schema:
* type: string
* responses:
* 200:
* description: Latest version of data returned
* 404:
* description: No versions found in folder
*/
app.get('/config-builder/:key/latest', (req, res) => {
const { key } = req.params;
const folderPath = path.join(dataFolder, key);
if (fs.existsSync(folderPath)) {
const files = fs.readdirSync(folderPath);
const jsonFiles = files.filter(file => file.endsWith('.json'));
jsonFiles.sort((a, b) => b.localeCompare(a));
if (jsonFiles.length > 0) {
const latestFile = jsonFiles[0];
const filePath = path.join(folderPath, latestFile);
const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
console.log(`GET /config-builder/${key}/latest: Phiên bản mới nhất được trả về`);
res.json({ versionId: latestFile.replace('.json', ''), data });
} else {
console.log(`GET /config-builder/${key}/latest: Không có phiên bản nào`);
res.status(404).json({ message: 'Không có phiên bản nào trong folder' });
}
} else {
console.log(`GET /config-builder/${key}/latest: Không tìm thấy folder`);
res.status(404).json({ message: 'Không tìm thấy folder' });
}
});
/**
* @swagger
* /config-builder/{key}/{versionId}:
* get:
* summary: Get data by version
* description: Retrieve data for a specific version of a key.
* parameters:
* - in: path
* name: key
* required: true
* description: The key for which to retrieve data.
* schema:
* type: string
* - in: path
* name: versionId
* required: true
* description: The version ID of the data to retrieve.
* schema:
* type: string
* responses:
* 200:
* description: Data returned successfully
* 404:
* description: Version or folder not found
*/
app.get('/config-builder/:key/:versionId', (req, res) => {
const { key, versionId } = req.params;
const filePath = path.join(dataFolder, key, `${versionId}.json`);
if (fs.existsSync(filePath)) {
const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
console.log(`GET /config-builder/${key}/${versionId}: Dữ liệu được trả về`);
res.json(data);
} else {
console.log(`GET /config-builder/${key}/${versionId}: Không tìm thấy phiên bản`);
res.status(404).json({ message: 'Không tìm thấy phiên bản hoặc folder' });
}
});
/**
* @swagger
* /config-builder/{key}/{versionId}:
* delete:
* summary: Delete data by version
* description: Delete a specific version of data for a specified key.
* parameters:
* - in: path
* name: key
* required: true
* description: The key for which to delete data.
* schema:
* type: string
* - in: path
* name: versionId
* required: true
* description: The version ID of the data to delete.
* schema:
* type: string
* responses:
* 200:
* description: Version deleted successfully
* 404:
* description: Version or folder not found
*/
app.delete('/config-builder/:key/:versionId', (req, res) => {
const { key, versionId } = req.params;
const filePath = path.join(dataFolder, key, `${versionId}.json`);
if (fs.existsSync(filePath)) {
fs.unlinkSync(filePath);
console.log(`DELETE /config-builder/${key}/${versionId}: Phiên bản đã bị xóa`);
res.json({ message: 'Phiên bản đã bị xóa' });
} else {
console.log(`DELETE /config-builder/${key}/${versionId}: Không tìm thấy phiên bản`);
res.status(404).json({ message: 'Không tìm thấy phiên bản hoặc folder' });
}
});
// Liệt kê các endpoint khi khởi động server
app.listen(PORT, () => {
console.log(`Server đang chạy tại http://localhost:${PORT}`);
console.log(`Tài liệu API có sẵn tại http://localhost:${PORT}/api-docs`);
console.log('Các endpoint có sẵn:');
console.log('POST /config-builder - Tạo dữ liệu mới');
console.log('GET /config-builder/:key - Lấy tất cả dữ liệu theo key');
console.log('GET /config-builder/:key/latest - Lấy dữ liệu phiên bản mới nhất');
console.log('GET /config-builder/:key/:versionId - Lấy dữ liệu theo phiên bản');
console.log('DELETE /config-builder/:key/:versionId - Xóa dữ liệu theo phiên bản');
});