码桶
发现社区成员的开源项目
monitors.js6 KB
// DNS Monitors API
// GET /api/monitors — list all monitors for the user
// POST /api/monitors — create a new monitor
// DELETE /api/monitors?id=MONITOR_ID — delete a monitor
const MAX_MONITORS_PER_USER = 50;
const VALID_TYPES = ['dns_record', 'traffic_spike', 'error_rate', 'ssl_expiry'];
export async function onRequestGet(context) {
const { env } = context;
const username = context.data.user?.username || 'client';
const kv = env.CF_DNS_KV;
if (!kv) {
return new Response(JSON.stringify({ error: 'KV not configured' }), {
status: 500,
headers: { 'Content-Type': 'application/json' }
});
}
const raw = await kv.get(`DNS_MONITORS:${username}`);
const monitors = raw ? JSON.parse(raw) : [];
return new Response(JSON.stringify({ success: true, monitors }), {
status: 200,
headers: { 'Content-Type': 'application/json' }
});
}
export async function onRequestPost(context) {
const { env, request } = context;
const username = context.data.user?.username || 'client';
const kv = env.CF_DNS_KV;
if (!kv) {
return new Response(JSON.stringify({ error: 'KV not configured' }), {
status: 500,
headers: { 'Content-Type': 'application/json' }
});
}
const body = await request.json();
const { zoneId, zoneName, monitorType = 'dns_record' } = body;
if (!zoneId) {
return new Response(JSON.stringify({ error: 'Missing required field: zoneId' }), {
status: 400, headers: { 'Content-Type': 'application/json' }
});
}
if (!VALID_TYPES.includes(monitorType)) {
return new Response(JSON.stringify({ error: `Invalid monitorType. Allowed: ${VALID_TYPES.join(', ')}` }), {
status: 400, headers: { 'Content-Type': 'application/json' }
});
}
// Validate per type
if (monitorType === 'dns_record') {
const { recordType, recordName, expectedContent } = body;
if (!recordType || !recordName || !expectedContent) {
return new Response(JSON.stringify({ error: 'DNS Record monitor requires: recordType, recordName, expectedContent' }), {
status: 400, headers: { 'Content-Type': 'application/json' }
});
}
} else if (monitorType === 'traffic_spike') {
if (!body.threshold || body.threshold < 1) {
return new Response(JSON.stringify({ error: 'Traffic Spike monitor requires: threshold (positive number)' }), {
status: 400, headers: { 'Content-Type': 'application/json' }
});
}
} else if (monitorType === 'error_rate') {
if (!body.threshold || body.threshold < 1 || body.threshold > 100) {
return new Response(JSON.stringify({ error: 'Error Rate monitor requires: threshold (1-100)' }), {
status: 400, headers: { 'Content-Type': 'application/json' }
});
}
} else if (monitorType === 'ssl_expiry') {
if (!body.daysBeforeExpiry || body.daysBeforeExpiry < 1) {
return new Response(JSON.stringify({ error: 'SSL Expiry monitor requires: daysBeforeExpiry (positive number)' }), {
status: 400, headers: { 'Content-Type': 'application/json' }
});
}
}
const raw = await kv.get(`DNS_MONITORS:${username}`);
const monitors = raw ? JSON.parse(raw) : [];
if (monitors.length >= MAX_MONITORS_PER_USER) {
return new Response(JSON.stringify({ error: `Maximum ${MAX_MONITORS_PER_USER} monitors allowed per user.` }), {
status: 400, headers: { 'Content-Type': 'application/json' }
});
}
const monitor = {
id: crypto.randomUUID(),
zoneId,
zoneName: zoneName || '',
monitorType,
enabled: true,
lastCheck: null,
lastStatus: 'unknown',
lastError: null,
createdAt: new Date().toISOString()
};
// Add type-specific fields
if (monitorType === 'dns_record') {
monitor.recordType = body.recordType.toUpperCase();
monitor.recordName = body.recordName;
monitor.expectedContent = body.expectedContent;
} else if (monitorType === 'traffic_spike') {
monitor.threshold = body.threshold;
monitor.timeWindow = body.timeWindow || '1h';
} else if (monitorType === 'error_rate') {
monitor.threshold = body.threshold;
monitor.statusType = body.statusType || '5xx';
} else if (monitorType === 'ssl_expiry') {
monitor.daysBeforeExpiry = body.daysBeforeExpiry;
}
monitors.push(monitor);
await kv.put(`DNS_MONITORS:${username}`, JSON.stringify(monitors));
return new Response(JSON.stringify({ success: true, monitor }), {
status: 201,
headers: { 'Content-Type': 'application/json' }
});
}
export async function onRequestDelete(context) {
const { env, request } = context;
const username = context.data.user?.username || 'client';
const kv = env.CF_DNS_KV;
if (!kv) {
return new Response(JSON.stringify({ error: 'KV not configured' }), {
status: 500,
headers: { 'Content-Type': 'application/json' }
});
}
const url = new URL(request.url);
const monitorId = url.searchParams.get('id');
if (!monitorId) {
return new Response(JSON.stringify({ error: 'Missing id parameter' }), {
status: 400,
headers: { 'Content-Type': 'application/json' }
});
}
const raw = await kv.get(`DNS_MONITORS:${username}`);
const monitors = raw ? JSON.parse(raw) : [];
const idx = monitors.findIndex(m => m.id === monitorId);
if (idx === -1) {
return new Response(JSON.stringify({ error: 'Monitor not found' }), {
status: 404,
headers: { 'Content-Type': 'application/json' }
});
}
monitors.splice(idx, 1);
await kv.put(`DNS_MONITORS:${username}`, JSON.stringify(monitors));
return new Response(JSON.stringify({ success: true }), {
status: 200,
headers: { 'Content-Type': 'application/json' }
});
}