logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
+#logger.setLevel(logging.DEBUG)
# 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_data() will fail
+# update() will fail
_pending = {
# Detection mode
# NULL means all detection methods have failed (maybe still reachable instance)
"total_peers" : {},
# Found total blocks
"total_blocks" : {},
+ # Obfuscated domains
+ "obfuscated_blocks" : {},
# Last fetched instances
"last_instance_fetch": {},
# Last updated
logger.debug("has='%s' - EXIT!", has)
return has
-def update_data(domain: str):
+def update(domain: str):
logger.debug("domain='%s' - CALLED!", domain)
domain_helper.raise_on(domain)
if not has_pending(domain):
logger.debug("sql_string(%d)='%s'", len(sql_string), sql_string)
if sql_string == "":
- raise ValueError(f"No fields have been set, but method invoked, domain='{domain}'")
+ raise ValueError(f"No fields have been set, but function invoked, domain='{domain}'")
# Set last_updated to current timestamp
fields.append(time.time())
# For WHERE statement
+ logger.debug("Setting domain='%s' for WHERE statement ...", domain)
fields.append(domain)
logger.debug("sql_string='%s',fields()=%d", sql_string, len(fields))
elif origin is not None and not validators.domain(origin.split("/")[0]):
raise ValueError(f"Bad origin name='{origin}'")
elif blacklist.is_blacklisted(domain):
- raise Exception(f"domain='{domain}' is blacklisted, but method invoked")
+ raise Exception(f"domain='{domain}' is blacklisted, but function invoked")
elif domain.find("/profile/") > 0 or domain.find("/users/") > 0 or (is_registered(domain.split("/")[0]) and domain.find("/c/") > 0):
raise Exception(f"domain='{domain}' is a single user")
elif domain.find("/tag/") > 0:
logger.debug("Checking if domain='%s' has pending updates ...", domain)
if has_pending(domain):
logger.debug("Flushing updates for domain='%s' ...", domain)
- update_data(domain)
+ update(domain)
logger.debug("EXIT!")
logger.debug("EXIT!")
-def is_registered(domain: str) -> bool:
- logger.debug("domain='%s' - CALLED!", domain)
- domain_helper.raise_on(domain)
+def is_registered(domain: str, skip_raise = False) -> bool:
+ logger.debug("domain='%s',skip_raise='%s' - CALLED!", domain, skip_raise)
+ if not isinstance(skip_raise, bool):
+ raise ValueError(f"skip_raise[]='{type(skip_raise)}' is not type of 'bool'")
+
+ if not skip_raise:
+ domain_helper.raise_on(domain)
logger.debug("domain='%s' - CALLED!", domain)
if not cache.key_exists("is_registered"):
if not isinstance(column, str):
raise ValueError(f"Parameter column[]='{type(column)}' is not of type 'str'")
- elif column not in ["last_instance_fetch", "last_blocked"]:
+ elif not column.startswith("last_"):
raise ValueError(f"Parameter column='{column}' is not expected")
elif not is_registered(domain):
logger.debug("domain='%s' is not registered, returning False - EXIT!", domain)
return False
+ key = "recheck_instance"
+ if column == "last_blocked":
+ key = "recheck_block"
+
# Query database
database.cursor.execute(f"SELECT {column} FROM instances WHERE domain = ? LIMIT 1", [domain])
# Fetch row
- fetched = database.cursor.fetchone()[column]
+ row = database.cursor.fetchone()
- logger.debug("fetched[%s]='%s'", type(fetched), fetched)
- recently = isinstance(fetched, float) and (time.time() - fetched) <= config.get("recheck_instance")
+ fetched = float(row[column]) if row[column] is not None else 0.0
+
+ diff = (time.time() - fetched)
+
+ logger.debug("fetched[%s]='%s',key='%s',diff=%f", type(fetched), fetched, key, diff)
+ recently = bool(diff < config.get(key))
logger.debug("recently='%s' - EXIT!", recently)
return recently
elif not char in domain:
raise ValueError(f"char='{char}' not found in domain='{domain}' but function invoked")
elif not isinstance(domain, str):
- raise ValueError(f"Parameter domain[]='%s'", type(domain))
+ raise ValueError(f"Parameter domain[]='{type(domain)}'")
elif domain == "":
raise ValueError("Parameter 'domain' is empty")
elif not isinstance(blocked_hash, str) and blocked_hash is not None:
logger.debug("domain='%s' - AFTER!", domain)
if domain == "":
- debug.warning("domain is empty after tidyup - EXIT!")
+ logger.warning("domain is empty after tidyup - EXIT!")
return None
search = domain.replace(char, "_")
_set_data("total_blocks", domain, len(blocks))
logger.debug("EXIT!")
+def set_obfuscated_blocks(domain: str, obfuscated: int):
+ logger.debug("domain='%s',obfuscated=%d - CALLED!", domain, obfuscated)
+ domain_helper.raise_on(domain)
+
+ if not isinstance(obfuscated, int):
+ raise ValueError(f"Parameter obfuscated[]='{type(obfuscated)}' is not of type 'int'")
+ elif obfuscated < 0:
+ raise ValueError(f"Parameter obfuscated={obfuscated} is not valid")
+
+ # Set timestamp
+ _set_data("obfuscated_blocks", domain, obfuscated)
+ logger.debug("EXIT!")
+
def set_nodeinfo_url(domain: str, url: str):
logger.debug("domain='%s',url='%s' - CALLED!", domain, url)
domain_helper.raise_on(domain)
logger.debug("EXIT!")
def set_has_obfuscation(domain: str, status: bool):
- logger.debug("domain(%d)='%s',status='%s' - CALLED!", len(domain), domain, status)
+ logger.debug("domain='%s',status='%s' - CALLED!", domain, status)
domain_helper.raise_on(domain)
if not isinstance(status, bool):
# Set timestamp
_set_data("software", domain, software)
logger.debug("EXIT!")
+
+def valid(value: str, column: str) -> bool:
+ logger.debug("value='%s' - CALLED!", value)
+ if not isinstance(value, str):
+ raise ValueError(f"Parameter value[]='{type(value)}' is not of type 'str'")
+ elif value == "":
+ raise ValueError("Parameter 'value' is empty")
+ elif not isinstance(column, str):
+ raise ValueError(f"Parameter column[]='{type(column)}' is not of type 'str'")
+ elif column == "":
+ raise ValueError("Parameter 'column' is empty")
+
+ # Query database
+ database.cursor.execute(
+ f"SELECT {column} FROM instances WHERE {column} = ? LIMIT 1", [value]
+ )
+
+ is_valid = database.cursor.fetchone() is not None
+
+ logger.debug("is_valid='%s' - EXIT!", is_valid)
+ return is_valid
+
+def translate_idnas(rows: list, column: str):
+ logger.debug("rows[]='%s' - CALLED!", type(rows))
+ if not isinstance(rows, list):
+ raise ValueError("rows[]='{type(rows)}' is not of type 'list'")
+ elif len(rows) == 0:
+ raise ValueError("Parameter 'rows' is an empty list")
+ elif not isinstance(column, str):
+ raise ValueError(f"column='{type(column)}' is not of type 'str'")
+ elif column == "":
+ raise ValueError("Parameter 'column' is empty")
+ elif column not in ["domain", "origin"]:
+ raise ValueError(f"column='{column}' is not supported")
+
+ logger.info("Checking/converting %d domain names ...", len(rows))
+ for row in rows:
+ logger.debug("row[]='%s'", type(row))
+
+ translated = row[column].encode("idna").decode("utf-8")
+ logger.debug("translated='%s',row[%s]='%s'", translated, column, row[column])
+
+ if translated != row[column]:
+ logger.info("Translated row[%s]='%s' to '%s'", column, row[column], translated)
+ if is_registered(translated, True):
+ logger.warning("Deleting row[%s]='%s' as translated='%s' already exist", column, row[column], translated)
+ database.cursor.execute(f"DELETE FROM instances WHERE {column} = ? LIMIT 1", [row[column]])
+ else:
+ database.cursor.execute(f"UPDATE instances SET {column} = ? WHERE {column} = ? LIMIT 1", [translated, row[column]])
+
+ logger.debug("Invoking commit() ...")
+ database.connection.commit()
+
+ logger.debug("EXIT!")