generated from template/slidev-template
feat: 添加IPv6地址获取功能,优化Cloudflare DNS记录更新逻辑,更新版本号并添加README
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
import { App } from '@kevisual/router'
|
import { App } from '@kevisual/router'
|
||||||
import { createStorage } from "unstorage";
|
import { createStorage } from "unstorage";
|
||||||
import fsDriver from "unstorage/drivers/fs";
|
import fsDriver from "unstorage/drivers/fs";
|
||||||
import { CloudflareConfig } from "@agent/task.ts";
|
|
||||||
export const storage = createStorage({
|
export const storage = createStorage({
|
||||||
driver: fsDriver({
|
driver: fsDriver({
|
||||||
base: process.cwd() + '/storage/ddns-agent'
|
base: process.cwd() + '/storage/ddns-agent'
|
||||||
|
|||||||
18
agent/ip.ts
18
agent/ip.ts
@@ -8,6 +8,14 @@ const baseURLv6 = 'https://6.ipw.cn/';
|
|||||||
// https://api.ipify.org/?format=text
|
// https://api.ipify.org/?format=text
|
||||||
// https://ipinfo.io/ip
|
// https://ipinfo.io/ip
|
||||||
import { app } from './app.ts';
|
import { app } from './app.ts';
|
||||||
|
import { exec } from 'child_process';
|
||||||
|
import { promisify } from 'util';
|
||||||
|
const execAsync = promisify(exec);
|
||||||
|
|
||||||
|
const curl6 = async (url: string): Promise<string> => {
|
||||||
|
const { stdout } = await execAsync(`curl -6 -s "${url}"`);
|
||||||
|
return stdout.trim();
|
||||||
|
};
|
||||||
|
|
||||||
app.route({
|
app.route({
|
||||||
path: 'ip',
|
path: 'ip',
|
||||||
@@ -29,15 +37,11 @@ app.route({
|
|||||||
}).define(async (ctx) => {
|
}).define(async (ctx) => {
|
||||||
let ip = ''
|
let ip = ''
|
||||||
try {
|
try {
|
||||||
const response = await fetch(baseURLv6);
|
ip = await curl6(baseURLv6);
|
||||||
ip = (await response.text()).trim();
|
} catch (error) { }
|
||||||
} catch (error) {
|
|
||||||
|
|
||||||
}
|
|
||||||
if (!isIpv6(ip)) {
|
if (!isIpv6(ip)) {
|
||||||
try {
|
try {
|
||||||
const response2 = await fetch('https://ifconfig.co/ip');
|
ip = await curl6('https://ifconfig.co/ip');
|
||||||
ip = (await response2.text()).trim();
|
|
||||||
console.log('尝试第二个接口获取IPv6地址:', ip);
|
console.log('尝试第二个接口获取IPv6地址:', ip);
|
||||||
} catch (error) { }
|
} catch (error) { }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,24 @@ app.route({
|
|||||||
|
|
||||||
const cf = new CloudflareDDNS();
|
const cf = new CloudflareDDNS();
|
||||||
|
|
||||||
|
// 先搜索是否已存在相同 domain 和 type 的记录
|
||||||
|
const searchRes = await cf.getList(zone_id, api_token, { search: domain });
|
||||||
|
if (searchRes.success && searchRes.result && searchRes.result.length > 0) {
|
||||||
|
const existingRecord = searchRes.result.find((r: any) => r.name === domain && r.type === type);
|
||||||
|
if (existingRecord) {
|
||||||
|
console.log(`记录已存在: ${domain} (${type}) -> ${existingRecord.content}`);
|
||||||
|
ctx.body = {
|
||||||
|
record_id: existingRecord.id,
|
||||||
|
name: existingRecord.name,
|
||||||
|
content: existingRecord.content,
|
||||||
|
result: existingRecord,
|
||||||
|
existed: true,
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 不存在则创建新记录
|
||||||
const result = await cf.createRecord({
|
const result = await cf.createRecord({
|
||||||
zone_id,
|
zone_id,
|
||||||
domain,
|
domain,
|
||||||
@@ -52,7 +70,7 @@ app.route({
|
|||||||
type,
|
type,
|
||||||
});
|
});
|
||||||
if (result.success === false) {
|
if (result.success === false) {
|
||||||
ctx.throw?.(result.errors?.map((e) => e.message).join('; ') || '创建DNS记录失败');
|
ctx.throw?.(result.errors?.map((e: any) => e.message).join('; ') || '创建DNS记录失败');
|
||||||
}
|
}
|
||||||
console.log(`创建成功: ${domain} -> ${new_ip}`);
|
console.log(`创建成功: ${domain} -> ${new_ip}`);
|
||||||
const record_id = result.result.id;
|
const record_id = result.result.id;
|
||||||
@@ -63,7 +81,8 @@ app.route({
|
|||||||
record_id: record_id,
|
record_id: record_id,
|
||||||
name: name,
|
name: name,
|
||||||
content: content,
|
content: content,
|
||||||
result: result.result
|
result: result.result,
|
||||||
|
existed: false,
|
||||||
};
|
};
|
||||||
}).addTo(app);
|
}).addTo(app);
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,12 @@ export type CloudflareConfig = {
|
|||||||
api_token: string;
|
api_token: string;
|
||||||
ipv6: string;
|
ipv6: string;
|
||||||
ipv4: string;
|
ipv4: string;
|
||||||
|
ipList?: {
|
||||||
|
type: 'A' | 'AAAA';
|
||||||
|
ip: string;
|
||||||
|
domain: string;
|
||||||
|
record_id: string;
|
||||||
|
}[];
|
||||||
flag: number; // 0: 不更新, 1: 仅IPv4, 2: 仅IPv6, 3: IPv4和IPv6
|
flag: number; // 0: 不更新, 1: 仅IPv4, 2: 仅IPv6, 3: IPv4和IPv6
|
||||||
time: string; // 上次更新时间戳
|
time: string; // 上次更新时间戳
|
||||||
}
|
}
|
||||||
@@ -43,7 +49,7 @@ app.route({
|
|||||||
const oldIp = isV4 ? config.ipv4 : config.ipv6;
|
const oldIp = isV4 ? config.ipv4 : config.ipv6;
|
||||||
console.log(date.toLocaleString() + ` 当前${isV4 ? 'IPv4' : 'IPv6'}地址: ${newIp}, 上次记录的IP地址: ${oldIp}`);
|
console.log(date.toLocaleString() + ` 当前${isV4 ? 'IPv4' : 'IPv6'}地址: ${newIp}, 上次记录的IP地址: ${oldIp}`);
|
||||||
if (newIp !== oldIp) {
|
if (newIp !== oldIp) {
|
||||||
// IP地址有变化,更新DNS记录
|
// IP地址有变化,更新主DNS记录
|
||||||
const cfUpdateRes = await app.run({
|
const cfUpdateRes = await app.run({
|
||||||
path: 'cf', key: 'update', payload: {
|
path: 'cf', key: 'update', payload: {
|
||||||
zone_id: config.zone_id,
|
zone_id: config.zone_id,
|
||||||
@@ -55,6 +61,49 @@ app.route({
|
|||||||
}
|
}
|
||||||
}, {});
|
}, {});
|
||||||
console.log(date.toLocaleString() + ` 更新${isV4 ? 'IPv4' : 'IPv6'}地址结果:`, cfUpdateRes);
|
console.log(date.toLocaleString() + ` 更新${isV4 ? 'IPv4' : 'IPv6'}地址结果:`, cfUpdateRes);
|
||||||
|
|
||||||
|
// 更新ipList中所有匹配的记录
|
||||||
|
if (config.ipList && config.ipList.length > 0) {
|
||||||
|
const recordType = isV4 ? 'A' : 'AAAA';
|
||||||
|
for (const item of config.ipList) {
|
||||||
|
if (item.type === recordType) {
|
||||||
|
if (item.record_id) {
|
||||||
|
// record_id 存在,更新记录
|
||||||
|
const listUpdateRes = await app.run({
|
||||||
|
path: 'cf', key: 'update', payload: {
|
||||||
|
zone_id: config.zone_id,
|
||||||
|
record_id: item.record_id,
|
||||||
|
domain: item.domain,
|
||||||
|
new_ip: newIp,
|
||||||
|
api_token: config.api_token,
|
||||||
|
type: recordType,
|
||||||
|
}
|
||||||
|
}, {});
|
||||||
|
console.log(date.toLocaleString() + ` 更新ipList[${item.domain}] 结果:`, listUpdateRes);
|
||||||
|
item.ip = newIp;
|
||||||
|
} else if (item.domain) {
|
||||||
|
// record_id 不存在但 domain 存在,创建新记录
|
||||||
|
const listCreateRes = await app.run({
|
||||||
|
path: 'cf', key: 'create', payload: {
|
||||||
|
zone_id: config.zone_id,
|
||||||
|
domain: item.domain,
|
||||||
|
new_ip: newIp,
|
||||||
|
api_token: config.api_token,
|
||||||
|
type: recordType,
|
||||||
|
}
|
||||||
|
}, {});
|
||||||
|
console.log(date.toLocaleString() + ` 创建ipList[${item.domain}] 记录结果:`, listCreateRes);
|
||||||
|
if (listCreateRes.data?.record_id) {
|
||||||
|
item.record_id = listCreateRes.data.record_id as string;
|
||||||
|
item.ip = newIp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 重新赋值 ipList 确保引用变化,触发更新
|
||||||
|
config.ipList = [...config.ipList];
|
||||||
|
}
|
||||||
|
|
||||||
// 更新配置文件中的IP地址
|
// 更新配置文件中的IP地址
|
||||||
if (isV4) {
|
if (isV4) {
|
||||||
config.ipv4 = newIp;
|
config.ipv4 = newIp;
|
||||||
@@ -118,8 +167,8 @@ app.route({
|
|||||||
if (cfRes.code !== 200) {
|
if (cfRes.code !== 200) {
|
||||||
ctx.throw?.(`创建${isV4 ? 'IPv4' : 'IPv6'}记录失败: ` + cfRes.message);
|
ctx.throw?.(`创建${isV4 ? 'IPv4' : 'IPv6'}记录失败: ` + cfRes.message);
|
||||||
}
|
}
|
||||||
console.log(`创建${isV4 ? 'IPv4' : 'IPv6'}记录结果:`, cfRes.body.record_id);
|
console.log(`创建${isV4 ? 'IPv4' : 'IPv6'}记录结果:`, cfRes.data.record_id);
|
||||||
const record_id = cfRes.body.record_id as string;
|
const record_id = cfRes.data.record_id as string;
|
||||||
|
|
||||||
if (isV4) {
|
if (isV4) {
|
||||||
config.record_id4 = record_id;
|
config.record_id4 = record_id;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@kevisual/ddns-agent",
|
"name": "@kevisual/ddns-agent",
|
||||||
"version": "1.0.3",
|
"version": "1.0.4",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"pub": "ev deploy . -k ddns-agent -v 1.0.3 -u",
|
"pub": "ev deploy . -k ddns-agent -v 1.0.4 -u",
|
||||||
"packup": "ev pack -p",
|
"packup": "ev pack -p",
|
||||||
"pm2": "pm2 start agent/main.ts --interpreter bun --name ddns-agent"
|
"pm2": "pm2 start agent/main.ts --interpreter bun --name ddns-agent"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -9,9 +9,11 @@
|
|||||||
"newLine": "LF",
|
"newLine": "LF",
|
||||||
"strict": false,
|
"strict": false,
|
||||||
"typeRoots": [
|
"typeRoots": [
|
||||||
"node",
|
|
||||||
"node_modules/@types",
|
"node_modules/@types",
|
||||||
],
|
],
|
||||||
|
"types": [
|
||||||
|
"node"
|
||||||
|
],
|
||||||
"declaration": false,
|
"declaration": false,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"allowImportingTsExtensions": true,
|
"allowImportingTsExtensions": true,
|
||||||
|
|||||||
Reference in New Issue
Block a user