UNPKG

hfs

Version:
83 lines (82 loc) 3.72 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.get_dynamic_dns_error = get_dynamic_dns_error; const config_1 = require("./config"); const cross_1 = require("./cross"); const lodash_1 = __importDefault(require("lodash")); const util_http_1 = require("./util-http"); const node_net_1 = require("node:net"); const net_1 = require("net"); const const_1 = require("./const"); const events_1 = __importDefault(require("./events")); const nat_1 = require("./nat"); const node_stream_1 = require("node:stream"); // optionally you can append '>' and a regular expression to determine what body is considered successful const dynamicDnsUrl = (0, config_1.defineConfig)(cross_1.CFG.dynamic_dns_url, ''); // listening this event will trigger public-ips fetching const EVENT = 'publicIpsChanged'; let stopFetching; let lastIPs; let lastMap; events_1.default.onListeners(EVENT, cbs => { stopFetching === null || stopFetching === void 0 ? void 0 : stopFetching(); if (!(cbs === null || cbs === void 0 ? void 0 : cbs.size)) return; stopFetching = (0, cross_1.repeat)(cross_1.HOUR, async () => { const IPs = await (0, nat_1.getPublicIps)(); if (lodash_1.default.isEqual(lastIPs, IPs)) return; lastIPs = IPs; events_1.default.emit(EVENT, lastMap = { IPs, IPX: IPs[0] || '', IP4: lodash_1.default.find(IPs, node_net_1.isIPv4) || '', IP6: lodash_1.default.find(IPs, net_1.isIPv6) || '', }); }); }); let stopListening; let last; dynamicDnsUrl.sub(v => { stopListening === null || stopListening === void 0 ? void 0 : stopListening(); if (!v) return; stopListening = events_1.default.on(EVENT, async () => { if (!lastMap) return; // called at start once, before first getPublicIps. Just skip it const lines = dynamicDnsUrl.get(); const all = await Promise.all(lines.split('\n').map(async (line) => { const [templateUrl, re] = (0, cross_1.splitAt)('>', line); const url = (0, cross_1.replace)(templateUrl, lastMap, '$'); const error = await (0, util_http_1.httpWithBody)(url, { httpThrow: false, headers: { 'User-Agent': "HFS/" + const_1.VERSION } }) // UA specified as requested by no-ip guidelines .then(async (res) => { const str = String(res.body).trim(); return (re ? str.match(re) : res.ok) ? '' : (str || res.statusMessage); }, (err) => err.code || err.message || String(err)); return { ts: new Date().toJSON(), error, url }; })); last = lodash_1.default.find(all, 'error') || all[0]; // the system is designed for just one result, and we give precedence to errors events_1.default.emit('dynamicDnsError', last); console.log('dynamic dns update', (last === null || last === void 0 ? void 0 : last.error) || 'ok'); }, { callNow: true }); }); async function get_dynamic_dns_error() { let unsub; return new node_stream_1.Readable({ objectMode: true, async read() { if (unsub) return; if (last) this.push(last); // start by sending current state unsub = events_1.default.on('dynamicDnsError', x => this.push(x)); // send updates, if any. This simplified way to manage the data stream is acceptable for this case of extremely low throughput }, async destroy() { unsub(); this.push(null); } }); }