fix: admin/internet: changing dynamic-dns url was not issuing a new request
Massimo Melina committed
Feb 8, 2025 at 13:29 UTC
9a6f41d1a6b13f6de36d08e3e95dd1334218960a
2 files changed
+14
-8
src/ddns.ts
+10
-7
@@ -15,6 +15,7 @@ const dynamicDnsUrl = defineConfig(CFG.dynamic_dns_url, '')
15
const EVENT = 'publicIpsChanged'
16
let stopFetching: any
17
let lastIPs: any
18
+let lastMap: any
19
events.onListeners(EVENT, cbs => {
20
stopFetching?.()
21
if (!cbs?.size) return
@@ -22,7 +23,7 @@ events.onListeners(EVENT, cbs => {
23
const IPs = await getPublicIps()
24
if (_.isEqual(lastIPs, IPs)) return
25
lastIPs = IPs
25
- events.emit(EVENT, {
26
+ events.emit(EVENT, lastMap = {
27
IPs,
28
IPX: IPs[0] || '',
29
IP4: _.find(IPs, isIPv4) || '',
@@ -32,15 +33,17 @@ events.onListeners(EVENT, cbs => {
33
})
34
35
export interface DynamicDnsResult { ts: string, error: string, url: string }
35
-let stopEvent: any
36
+let stopListening: any
37
let last: DynamicDnsResult | undefined
38
dynamicDnsUrl.sub(v => {
38
- stopEvent?.()
39
+ stopListening?.()
40
if (!v) return
40
- stopEvent = events.on(EVENT, async map => {
41
- const all: DynamicDnsResult[] = await Promise.all(v.split('\n').map(async line => {
41
+ stopListening = events.on(EVENT, async () => {
42
+ if (!lastMap) return // called at start once, before first getPublicIps. Just skip it
43
+ const lines = dynamicDnsUrl.get()
44
+ const all: DynamicDnsResult[] = await Promise.all(lines.split('\n').map(async line => {
45
const [templateUrl, re] = splitAt('>', line)
43
- const url = replace(templateUrl, map, '$')
46
+ const url = replace(templateUrl, lastMap, '$')
47
const error = await httpWithBody(url, { httpThrow: false, headers: { 'User-Agent': "HFS/" + VERSION } }) // UA specified as requested by no-ip guidelines
48
.then(async res => {
49
const str = String(res.body).trim()
@@ -51,7 +54,7 @@ dynamicDnsUrl.sub(v => {
54
last = _.find(all, 'error') || all[0] // the system is designed for just one result, and we give precedence to errors
55
events.emit('dynamicDnsError', last)
56
console.log('dynamic dns update', last?.error || 'ok')
54
- })
57
+ }, { callNow: true })
58
})
59
60
export async function* get_dynamic_dns_error() {
src/events.ts
+4
-1
@@ -8,7 +8,7 @@ export class BetterEventEmitter {
8
protected listeners = new Map<string, Listeners>()
9
preventDefault = Symbol()
10
stop = this.preventDefault // legacy pre-0.54 (introduced in 0.53)
11
- on(event: string | string[], listener: Listener, { warnAfter=10 }={}) {
11
+ on(event: string | string[], listener: Listener, { warnAfter=10, callNow=false }={}) {
12
if (typeof event === 'string')
13
event = [event]
14
for (const e of event) {
@@ -20,6 +20,9 @@ export class BetterEventEmitter {
20
console.warn("Warning: many event listeners for ", e)
21
this.emit(e + LISTENERS_SUFFIX, cbs)
22
}
23
+ if (callNow)
24
+ try { listener() }
25
+ catch {}
26
return () => {
27
for (const e of event) {
28
const cbs = this.listeners.get(e)