From 25fc01f04f4cbf164e91afc95bec6921e9464c29 Mon Sep 17 00:00:00 2001
From: Ferenc Schulcz <schulcz.ferenc@gmail.com>
Date: Thu, 6 Feb 2025 15:11:23 +0100
Subject: [PATCH] Multiple DNS server support

---
 dyndns.py | 54 +++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 43 insertions(+), 11 deletions(-)

diff --git a/dyndns.py b/dyndns.py
index 393b46a..a1d4c82 100644
--- a/dyndns.py
+++ b/dyndns.py
@@ -1,11 +1,12 @@
 import services
 import db
 import os
-import requests
 import datetime
 import config
 import random
 import hashlib
+import asyncio
+import aiohttp
 from werkzeug.security import check_password_hash
 
 
@@ -36,6 +37,19 @@ def dyndns(**kwargs):
 
     return rqtools.render_template(plugin_dir + '/templates/dyndns.html', records=ownRecords, recordsCount=recordsCount, otherRecords=otherRecords)
 
+async def sendRequest(session, url, urlparams):
+    try:
+        async with session.get(url, params=urlparams) as response:
+            return response.status
+    except Exception as e:
+        print(f"Could not reach {url}: {e}")
+        return 600
+
+async def sendAllRequests(urls, urlparams):
+    async with aiohttp.ClientSession() as session:
+        requests = [sendRequest(session, url, urlparams) for url in urls]
+        return await asyncio.gather(*requests)
+
 def dyndnsRegister(**kwargs):
     session = kwargs['session']
     request = kwargs['request']
@@ -52,14 +66,23 @@ def dyndnsRegister(**kwargs):
         return rqtools.redirect(rqtools.url_for('service', servicename='dyndns'))
     tokenseed = str(random.randint(1, 2**32)) + str(random.randint(1, 2**32))
     domain = request.form['domainname']
-    r = requests.get(url = config.get('DYNDNS_SERVER_URL') + '/register', params = {'domain': domain, 'tokenseed': tokenseed})
-    reply = r.json()
-    if r.status_code > 299:
-        db.sendMessage(session['username'], reply['message'])
+    registrationStatuses = asyncio.run(sendAllRequests(config.get('DYNDNS_SERVER_URLS'), {'domain': domain, 'tokenseed': tokenseed}))
+    allFail = True
+    allSuccess = True
+    for s in registrationStatuses:
+        if s > 299:
+            allSuccess = False
+        else:
+            allFail = False
+    if allFail:
+        db.sendMessage(session['username'], "Registration is not possible as no DNS servers are online.")
         return rqtools.redirect(rqtools.url_for('service', servicename='dyndns'))
     token = hashlib.md5((domain + tokenseed).encode()).hexdigest()
-    x = db.db['dyndns-records'].insert_one({'username': session['username'], 'domain': reply['domainName'], 'token': token, 'ip': "null", 'lastupdate': "never"})
-    db.sendMessage(session['username'], reply['message'])
+    x = db.db['dyndns-records'].insert_one({'username': session['username'], 'domain': domain + '.dyndns.sfsrv.hu', 'token': token, 'ip': "null", 'lastupdate': "never"})
+    if allSuccess:
+        db.sendMessage(session['username'], "Registration successful. Record is not served until first DNS update.")
+    else:
+        db.sendMessage(session['username'], "Registration successful although not all DNS servers are online. Record is not served until first DNS update.")
     return rqtools.redirect(rqtools.url_for('service', servicename='dyndns'))
     
 
@@ -74,12 +97,21 @@ def dyndnsUpdate(**kwargs):
     x = db.db['dyndns-records'].find_one({'token': request.args['token']})
     if x['ip'] == ip:
         return {'message': 'Already set.'}, 200
-    r = requests.get(url = config.get('DYNDNS_SERVER_URL')+ "/update", params = {'token': request.args['token'], 'ip': ip})
-    reply = r.json()
-    if r.status_code < 300:
+    updateStatuses = asyncio.run(sendAllRequests(config.get('DYNDNS_SERVER_URLS'), {'token': request.args['token'], 'ip': ip}))
+    allFail = True
+    allSuccess = True
+    for s in updateStatuses:
+        if s > 299:
+            allSuccess = False
+        else:
+            allFail = False
+    if allSuccess:
+        print("Not updated " + x['domain'] + " as no DNS servers are online.")
+        return {'message': 'NOT updated. No DNS servers are online.'}, 500
+    else:
         print("Updated " + x['domain'] + " from " + x['ip'] + " to " + ip)
         db.db['dyndns-records'].update_one(filter={'token': request.args['token']}, update={'$set': {'ip': ip, 'lastupdate': datetime.datetime.now()}})
-    return reply, r.status_code
+        return {'message': 'Updated.'}, 200
 
 def dyndnsList(**kwargs):
 
-- 
GitLab