@linkedmink/node-route53-dynamic-dns
Version:
Background process that updates AWS Route 53 DNS address records whenever the public IP of the hosting environment changes
77 lines • 3.15 kB
JavaScript
import EventEmitter from "node:events";
import { setInterval } from "node:timers/promises";
import { IpNotFoundError, publicIpv4, publicIpv6 } from "public-ip";
import { MINIMUM_IP_RETRIEVE_TIMEOUT_MS, MINIMUM_IP_RETRIEVE_UPDATE_DIFF_MS, } from "../constants/behavior.mjs";
import { PublicIpEvent } from "../constants/events.mjs";
import { loggerForModuleUrl } from "../environment/logger.mjs";
import { formatError } from "../functions/format.mjs";
export class PublicIpClient extends EventEmitter {
updateIntervalMs;
ipRetrieveTimeout;
isIpV6Enabled;
logger = loggerForModuleUrl(import.meta.url);
constructor(updateIntervalMs, ipRetrieveTimeout, isIpV6Enabled) {
super();
this.updateIntervalMs = updateIntervalMs;
this.ipRetrieveTimeout = ipRetrieveTimeout;
this.isIpV6Enabled = isIpV6Enabled;
if (this.ipRetrieveTimeout < MINIMUM_IP_RETRIEVE_TIMEOUT_MS) {
throw new Error(`ipRetrieveTimeout must be at least: ${MINIMUM_IP_RETRIEVE_TIMEOUT_MS}ms`);
}
// Don't allow getting the IP again while a retrieval is possibly in progress
const updateIntervalMinimumMs = MINIMUM_IP_RETRIEVE_TIMEOUT_MS + MINIMUM_IP_RETRIEVE_UPDATE_DIFF_MS;
if (this.updateIntervalMs < updateIntervalMinimumMs) {
throw new Error(`updateIntervalMs must be at least: ${MINIMUM_IP_RETRIEVE_UPDATE_DIFF_MS}ms more than ipRetrieveTimeout(${MINIMUM_IP_RETRIEVE_TIMEOUT_MS}ms)`);
}
}
start = async () => {
await this.updatePublicIpState();
for await (const _ of setInterval(this.updateIntervalMs)) {
await this.updatePublicIpState();
}
};
updatePublicIpState = async () => {
this.logger.debug("Getting latest public IP");
const [ipV4, ipV6] = await Promise.all([this.getPublicIpV4(), this.getPublicIpV6()]);
const state = {
publicIpAddresses: {
v4: ipV4,
v6: ipV6,
},
lastPublicIpDateTime: new Date(),
};
this.logger.info(`Emitting public IPs to check: v4=${ipV4}, v6=${ipV6}`);
this.emit(PublicIpEvent.Retrieved, state);
return state;
};
getPublicIpV4 = async () => {
try {
return await publicIpv4({ timeout: this.ipRetrieveTimeout });
}
catch (error) {
this.logIpError(error, "V4");
return null;
}
};
getPublicIpV6 = async () => {
if (!this.isIpV6Enabled) {
return null;
}
try {
return await publicIpv6({ timeout: this.ipRetrieveTimeout });
}
catch (error) {
this.logIpError(error, "V6");
return null;
}
};
logIpError = (error, version) => {
if (error instanceof IpNotFoundError) {
this.logger.verbose(`Could not determine IP ${version}. It may not be assigned, or this may indicate another problem (no internet access, etc.)`);
}
else {
this.logger.error(formatError(error));
}
};
}
//# sourceMappingURL=public-ip-event-emitter.mjs.map