]> git.mxchange.org Git - fba.git/commitdiff
Continued:
authorRoland Häder <roland@mxchange.org>
Thu, 8 Jun 2023 06:01:00 +0000 (08:01 +0200)
committerRoland Häder <roland@mxchange.org>
Thu, 8 Jun 2023 06:38:19 +0000 (08:38 +0200)
- moved more instances-related functions to module fba.instances
- also cut of /profile/ and /users/ from paths

fba/commands.py
fba/fba.py
fba/federation/gotosocial.py
fba/federation/mastodon.py
fba/federation/pleroma.py
fba/instances.py

index 514da073b71654fc65db8d31b51cb572e0b9c6ff..408eadd52a669f35494b7b4e193b77a2984dc936 100644 (file)
@@ -44,7 +44,7 @@ def check_instance(args: argparse.Namespace) -> int:
     elif blacklist.is_blacklisted(args.domain):
         print(f"WARNING: args.domain='{args.domain}' is blacklisted")
         status = 101
-    elif fba.is_instance_registered(args.domain):
+    elif instances.is_registered(args.domain):
         print(f"WARNING: args.domain='{args.domain}' is already registered")
         status = 102
     else:
@@ -80,7 +80,7 @@ def fetch_bkali(args: argparse.Namespace):
             elif blacklist.is_blacklisted(entry["domain"]):
                 # DEBUG: print(f"DEBUG: domain='{entry['domain']}' is blacklisted - SKIPPED!")
                 continue
-            elif fba.is_instance_registered(entry["domain"]):
+            elif instances.is_registered(entry["domain"]):
                 # DEBUG: print(f"DEBUG: domain='{entry['domain']}' is already registered - SKIPPED!")
                 continue
 
@@ -111,7 +111,7 @@ def fetch_blocks(args: argparse.Namespace):
         elif blacklist.is_blacklisted(args.domain):
             print(f"WARNING: domain='{args.domain}' is blacklisted, won't check it!")
             return
-        elif not fba.is_instance_registered(args.domain):
+        elif not instances.is_registered(args.domain):
             print(f"WARNING: domain='{args.domain}' is not registered, please run ./fba.py fetch_instances {args.domain} first.")
             return
 
@@ -218,7 +218,7 @@ def fetch_blocks(args: argparse.Namespace):
                         if not validators.domain(blocked):
                             print(f"WARNING: blocked='{blocked}',software='{software}' is not a valid domain name - skipped!")
                             continue
-                        elif not fba.is_instance_registered(blocked):
+                        elif not instances.is_registered(blocked):
                             # DEBUG: print("DEBUG: Hash wasn't found, adding:", blocked, blocker)
                             instances.add(blocked, blocker, inspect.currentframe().f_code.co_name, nodeinfo_url)
 
@@ -288,7 +288,7 @@ def fetch_cs(args: argparse.Namespace):
 
             for row in domains[block_level]:
                 # DEBUG: print(f"DEBUG: row='{row}'")
-                if not fba.is_instance_registered(row["domain"]):
+                if not instances.is_registered(row["domain"]):
                     print(f"INFO: Fetching instances from domain='{row['domain']}' ...")
                     fba.fetch_instances(row["domain"], None, None, inspect.currentframe().f_code.co_name)
 
@@ -325,7 +325,7 @@ def fetch_fba_rss(args: argparse.Namespace):
                 elif domain in domains:
                     # DEBUG: print(f"DEBUG: domain='{domain}' is already added - SKIPPED!")
                     continue
-                elif fba.is_instance_registered(domain):
+                elif instances.is_registered(domain):
                     # DEBUG: print(f"DEBUG: domain='{domain}' is already registered - SKIPPED!")
                     continue
 
@@ -378,7 +378,7 @@ def fetch_fbabot_atom(args: argparse.Namespace):
                         elif domain in domains:
                             # DEBUG: print(f"DEBUG: domain='{domain}' is already added - SKIPPED!")
                             continue
-                        elif fba.is_instance_registered(domain):
+                        elif instances.is_registered(domain):
                             # DEBUG: print(f"DEBUG: domain='{domain}' is already registered - SKIPPED!")
                             continue
 
index 2d11a69f03894b87d9c74f4fc4f872d4b516381b..9a8b3d7319c689f4c1487bebf27084f4c73509a2 100644 (file)
@@ -101,7 +101,7 @@ def fetch_instances(domain: str, origin: str, software: str, script: str, path:
     elif domain == "":
         raise ValueError(f"Parameter 'domain' is empty")
 
-    if not is_instance_registered(domain):
+    if not instances.is_registered(domain):
         # DEBUG: print("DEBUG: Adding new domain:", domain, origin)
         instances.add(domain, origin, script, path)
 
@@ -113,7 +113,7 @@ def fetch_instances(domain: str, origin: str, software: str, script: str, path:
         return
     elif instances.has_pending_instance_data(domain):
         # DEBUG: print(f"DEBUG: domain='{domain}' has pending nodeinfo data, flushing ...")
-        instances.update_instance_data(domain)
+        instances.update_data(domain)
 
     print(f"INFO: Checking {len(peerlist)} instances from {domain} ...")
     for instance in peerlist:
@@ -137,7 +137,7 @@ def fetch_instances(domain: str, origin: str, software: str, script: str, path:
 
         # DEBUG: print("DEBUG: Handling instance:", instance)
         try:
-            if not is_instance_registered(instance):
+            if not instances.is_registered(instance):
                 # DEBUG: print("DEBUG: Adding new instance:", instance, domain)
                 instances.add(instance, domain, script)
         except BaseException as e:
@@ -343,52 +343,6 @@ def log_error(domain: str, response: requests.models.Response):
 
     # DEBUG: print("DEBUG: EXIT!")
 
-def update_last_error(domain: str, response: requests.models.Response):
-    # DEBUG: print("DEBUG: domain,response[]:", domain, type(response))
-    if type(domain) != str:
-        raise ValueError(f"Parameter domain[]={type(domain)} is not 'str'")
-    elif domain == "":
-        raise ValueError(f"Parameter 'domain' is empty")
-
-    # DEBUG: print("DEBUG: BEFORE response[]:", type(response))
-    if isinstance(response, BaseException) or isinstance(response, json.decoder.JSONDecodeError):
-        response = f"{type}:str(response)"
-
-    # DEBUG: print("DEBUG: AFTER response[]:", type(response))
-    if type(response) is str:
-        # DEBUG: print(f"DEBUG: Setting last_error_details='{response}'");
-        instances.set("last_status_code"  , domain, 999)
-        instances.set("last_error_details", domain, response)
-    else:
-        # DEBUG: print(f"DEBUG: Setting last_error_details='{response.reason}'");
-        instances.set("last_status_code"  , domain, response.status_code)
-        instances.set("last_error_details", domain, response.reason)
-
-    # Running pending updated
-    # DEBUG: print(f"DEBUG: Invoking instances.update_instance_data({domain}) ...")
-    instances.update_instance_data(domain)
-
-    log_error(domain, response)
-
-    # DEBUG: print("DEBUG: EXIT!")
-
-def update_last_nodeinfo(domain: str):
-    # DEBUG: print(f"DEBUG: domain='{domain}' - CALLED!")
-    if type(domain) != str:
-        raise ValueError(f"Parameter domain[]={type(domain)} is not 'str'")
-    elif domain == "":
-        raise ValueError(f"Parameter 'domain' is empty")
-
-    # DEBUG: print("DEBUG: Updating last_nodeinfo for domain:", domain)
-    instances.set("last_nodeinfo", domain, time.time())
-    instances.set("last_updated" , domain, time.time())
-
-    # Running pending updated
-    # DEBUG: print(f"DEBUG: Invoking instances.update_instance_data({domain}) ...")
-    instances.update_instance_data(domain)
-
-    # DEBUG: print("DEBUG: EXIT!")
-
 def get_peers(domain: str, software: str) -> list:
     # DEBUG: print(f"DEBUG: domain({len(domain)})={domain},software={software} - CALLED!")
     if type(domain) != str:
@@ -424,7 +378,7 @@ def get_peers(domain: str, software: str) -> list:
             # DEBUG: print(f"DEBUG: response.ok={response.ok},response.status_code={response.status_code},data[]='{type(data)}'")
             if not response.ok or response.status_code >= 400:
                 print("WARNING: Could not reach any JSON API:", domain)
-                update_last_error(domain, response)
+                instances.update_last_error(domain, response)
             elif response.ok and isinstance(data, list):
                 # DEBUG: print(f"DEBUG: domain='{domain}' returned a list: '{data}'")
                 sys.exit(255)
@@ -434,14 +388,14 @@ def get_peers(domain: str, software: str) -> list:
                 # DEBUG: print("DEBUG: Added instance(s) to peers")
             else:
                 print("WARNING: JSON response does not contain 'federated_instances':", domain)
-                update_last_error(domain, response)
+                instances.update_last_error(domain, response)
         else:
             # DEBUG: print("DEBUG: Querying API was successful:", domain, len(data))
             peers = data
 
     except BaseException as e:
         print("WARNING: Some error during get():", domain, e)
-        update_last_error(domain, e)
+        instances.update_last_error(domain, e)
 
     # DEBUG: print(f"DEBUG: Adding '{len(peers)}' for domain='{domain}'")
     instances.set("total_peers", domain, len(peers))
@@ -479,7 +433,7 @@ def post_json_api(domain: str, path: str, parameter: str, extra_headers: dict =
         # DEBUG: print(f"DEBUG: response.ok={response.ok},response.status_code={response.status_code},data[]='{type(data)}'")
         if not response.ok or response.status_code >= 400:
             print(f"WARNING: Cannot query JSON API: domain='{domain}',path='{path}',parameter()={len(parameter)},response.status_code='{response.status_code}',data[]='{type(data)}'")
-            update_last_error(domain, response)
+            instances.update_last_error(domain, response)
 
     except BaseException as e:
         print(f"WARNING: Some error during post(): domain='{domain}',path='{path}',parameter()={len(parameter)},exception[{type(e)}]:'{str(e)}'")
@@ -535,12 +489,12 @@ def fetch_nodeinfo(domain: str, path: str = None) -> list:
                 sys.exit(255)
             elif not response.ok or response.status_code >= 400:
                 print("WARNING: Failed fetching nodeinfo from domain:", domain)
-                update_last_error(domain, response)
+                instances.update_last_error(domain, response)
                 continue
 
         except BaseException as e:
             # DEBUG: print("DEBUG: Cannot fetch API request:", request)
-            update_last_error(domain, e)
+            instances.update_last_error(domain, e)
             pass
 
     # DEBUG: print(f"DEBUG: data()={len(data)} - EXIT!")
@@ -586,7 +540,7 @@ def fetch_wellknown_nodeinfo(domain: str) -> list:
 
     except BaseException as e:
         print("WARNING: Failed fetching .well-known info:", domain)
-        update_last_error(domain, e)
+        instances.update_last_error(domain, e)
         pass
 
     # DEBUG: print("DEBUG: Returning data[]:", type(data))
@@ -635,7 +589,7 @@ def fetch_generator_from_path(domain: str, path: str = "/") -> str:
 
     except BaseException as e:
         # DEBUG: print(f"DEBUG: Cannot fetch / from '{domain}':", e)
-        update_last_error(domain, e)
+        instances.update_last_error(domain, e)
         pass
 
     # DEBUG: print(f"DEBUG: software[]={type(software)}")
@@ -686,11 +640,11 @@ def determine_software(domain: str, path: str = None) -> str:
     # DEBUG: print("DEBUG: data():", len(data), data)
     if "status" in data and data["status"] == "error" and "message" in data:
         print("WARNING: JSON response is an error:", data["message"])
-        update_last_error(domain, data["message"])
+        instances.update_last_error(domain, data["message"])
         return fetch_generator_from_path(domain)
     elif "message" in data:
         print("WARNING: JSON response contains only a message:", data["message"])
-        update_last_error(domain, data["message"])
+        instances.update_last_error(domain, data["message"])
         return fetch_generator_from_path(domain)
     elif "software" not in data or "name" not in data["software"]:
         # DEBUG: print(f"DEBUG: JSON response from domain='{domain}' does not include [software][name], fetching / ...")
@@ -748,31 +702,6 @@ def determine_software(domain: str, path: str = None) -> str:
     # DEBUG: print("DEBUG: Returning domain,software:", domain, software)
     return software
 
-def is_instance_registered(domain: str) -> bool:
-    # DEBUG: print(f"DEBUG: domain='{domain}' - CALLED!")
-    if type(domain) != str:
-        raise ValueError(f"Parameter domain[]={type(domain)} is not 'str'")
-    elif domain == "":
-        raise ValueError(f"Parameter 'domain' is empty")
-
-    # DEBUG: print(f"DEBUG: domain='{domain}' - CALLED!")
-    if not cache.key_exists("is_registered"):
-        # DEBUG: print(f"DEBUG: Cache for 'is_registered' not initialized, fetching all rows ...")
-        try:
-            cursor.execute("SELECT domain FROM instances")
-
-            # Check Set all
-            cache.set_all("is_registered", cursor.fetchall(), True)
-        except BaseException as e:
-            print(f"ERROR: failed SQL query: domain='{domain}',exception[{type(e)}]:'{str(e)}'")
-            sys.exit(255)
-
-    # Is cache found?
-    registered = cache.sub_key_exists("is_registered", domain)
-
-    # DEBUG: print(f"DEBUG: registered='{registered}' - EXIT!")
-    return registered
-
 def send_bot_post(instance: str, blocklist: dict):
     # DEBUG: print(f"DEBUG: instance={instance},blocklist()={len(blocklist)} - CALLED!")
     if type(domain) != str:
@@ -835,7 +764,7 @@ def fetch_friendica_blocks(domain: str) -> dict:
         )
     except BaseException as e:
         print("WARNING: Failed to fetch /friendica from domain:", domain, e)
-        update_last_error(domain, e)
+        instances.update_last_error(domain, e)
         return {}
 
     blocklist = doc.find(id="about_blocklist")
@@ -941,7 +870,7 @@ def fetch_misskey_blocks(domain: str) -> dict:
 
         except BaseException as e:
             print("WARNING: Caught error, exiting loop:", domain, e)
-            update_last_error(domain, e)
+            instances.update_last_error(domain, e)
             offset = 0
             break
 
@@ -998,7 +927,7 @@ def fetch_misskey_blocks(domain: str) -> dict:
 
         except BaseException as e:
             print("ERROR: Exception during POST:", domain, e)
-            update_last_error(domain, e)
+            instances.update_last_error(domain, e)
             offset = 0
             break
 
@@ -1047,6 +976,10 @@ def tidyup_domain(domain: str) -> str:
 
     # No individual users in block lists
     domain = re.sub("(.+)\@", "", domain)
+    if domain.find("/profile/"):
+        domain = domain.split("/profile/")[0]
+    elif domain.find("/users/"):
+        domain = domain.split("/users/")[0]
 
     # DEBUG: print(f"DEBUG: domain='{domain}' - EXIT!")
     return domain
@@ -1087,7 +1020,7 @@ def get_response(domain: str, path: str, headers: dict, timeout: list) -> reques
         );
     except requests.exceptions.ConnectionError as e:
         # DEBUG: print(f"DEBUG: Fetching '{path}' from '{domain}' failed. exception[{type(e)}]='{str(e)}'")
-        update_last_error(domain, e)
+        instances.update_last_error(domain, e)
         raise e
 
     # DEBUG: print(f"DEBUG: response[]='{type(response)}' - EXXIT!")
index 4008110e98b15e93bbccc0be05ace82a349a69dd..2ca6309e1826931a6dcbd21fb455c23792615c46 100644 (file)
@@ -21,6 +21,7 @@ from fba import blacklist
 from fba import blocks
 from fba import config
 from fba import fba
+from fba import instances
 
 def fetch_blocks(domain: str, origin: str, nodeinfo_url: str):
     print(f"DEBUG: domain='{domain}',origin='{origin}',nodeinfo_url='{nodeinfo_url}' - CALLED!")
@@ -81,7 +82,7 @@ def fetch_blocks(domain: str, origin: str, nodeinfo_url: str):
                 if not validators.domain(blocked):
                     print(f"WARNING: blocked='{blocked}',software='gotosocial' is not a valid domain name - skipped!")
                     continue
-                elif not fba.is_instance_registered(blocked):
+                elif not instances.is_registered(blocked):
                     # DEBUG: print(f"DEBUG: Domain blocked='{blocked}' wasn't found, adding ..., domain='{domain}',origin='{origin}',nodeinfo_url='{nodeinfo_url}'")
                     instances.add(blocked, domain, inspect.currentframe().f_code.co_name, nodeinfo_url)
 
index e0c180d8fbb9dd8612d90614876444aaef1e5519..e03a7d7cce8cbce7f7c131ec5ca4f8a5eb16090e 100644 (file)
@@ -21,6 +21,7 @@ from fba import blacklist
 from fba import blocks
 from fba import config
 from fba import fba
+from fba import instances
 
 language_mapping = {
     # English -> English
@@ -217,7 +218,7 @@ def fetch_blocks(domain: str, origin: str, nodeinfo_url: str):
                     if not validators.domain(blocked):
                         print(f"WARNING: blocked='{blocked}',software='mastodon' is not a valid domain name - skipped!")
                         continue
-                    elif not fba.is_instance_registered(blocked):
+                    elif not instances.is_registered(blocked):
                         # DEBUG: print(f"DEBUG: Domain blocked='{blocked}' wasn't found, adding ..., domain='{domain}',origin='{origin}',nodeinfo_url='{nodeinfo_url}'")
                         instances.add(blocked, domain, inspect.currentframe().f_code.co_name, nodeinfo_url)
                 elif not validators.domain(blocked):
@@ -228,7 +229,7 @@ def fetch_blocks(domain: str, origin: str, nodeinfo_url: str):
                 if not validators.domain(blocked):
                     print(f"WARNING: blocked='{blocked}',software='mastodon' is not a valid domain name - skipped!")
                     continue
-                elif not fba.is_instance_registered(blocked):
+                elif not instances.is_registered(blocked):
                     # DEBUG: print("DEBUG: Hash wasn't found, adding:", blocked, domain)
                     instances.add(blocked, domain, inspect.currentframe().f_code.co_name, nodeinfo_url)
 
index 52c0f00c2450473c03dd3e8b96d332d31ee697e4..3e47c01c2c19031ebfc9a2d888fd8608ddfdde71 100644 (file)
@@ -20,6 +20,7 @@ import validators
 from fba import blacklist
 from fba import blocks
 from fba import fba
+from fba import instances
 
 def fetch_blocks(domain: str, origin: str, nodeinfo_url: str):
     print(f"DEBUG: domain='{domain}',origin='{origin}',nodeinfo_url='{nodeinfo_url}' - CALLED!")
@@ -52,7 +53,7 @@ def fetch_blocks(domain: str, origin: str, nodeinfo_url: str):
             return
 
         # DEBUG: print("DEBUG: Updating nodeinfo:", domain)
-        fba.update_last_nodeinfo(domain)
+        instances.update_last_nodeinfo(domain)
 
         federation = json["metadata"]["federation"]
 
@@ -108,7 +109,7 @@ def fetch_blocks(domain: str, origin: str, nodeinfo_url: str):
                     if not validators.domain(blocked):
                         print(f"WARNING: blocked='{blocked}',software='pleroma' is not a valid domain name - skipped!")
                         continue
-                    elif not fba.is_instance_registered(blocked):
+                    elif not instances.is_registered(blocked):
                         # DEBUG: print(f"DEBUG: Domain blocked='{blocked}' wasn't found, adding ..., domain='{domain}',origin='{origin}',nodeinfo_url='{nodeinfo_url}'")
                         instances.add(blocked, domain, inspect.currentframe().f_code.co_name, nodeinfo_url)
 
@@ -181,7 +182,7 @@ def fetch_blocks(domain: str, origin: str, nodeinfo_url: str):
                     if not validators.domain(blocked):
                         print(f"WARNING: blocked='{blocked}',software='pleroma' is not a valid domain name - skipped!")
                         continue
-                    elif not fba.is_instance_registered(blocked):
+                    elif not instances.is_registered(blocked):
                         # DEBUG: print(f"DEBUG: Domain blocked='{blocked}' wasn't found, adding ..., domain='{domain}',origin='{origin}',nodeinfo_url='{nodeinfo_url}'")
                         instances.add(blocked, domain, inspect.currentframe().f_code.co_name, nodeinfo_url)
 
index 88189207bfedd046811327744b9ab6c4b9187620..76a1a80aa4d58b878423abe6503445499955a3bf 100644 (file)
 # You should have received a copy of the GNU Affero General Public License
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
+import json
+import requests
 import sys
 import time
+import validators
 
+from fba import blacklist
+from fba import cache
 from fba import fba
 
 # Found info from node, such as nodeinfo URL, detection mode that needs to be
 # written to database. Both arrays must be filled at the same time or else
-# update_instance_data() will fail
+# update_data() will fail
 _pending = {
     # Detection mode: 'AUTO_DISCOVERY', 'STATIC_CHECKS' or 'GENERATOR'
     # NULL means all detection methods have failed (maybe still reachable instance)
@@ -81,7 +86,7 @@ def has_pending_instance_data(domain: str) -> bool:
     # DEBUG: print(f"DEBUG: has_pending='{has_pending}' - EXIT!")
     return has_pending
 
-def update_instance_data(domain: str):
+def update_data(domain: str):
     # DEBUG: print(f"DEBUG: domain='{domain}' - CALLED!")
     if type(domain) != str:
         raise ValueError(f"Parameter domain[]={type(domain)} is not 'str'")
@@ -147,8 +152,8 @@ def update_last_instance_fetch(domain: str):
     set("last_instance_fetch", domain, time.time())
 
     # Running pending updated
-    # DEBUG: print(f"DEBUG: Invoking update_instance_data({domain}) ...")
-    update_instance_data(domain)
+    # DEBUG: print(f"DEBUG: Invoking update_data({domain}) ...")
+    update_data(domain)
 
     # DEBUG: print("DEBUG: EXIT!")
 
@@ -162,8 +167,8 @@ def update_last_blocked(domain: str):
     set("last_blocked", domain, time.time())
 
     # Running pending updated
-    # DEBUG: print(f"DEBUG: Invoking update_instance_data({domain}) ...")
-    update_instance_data(domain)
+    # DEBUG: print(f"DEBUG: Invoking update_data({domain}) ...")
+    update_data(domain)
 
     # DEBUG: print("DEBUG: EXIT!")
 
@@ -185,26 +190,27 @@ def add(domain: str, origin: str, originator: str, path: str = None):
         raise ValueError(f"Bad origin name='{origin}'")
     elif blacklist.is_blacklisted(domain):
         raise Exception(f"domain='{domain}' is blacklisted, but method invoked")
+    elif domain.find("/profile/") > 0 or domain.find("/users/") > 0:
+        raise Exception(f"domain='{domain}' is a single user")
 
     # DEBUG: print("DEBUG: domain,origin,originator,path:", domain, origin, originator, path)
-    if domain.find("/profile") > 0:
-        # Need to cut off /profile/* part
-        domain = domain.split("/profile/")[0]
-        if instances.is_registered(domain):
-            raise Exception(f"WARNING: After removing /profile/ domain='{domain}' is already registered - EXIT!")
-
-    software = determine_software(domain, path)
+    software = fba.determine_software(domain, path)
     # DEBUG: print("DEBUG: Determined software:", software)
+    if domain.find("/c/") > 0 and software == "lemmy":
+        domain = domain.split("/c/")[0]
+        if is_registered(domain):
+            print(f"WARNING: domain='{domain}' already registered after cutting off user part. - EXIT!")
+            return
 
     print(f"INFO: Adding instance domain='{domain}' (origin='{origin}',software='{software}')")
     try:
-        cursor.execute(
+        fba.cursor.execute(
             "INSERT INTO instances (domain, origin, originator, hash, software, first_seen) VALUES (?, ?, ?, ?, ?, ?)",
             (
                domain,
                origin,
                originator,
-               get_hash(domain),
+               fba.get_hash(domain),
                software,
                time.time()
             ),
@@ -212,17 +218,17 @@ def add(domain: str, origin: str, originator: str, path: str = None):
 
         cache.set_sub_key("is_registered", domain, True)
 
-        if instances.has_pending_instance_data(domain):
+        if has_pending_instance_data(domain):
             # DEBUG: print(f"DEBUG: domain='{domain}' has pending nodeinfo being updated ...")
-            instances.set("last_status_code"  , domain, None)
-            instances.set("last_error_details", domain, None)
-            instances.update_instance_data(domain)
-            remove_pending_error(domain)
+            set("last_status_code"  , domain, None)
+            set("last_error_details", domain, None)
+            update_data(domain)
+            fba.remove_pending_error(domain)
 
-        if domain in pending_errors:
+        if domain in fba.pending_errors:
             # DEBUG: print("DEBUG: domain has pending error being updated:", domain)
-            update_last_error(domain, pending_errors[domain])
-            remove_pending_error(domain)
+            update_last_error(domain, fba.pending_errors[domain])
+            fba.remove_pending_error(domain)
 
     except BaseException as e:
         print(f"ERROR: failed SQL query: domain='{domain}',exception[{type(e)}]:'{str(e)}'")
@@ -232,3 +238,74 @@ def add(domain: str, origin: str, originator: str, path: str = None):
         update_last_nodeinfo(domain)
 
     # DEBUG: print("DEBUG: EXIT!")
+
+def update_last_nodeinfo(domain: str):
+    # DEBUG: print(f"DEBUG: domain='{domain}' - CALLED!")
+    if type(domain) != str:
+        raise ValueError(f"Parameter domain[]={type(domain)} is not 'str'")
+    elif domain == "":
+        raise ValueError(f"Parameter 'domain' is empty")
+
+    # DEBUG: print("DEBUG: Updating last_nodeinfo for domain:", domain)
+    set("last_nodeinfo", domain, time.time())
+    set("last_updated" , domain, time.time())
+
+    # Running pending updated
+    # DEBUG: print(f"DEBUG: Invoking update_data({domain}) ...")
+    update_data(domain)
+
+    # DEBUG: print("DEBUG: EXIT!")
+
+def update_last_error(domain: str, response: requests.models.Response):
+    # DEBUG: print("DEBUG: domain,response[]:", domain, type(response))
+    if type(domain) != str:
+        raise ValueError(f"Parameter domain[]={type(domain)} is not 'str'")
+    elif domain == "":
+        raise ValueError(f"Parameter 'domain' is empty")
+
+    # DEBUG: print("DEBUG: BEFORE response[]:", type(response))
+    if isinstance(response, BaseException) or isinstance(response, json.decoder.JSONDecodeError):
+        response = f"{type}:str(response)"
+
+    # DEBUG: print("DEBUG: AFTER response[]:", type(response))
+    if type(response) is str:
+        # DEBUG: print(f"DEBUG: Setting last_error_details='{response}'");
+        set("last_status_code"  , domain, 999)
+        set("last_error_details", domain, response)
+    else:
+        # DEBUG: print(f"DEBUG: Setting last_error_details='{response.reason}'");
+        set("last_status_code"  , domain, response.status_code)
+        set("last_error_details", domain, response.reason)
+
+    # Running pending updated
+    # DEBUG: print(f"DEBUG: Invoking update_data({domain}) ...")
+    update_data(domain)
+
+    fba.log_error(domain, response)
+
+    # DEBUG: print("DEBUG: EXIT!")
+
+def is_registered(domain: str) -> bool:
+    # DEBUG: print(f"DEBUG: domain='{domain}' - CALLED!")
+    if type(domain) != str:
+        raise ValueError(f"Parameter domain[]={type(domain)} is not 'str'")
+    elif domain == "":
+        raise ValueError(f"Parameter 'domain' is empty")
+
+    # DEBUG: print(f"DEBUG: domain='{domain}' - CALLED!")
+    if not cache.key_exists("is_registered"):
+        # DEBUG: print(f"DEBUG: Cache for 'is_registered' not initialized, fetching all rows ...")
+        try:
+            fba.cursor.execute("SELECT domain FROM instances")
+
+            # Check Set all
+            cache.set_all("is_registered", fba.cursor.fetchall(), True)
+        except BaseException as e:
+            print(f"ERROR: failed SQL query: domain='{domain}',exception[{type(e)}]:'{str(e)}'")
+            sys.exit(255)
+
+    # Is cache found?
+    registered = cache.sub_key_exists("is_registered", domain)
+
+    # DEBUG: print(f"DEBUG: registered='{registered}' - EXIT!")
+    return registered