Files
aitbc/cli/config/__init__.py
aitbc1 c0952c2525 refactor: flatten CLI directory structure - remove 'box in a box'
BEFORE:
/opt/aitbc/cli/
├── aitbc_cli/                    # Python package (box in a box)
│   ├── commands/
│   ├── main.py
│   └── ...
├── setup.py

AFTER:
/opt/aitbc/cli/                    # Flat structure
├── commands/                      # Direct access
├── main.py                        # Direct access
├── auth/
├── config/
├── core/
├── models/
├── utils/
├── plugins.py
└── setup.py

CHANGES MADE:
- Moved all files from aitbc_cli/ to cli/ root
- Fixed all relative imports (from . to absolute imports)
- Updated setup.py entry point: aitbc_cli.main → main
- Added CLI directory to Python path in entry script
- Simplified deployment.py to remove dependency on deleted core.deployment
- Fixed import paths in all command files
- Recreated virtual environment with new structure

BENEFITS:
- Eliminated 'box in a box' nesting
- Simpler directory structure
- Direct access to all modules
- Cleaner imports
- Easier maintenance and development
- CLI works with both 'python main.py' and 'aitbc' commands
2026-03-26 09:12:02 +01:00

115 lines
4.4 KiB
Python
Executable File

"""Configuration management for AITBC CLI"""
import os
import yaml
from pathlib import Path
from typing import Optional
from dataclasses import dataclass, field
from dotenv import load_dotenv
@dataclass
class Config:
"""Configuration object for AITBC CLI"""
coordinator_url: str = "http://127.0.0.1:8000"
api_key: Optional[str] = None
role: Optional[str] = None # admin, client, miner, etc.
config_dir: Path = field(default_factory=lambda: Path.home() / ".aitbc")
config_file: Optional[str] = None
blockchain_rpc_url: str = "http://127.0.0.1:8006"
wallet_url: str = "http://127.0.0.1:8002"
def _validate_localhost_urls(self):
"""Validate that all service URLs point to localhost"""
localhost_prefixes = ["http://localhost:", "http://127.0.0.1:", "https://localhost:", "https://127.0.0.1:"]
urls_to_check = [
("coordinator_url", self.coordinator_url),
("blockchain_rpc_url", self.blockchain_rpc_url),
("wallet_url", self.wallet_url)
]
for url_name, url in urls_to_check:
if not any(url.startswith(prefix) for prefix in localhost_prefixes):
# Force to localhost if not already
if url_name == "coordinator_url":
self.coordinator_url = "http://localhost:8000"
elif url_name == "blockchain_rpc_url":
self.blockchain_rpc_url = "http://localhost:8006"
elif url_name == "wallet_url":
self.wallet_url = "http://localhost:8002"
def __post_init__(self):
"""Initialize configuration"""
# Load environment variables
load_dotenv()
# Set default config file based on role if not specified
if not self.config_file:
if self.role:
self.config_file = str(self.config_dir / f"{self.role}-config.yaml")
else:
self.config_file = str(self.config_dir / "config.yaml")
# Load config from file if it exists
self.load_from_file()
# Override with environment variables
if os.getenv("AITBC_URL"):
self.coordinator_url = os.getenv("AITBC_URL")
if os.getenv("AITBC_API_KEY"):
self.api_key = os.getenv("AITBC_API_KEY")
if os.getenv("AITBC_ROLE"):
self.role = os.getenv("AITBC_ROLE")
if os.getenv("AITBC_BLOCKCHAIN_RPC_URL"):
self.blockchain_rpc_url = os.getenv("AITBC_BLOCKCHAIN_RPC_URL")
if os.getenv("AITBC_WALLET_URL"):
self.wallet_url = os.getenv("AITBC_WALLET_URL")
# Validate and enforce localhost URLs
self._validate_localhost_urls()
def load_from_file(self):
"""Load configuration from YAML file"""
if self.config_file and Path(self.config_file).exists():
try:
with open(self.config_file, 'r') as f:
data = yaml.safe_load(f) or {}
self.coordinator_url = data.get('coordinator_url', self.coordinator_url)
self.api_key = data.get('api_key', self.api_key)
self.role = data.get('role', self.role)
self.blockchain_rpc_url = data.get('blockchain_rpc_url', self.blockchain_rpc_url)
self.wallet_url = data.get('wallet_url', self.wallet_url)
except Exception as e:
print(f"Warning: Could not load config file: {e}")
# Validate and enforce localhost URLs after file loading
self._validate_localhost_urls()
def save_to_file(self):
"""Save configuration to YAML file"""
if not self.config_file:
return
# Ensure config directory exists
Path(self.config_file).parent.mkdir(parents=True, exist_ok=True)
data = {
'coordinator_url': self.coordinator_url,
'api_key': self.api_key,
'blockchain_rpc_url': self.blockchain_rpc_url,
'wallet_url': self.wallet_url
}
if self.role:
data['role'] = self.role
with open(self.config_file, 'w') as f:
yaml.dump(data, f, default_flow_style=False)
def get_config(config_file: Optional[str] = None, role: Optional[str] = None) -> Config:
"""Get configuration instance with optional role"""
return Config(config_file=config_file, role=role)