hfs
Version:
HTTP File Server
83 lines (82 loc) • 3.72 kB
JavaScript
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);
}
});
}
;