mirror of
https://github.com/status-im/status-bot.git
synced 2026-08-27 10:41:08 +00:00
189 lines
5.6 KiB
Python
189 lines
5.6 KiB
Python
import os
|
|
import sys
|
|
import signal
|
|
import argparse
|
|
import logging
|
|
|
|
from fastapi import FastAPI
|
|
|
|
from status_sdk import Account
|
|
from status_bot import Config, Database, setup_logging
|
|
from status_bot.metrics import start_prometheus
|
|
from status_bot.modules.manager import ModuleManager
|
|
|
|
logger = logging.getLogger("status_bot.main")
|
|
|
|
|
|
def create_bot(config: Config, project_root: str) -> Account:
|
|
account = Account(**config.backend.model_dump())
|
|
available_accounts = [a["name"] for a in account.available_accounts]
|
|
|
|
name = config.bot.name
|
|
password = config.bot.password
|
|
|
|
if name in available_accounts:
|
|
logger.info(f"Logging in with display name: {name}")
|
|
account.login(
|
|
name=name,
|
|
password=password,
|
|
infura_token=config.bot.infura_token,
|
|
coingecko_api_key=config.bot.coingecko_api_key
|
|
)
|
|
elif config.bot.init_account:
|
|
mnemonic = config.bot.mnemonic_phrase
|
|
if not mnemonic:
|
|
raise ValueError(
|
|
"init_account is true but no mnemonic_phrase provided"
|
|
)
|
|
logger.info(f"Creating/restoring account: {name}")
|
|
account.login(
|
|
name=name,
|
|
password=password,
|
|
mnemonic=mnemonic,
|
|
infura_token=config.bot.infura_token,
|
|
coingecko_api_key=config.bot.coingecko_api_key
|
|
)
|
|
else:
|
|
raise ValueError(
|
|
f"Account '{name}' not found and init_account is false. "
|
|
f"Available accounts: {[a['display_name'] for a in available_accounts]}"
|
|
)
|
|
|
|
if account.info["compressed_key"] != config.bot.compressed_key:
|
|
raise Exception(
|
|
"Target compressed key and logged in compressed key are different."
|
|
)
|
|
|
|
profile_path = os.path.join(project_root, "assets", "profile.jpg")
|
|
account.profile_picture = profile_path
|
|
logger.info(
|
|
f"Account Information: {account.info['display_name']}\n"
|
|
f"\tCompressed Key: {account.info['compressed_key']}\n"
|
|
f"\tPublic Key: {account.info['public_key']}\n"
|
|
f"\tURL: {account.info['url']}"
|
|
)
|
|
return account
|
|
|
|
|
|
def init_database(config: Config) -> Database:
|
|
return Database(
|
|
db_type=config.database.type,
|
|
host=config.database.host,
|
|
port=config.database.port,
|
|
user=config.database.user,
|
|
password=config.database.password,
|
|
name=config.database.name,
|
|
schema=config.database.schema,
|
|
)
|
|
|
|
|
|
def main():
|
|
setup_logging()
|
|
|
|
parser = argparse.ArgumentParser(
|
|
description="Status Bot - Modular monitoring framework"
|
|
)
|
|
parser.add_argument(
|
|
"--config",
|
|
default="./config.yaml",
|
|
help="Path to configuration file (default: ./config.yaml)",
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
config_path = args.config
|
|
|
|
try:
|
|
logger.info("Loading the configuration")
|
|
Config._yaml_file = config_path
|
|
config = Config()
|
|
setup_logging(config)
|
|
except Exception as e:
|
|
logger.error(f"Failed to load config: {e}", exc_info=True)
|
|
sys.exit(1)
|
|
|
|
logger.info("Status Bot starting...")
|
|
|
|
project_root = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
try:
|
|
logger.info(
|
|
"Configuration loaded: backend=%s database=%s modules=%s",
|
|
config.backend.domain,
|
|
config.database.type,
|
|
config.modules.enabled,
|
|
)
|
|
account = create_bot(config, project_root)
|
|
except Exception as e:
|
|
logger.error(f"Failed to create bot account: {e}", exc_info=True)
|
|
sys.exit(1)
|
|
|
|
db = None
|
|
has_database = all([
|
|
config.database.host,
|
|
config.database.user,
|
|
config.database.password,
|
|
config.database.name,
|
|
])
|
|
|
|
if has_database:
|
|
try:
|
|
db = init_database(config)
|
|
logger.info(f"Database connection established ({config.database.type})")
|
|
except Exception as e:
|
|
logger.warning(f"Failed to connect to database: {e}", exc_info=True)
|
|
logger.warning("Continuing without database connection")
|
|
else:
|
|
logger.info("No database configuration found, running without database")
|
|
|
|
fastapi_app = FastAPI(title="Status Bot API")
|
|
shared_state = {"config": config, "project_root": project_root, "fastapi_app": fastapi_app}
|
|
|
|
if config.api.enable and "api_server" not in config.modules.enabled:
|
|
config.modules.enabled.append("api_server")
|
|
|
|
manager = ModuleManager(config.modules, account, db, shared_state=shared_state)
|
|
manager.discover_modules()
|
|
manager.load_modules()
|
|
|
|
if db is not None:
|
|
db.create_tables()
|
|
|
|
start_prometheus(config.metrics, manager)
|
|
|
|
stop_event = manager._stop_event
|
|
|
|
def handle_sigterm(signum, frame):
|
|
logger.info("Received SIGTERM, shutting down...")
|
|
stop_event.set()
|
|
|
|
signal.signal(signal.SIGTERM, handle_sigterm)
|
|
signal.signal(signal.SIGINT, handle_sigterm)
|
|
|
|
if manager.module_names:
|
|
logger.info(
|
|
f"Starting {len(manager.module_names)} module(s): "
|
|
f"{manager.module_names}"
|
|
)
|
|
manager.start_all()
|
|
|
|
try:
|
|
while manager.has_alive_modules():
|
|
stop_event.wait(1)
|
|
except KeyboardInterrupt:
|
|
logger.info("Received keyboard interrupt, shutting down...")
|
|
else:
|
|
logger.info("No modules enabled. Bot running without modules.")
|
|
logger.info("Press Ctrl+C to stop.")
|
|
try:
|
|
while True:
|
|
stop_event.wait(1)
|
|
except KeyboardInterrupt:
|
|
logger.info("Received keyboard interrupt, shutting down...")
|
|
|
|
manager.stop_all()
|
|
logger.info("Status Bot stopped")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|