feat: Добавить API для управления настройками пользовательского интерфейса, включая получение и обновление конфигурации из S3; интегрировать модальное окно настроек в интерфейс
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m33s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m33s
This commit is contained in:
+66
-1
@@ -1049,7 +1049,8 @@ app.get('/api/s3/last-modified', async (req, res) => {
|
||||
{ name: 'asns', key: 'bgp_data/asns.txt' },
|
||||
{ name: 'servers', key: 'servers.json' },
|
||||
{ name: 'filters', key: 'filters.json' },
|
||||
{ name: 'ipRanges', key: 'bgp_data/ips.txt' }
|
||||
{ name: 'ipRanges', key: 'bgp_data/ips.txt' },
|
||||
{ name: 'uiSettings', key: 'bgp_data/rt_ui_settings.json' }
|
||||
];
|
||||
const results = await Promise.allSettled(
|
||||
keys.map(k => s3.headObject({ Bucket: BUCKET_NAME, Key: k.key }).promise())
|
||||
@@ -1625,6 +1626,70 @@ app.get('/api/auto-urls', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// --- UI Settings (rt_ui_settings.json in bgp_data) ---
|
||||
// Get UI settings
|
||||
app.get('/api/ui-settings', async (req, res) => {
|
||||
const params = {
|
||||
Bucket: BUCKET_NAME,
|
||||
Key: 'bgp_data/rt_ui_settings.json',
|
||||
};
|
||||
|
||||
try {
|
||||
const data = await s3.getObject(params).promise();
|
||||
const jsonText = data.Body.toString('utf-8');
|
||||
let settings = {};
|
||||
try {
|
||||
const parsed = JSON.parse(jsonText);
|
||||
if (parsed && typeof parsed === 'object') settings = parsed;
|
||||
} catch (parseError) {
|
||||
settings = {};
|
||||
}
|
||||
if (data.ETag) res.set('ETag', String(data.ETag));
|
||||
if (data.LastModified) res.set('Last-Modified', new Date(data.LastModified).toUTCString());
|
||||
if (typeof data.ContentLength === 'number') res.set('Content-Length-Source', String(data.ContentLength));
|
||||
return res.json(settings);
|
||||
} catch (error) {
|
||||
if (error.code === 'NoSuchKey') {
|
||||
return res.json({});
|
||||
}
|
||||
console.error('Error reading ui settings from S3:', error);
|
||||
return sendError(res, 500, 'Error reading UI settings from S3', 'E_S3');
|
||||
}
|
||||
});
|
||||
|
||||
// Update UI settings
|
||||
app.post('/api/ui-settings', async (req, res) => {
|
||||
const { settings, etag } = req.body || {};
|
||||
const payload = (settings && typeof settings === 'object') ? settings : {};
|
||||
|
||||
try {
|
||||
// optimistic concurrency if ETag provided (or If-Match header)
|
||||
let current = null;
|
||||
const ifMatch = req.headers['if-match'] ? String(req.headers['if-match']).replace(/\"/g,'"') : null;
|
||||
try { current = await headS3ObjectEtag('bgp_data/rt_ui_settings.json'); } catch {}
|
||||
if (current && (ifMatch || etag) && current !== String(ifMatch || etag)) {
|
||||
const meta = await headMeta('bgp_data/rt_ui_settings.json');
|
||||
return sendError(res, 412, 'Precondition Failed: ETag mismatch', 'E_ETAG_MISMATCH', { currentEtag: current, meta });
|
||||
}
|
||||
} catch {}
|
||||
|
||||
const params = {
|
||||
Bucket: BUCKET_NAME,
|
||||
Key: 'bgp_data/rt_ui_settings.json',
|
||||
Body: JSON.stringify(payload, null, 2),
|
||||
ContentType: 'application/json',
|
||||
};
|
||||
|
||||
try {
|
||||
await s3.putObject(params).promise();
|
||||
const meta = await headMeta('bgp_data/rt_ui_settings.json');
|
||||
return sendOk(res, meta);
|
||||
} catch (error) {
|
||||
console.error('Error writing UI settings to S3:', error);
|
||||
return sendError(res, 500, 'Error writing UI settings to S3', 'E_S3', { error: String(error?.message || error) });
|
||||
}
|
||||
});
|
||||
|
||||
// --- Servers availability check ---
|
||||
// Optimized TCP check: parallelize ports and hosts, cap per-host time, add in-memory TTL cache
|
||||
function tcpCheck(host, port, timeoutMs) {
|
||||
|
||||
Reference in New Issue
Block a user