From 1c67a08b41feb82f78895ae9ac2b2f364626eb3f Mon Sep 17 00:00:00 2001 From: Nick Ninov Date: Thu, 12 Mar 2026 22:14:57 +0000 Subject: [PATCH] account: custom logger Related to https://github.com/status-im/status-bot/issues/7 - Add custom logger to `Account` class - Add `display_name` validation based on Status App - Update new `display_name` for other accounts when account has been recovered with mnemonics - Update documentation --- bot/account.py | 24 +++++++++++++++++++++--- bot/docs/account.md | 29 +++++++++++++++++++++++++++++ bot/logger.py | 24 ++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 bot/logger.py diff --git a/bot/account.py b/bot/account.py index 41c9787..74e3250 100644 --- a/bot/account.py +++ b/bot/account.py @@ -1,7 +1,7 @@ from typing import Optional, Union, Generator, Any -import requests, datetime, re +import requests, datetime, re, logging from .signal import Signal - +from .logger import Logger class Account: # Enum mappings from original wakuext.py @@ -28,6 +28,7 @@ class Account: - `port` - the port to connect to Status Backend. Verify the port in the Docker files. - `is_secure` - if `http` or `https` should be used """ + self.__logger = Logger() self.__timestamp_divisor = 1_000 self.__kd_iterations = 256000 self.__unix_folder = unix_folder @@ -86,7 +87,7 @@ class Account: raise ValueError(f"Given Key Unique Identifier is invalid...\nAvailable Key Unique Identifiers:\n{info}") is_new_account = isinstance(key_uid, type(None)) - is_recovery = not isinstance(mnemonic, type(None)) + is_recovery = not isinstance(mnemonic, type(None)) and not key_uid url_key = "login" params = { @@ -107,6 +108,7 @@ class Account: "thirdpartyServicesEnabled": True } url_key = "restore" + self.logger.info(f"Restoring account for given mnemonics") elif is_new_account: self.__validate_display_name(display_name) params = { @@ -119,6 +121,9 @@ class Account: "thirdpartyServicesEnabled": True, } url_key = "create" + self.logger.info(f"Creating account with display_name {display_name}") + else: + self.logger.info(f"Logging in with Key UID - {key_uid}") self.logout() url = self.urls["http"][url_key] @@ -127,6 +132,7 @@ class Account: if signal_event["is_error"]: raise Exception(f"There was an error with Status Backend...\n{signal_event['error_message']}") + self.logger.info("Successfully logged in!") event: dict = signal_event["event"]["settings"] self.__info = { "public_key": event["public-key"], @@ -142,6 +148,9 @@ class Account: } # Messenger can be activated only when logged in self.__start_messenger() + if is_recovery: + self.display_name = event["display-name"] + return self def logout(self): @@ -153,6 +162,10 @@ class Account: self.__is_messenger_launched = False return self + @property + def logger(self) -> logging.Logger: + return self.__logger + @property def available_accounts(self) -> list[dict]: """ @@ -505,9 +518,11 @@ class Account: """ if self.__is_messenger_launched: return + self.logger.info("Starting messaging") self.__call_rpc("messaging", "startMessenger") self.__signal.get("wakuv2.peerstats") self.__is_messenger_launched = True + self.logger.info("Messaging launched") def __del__(self): """ @@ -593,6 +608,9 @@ class Account: if len(name) < 5: raise ValueError("Display name must be at least 5 characters long.") + if len(name) > 24: + raise ValueError("Display name cannot be more than 24 characters long.") + if not re.fullmatch(r"[A-Za-z0-9_-]+", name): raise ValueError("Display name can contain only A-Z, 0-9, hyphens (-), and underscores (_).") diff --git a/bot/docs/account.md b/bot/docs/account.md index 12e6b45..2fc0950 100644 --- a/bot/docs/account.md +++ b/bot/docs/account.md @@ -13,6 +13,7 @@ Display names must follow strict validation rules enforced by the library and ex - It may contain **hyphens (`-`)** - It may contain **underscores (`_`)** - It must be **at least 5 characters long** +- It **cannot be more than 24 characters long** - It **cannot start or end with a space** Characters such as spaces, punctuation, emojis, or other symbols are **not allowed**. @@ -97,6 +98,10 @@ params = { account.login(**params) ``` +**Note**: When in recovery mode, the display name is updated on Status App as well so it is consistent locally and to other users. + + + ### `logout()` Logout from the currently logged-in Status account. This method also clears the internal account state and stops the active messenger session. This function is also supported in `del` and when the script automatically finishes. @@ -624,3 +629,27 @@ account.login(**params) # account.bio = None del account.bio ``` + +### `logger` + +Provides access to the internal **Python logger** for monitoring the lifecycle of the account and backend operations such as login, account creation, messenger startup, and recovery. + +Returns `logging.Logger`. + +Default logger configuration: + +- **Name**: `status-bot` +- **Level**: `INFO` +- **Output**: standard output (terminal) + +Example: + +```python +from bot import Account + +account = Account() + +account.logger.info("Starting Status bot") +account.logger.warning("This is a warning") +account.logger.error("Something went wrong") +``` diff --git a/bot/logger.py b/bot/logger.py new file mode 100644 index 0000000..850b254 --- /dev/null +++ b/bot/logger.py @@ -0,0 +1,24 @@ +from typing import Optional +import logging + +class Logger: + instance: Optional[logging.Logger] = None + + def __new__(cls) -> logging.Logger: + + if cls.instance: + return cls.instance + + cls.instance = logging.getLogger("status-bot") + cls.instance.setLevel(logging.INFO) + cls.instance.propagate = False + + handler = logging.StreamHandler() + formatter = logging.Formatter( + f"[%(asctime)s] [%(levelname)s]\t%(message)s", + datefmt="%Y-%m-%d %H:%M:%S" + ) + + handler.setFormatter(formatter) + cls.instance.addHandler(handler) + return cls.instance