This repository has been archived by the owner on Jan 29, 2024. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 39
/
Copy pathindex.ts
97 lines (90 loc) · 3.05 KB
/
index.ts
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
import { get, omit } from "lodash-es";
import axios from "axios";
import pino from "pino";
import { readConfig } from "@cloudflare-ddns/config";
import { registerParser } from "@cloudflare-ddns/ip-echo-parser";
import { fetchIPv4, fetchIPv6 } from "./ip.js";
import { updateDns } from "./api.js";
import { getConfigFilePath } from "./env.js";
import type { Config, Domain, WebhookFormatter } from "@cloudflare-ddns/config";
import type { Context } from "./context.js";
const updateDomain = async (ctx: Context, domain: Domain): Promise<unknown> => {
const { config, logger } = ctx;
const { ipv4, ipv6 } = config;
const useIPv4 = domain.type === "A";
const fetchIp = useIPv4 ? fetchIPv4 : fetchIPv6;
const ipEchos = useIPv4 ? ipv4 : ipv6;
const ip = await fetchIp(ctx, ipEchos);
const result = await updateDns(ctx, { domain, ip });
logger.info(`Updated ${domain.name} with ${ip}`);
return result;
};
const requestWebhook = async (
ctx: Context,
url?: string,
data?: unknown
): Promise<void> => {
if (!url) {
return;
}
const { logger } = ctx;
try {
if (data) {
await axios.post(url, data);
} else {
await axios.get(url);
}
} catch (e) {
logger.warn(`Fail to fetch ${url}.\n${get(e, "message", e)}`);
}
};
const updateDnsRecords = async (ctx: Context): Promise<void> => {
const { config, logger } = ctx;
const promises = config.domains.map(async domain => {
const { webhook } = domain;
const formatter: WebhookFormatter = webhook?.formatter ?? (() => undefined);
try {
const runMessage = await formatter("run");
await requestWebhook(ctx, webhook?.run, runMessage);
const result = await updateDomain(ctx, domain);
const successMessage = await formatter("success", result);
await requestWebhook(ctx, webhook?.success, successMessage);
} catch (e) {
const failureMessage = await formatter("failure", e);
await requestWebhook(ctx, webhook?.failure, failureMessage);
logger.error(
`Failed to update ${domain.name}. (${get(e, "message", e)})`
);
}
});
await Promise.all(promises);
};
const printConfig = (ctx: Context): void => {
const { config, logger } = ctx;
const cloneConfig = omit(config, ["auth"]);
const configStr = JSON.stringify(cloneConfig, null, 2);
logger.debug(`Running with the following configuration:\n${configStr}`);
};
const registerParsers = (config: Config): void => {
config.echoParsers.forEach(({ resolve, alias }) =>
registerParser(resolve, alias)
);
};
export const main = async (): Promise<void> => {
const configPath = getConfigFilePath();
const logLevel = process.env.CF_DNS_LOG_LEVEL ?? "info";
const logger = pino.default({ level: logLevel });
const config = await readConfig(configPath);
try {
const ctx: Context = { config, logger };
logger.info("Cloudflare DDNS start");
registerParsers(config);
printConfig(ctx);
await updateDnsRecords(ctx);
} catch (e) {
logger.error(get(e, "message", e));
process.exitCode = 1;
} finally {
logger.info("Cloudflare DDNS end");
}
};