Files
ddns-agent/agent/task.ts
2025-11-18 14:39:32 +08:00

162 lines
4.7 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { app, storage } from './app.ts';
export type CloudflareConfig = {
// Cloudflare 访问地址
website: string;
domain: string;
zone_id: string;
// 更新IPv4记录的ID
record_id4: string;
// 更新IPv6记录的ID
record_id6: string;
api_token: string;
ipv6: string;
ipv4: string;
flag: number; // 0: 不更新, 1: 仅IPv4, 2: 仅IPv6, 3: IPv4和IPv6
time: string; // 上次更新时间戳
}
app.route({
path: 'ip',
key: 'task',
description: `执行IP更新任务
1. 读取配置文件cloudflare.json
2. 根据flag决定更新IPv4和/或IPv6地址
3. 获取当前公网IP地址
4. 如果IP地址有变化则调用 router: cf/update 更新DNS记录
5. 保存最新的IP地址和更新时间戳到配置文件
`,
}).define(async (ctx) => {
const config = await storage.getItem<CloudflareConfig>('cloudflare.json');
if (!config) {
ctx.throw?.('未找到配置');
}
const now = Date.now();
const date = new Date(now);
const updateIp = async (isV4 = true) => {
const res = await app.call({ path: 'ip', key: isV4 ? 'v4' : 'v6' });
if (res.code !== 200) {
ctx.throw(res.message);
}
const newIp = res.body.ip as string;
const oldIp = isV4 ? config.ipv4 : config.ipv6;
if (newIp !== oldIp) {
// IP地址有变化更新DNS记录
await app.call({
path: 'cf', key: 'update', payload: {
zone_id: config.zone_id,
record_id: isV4 ? config.record_id4 : config.record_id6,
domain: config.domain,
new_ip: newIp,
api_token: config.api_token,
type: isV4 ? 'A' : 'AAAA',
}
}, {});
// 更新配置文件中的IP地址
if (isV4) {
config.ipv4 = newIp;
} else {
config.ipv6 = newIp;
}
config.time = date.toLocaleString();
await storage.setItem('cloudflare.json', config);
console.log(date.toLocaleString() + ` 更新 ${isV4 ? 'IPv4' : 'IPv6'} 地址为: ${newIp}`);
} else {
console.log(date.toLocaleString() + ` ${isV4 ? 'IPv4' : 'IPv6'} 地址未改变: ${newIp}`);
}
}
if (config.flag === 1) {
await updateIp(true);
}
if (config.flag === 2) {
await updateIp(false);
}
if (config.flag === 3) {
await updateIp(true);
await updateIp(false);
}
ctx.body = { message: '任务完成' };
}).addTo(app);
app.route({
path: 'ip',
key: 'init',
description: '初始化配置文件cloudflare.json',
}).define(async (ctx) => {
// 初始化逻辑
const config = await storage.getItem<CloudflareConfig>('cloudflare.json');
const isIpv4 = config?.flag === 1 || config?.flag === 3;
const isIpv6 = config?.flag === 2 || config?.flag === 3;
const apiToken = config?.api_token || '';
if (!apiToken) {
ctx.throw?.('配置错误api_token为空');
}
const getIp = async (isV4: boolean) => {
const res = await app.call({ path: 'ip', key: isV4 ? 'v4' : 'v6' });
if (res.code !== 200) {
ctx.throw?.(`获取${isV4 ? 'IPv4' : 'IPv6'}地址失败: ` + res.message);
}
return res.body.ip as string;
}
const createCfRecord = async (isV4: boolean) => {
const newIp = await getIp(isV4);
const cfRes = await app.call({
path: 'cf',
key: 'create',
payload: {
zone_id: config.zone_id,
domain: config.domain,
new_ip: newIp,
api_token: config.api_token,
type: isV4 ? 'A' : 'AAAA',
}
});
if (cfRes.code !== 200) {
ctx.throw?.(`创建${isV4 ? 'IPv4' : 'IPv6'}记录失败: ` + cfRes.message);
}
console.log(`创建${isV4 ? 'IPv4' : 'IPv6'}记录结果:`, cfRes.body.record_id);
const record_id = cfRes.body.record_id as string;
if (isV4) {
config.record_id4 = record_id;
} else {
config.record_id6 = record_id;
}
config.time = new Date().toLocaleString();
await storage.setItem('cloudflare.json', config);
}
let isInit = false;
if (isIpv4 && config.record_id4 === '') {
console.log('配置错误需要更新IPv4地址但record_id4为空, 正在创建新记录...');
await createCfRecord(true);
isInit = true;
}
if (isIpv6 && config.record_id6 === '') {
console.log('配置警告需要更新IPv6地址但record_id6为空正在创建新记录...');
await createCfRecord(false);
isInit = true;
}
ctx.body = { init: isInit, message: '初始化完成' };
}).addTo(app);
export const main = async () => {
const res = await app.call({
path: 'ip',
key: 'init',
});
if (res.code !== 200) {
console.error('初始化失败:', res.message);
return;
}
if (res.body.init) {
console.log('初始化完成并创建了必要的DNS记录任务结束。');
return;
}
await app.call({
path: 'ip',
key: 'task',
})
}