fix: replace all print() with click.echo() or logger in CLI production code

- 55 CLI files: handlers/, aitbc_cli/commands/, cli/core/, cli/utils/, top-level scripts
- Click-based files: print() -> click.echo()
- Library modules: print() -> logger.info/error/warning
- Fixed pre-existing indentation bugs in monitor.py dashboard function
- Fixed bare print() -> logger.info('') in chain_manager.py
- 0 remaining print() in production CLI code
- All files compile cleanly
This commit is contained in:
aitbc
2026-05-25 13:53:49 +02:00
parent b9b70923d5
commit a7b6e39cdf
126 changed files with 20949 additions and 1071 deletions

View File

@@ -4,6 +4,9 @@ import json
import sys
from aitbc import AITBCHTTPClient, NetworkError
import logging
logger = logging.getLogger(__name__)
def handle_account_get(args, default_rpc_url, output_format):
@@ -12,10 +15,10 @@ def handle_account_get(args, default_rpc_url, output_format):
chain_id = getattr(args, "chain_id", None)
if not args.address:
print("Error: --address is required")
logger.error("Error: --address is required")
sys.exit(1)
print(f"Getting account {args.address} from {rpc_url}...")
logger.info(f"Getting account {args.address} from {rpc_url}...")
try:
params = {}
if chain_id:
@@ -24,12 +27,12 @@ def handle_account_get(args, default_rpc_url, output_format):
http_client = AITBCHTTPClient(base_url=rpc_url, timeout=10)
account = http_client.get(f"/rpc/account/{args.address}", params=params)
if output_format(args) == "json":
print(json.dumps(account, indent=2))
logger.info(json.dumps(account, indent=2))
else:
render_mapping(f"Account {args.address}:", account)
except NetworkError as e:
print(f"Error getting account: {e}")
logger.error(f"Error getting account: {e}")
sys.exit(1)
except Exception as e:
print(f"Error getting account: {e}")
logger.error(f"Error getting account: {e}")
sys.exit(1)

View File

@@ -2,6 +2,7 @@
import json
import sys
import click
import requests
@@ -17,7 +18,7 @@ def handle_ai_submit(args, default_rpc_url, default_coordinator_url, first, read
payment = first(getattr(args, "payment_arg", None), getattr(args, "payment", None))
if not wallet or not model or not prompt:
print("Error: --wallet, --type, and --prompt are required")
click.echo("Error: --wallet, --type, and --prompt are required")
sys.exit(1)
# Get sender address (no password needed for Agent Coordinator)
@@ -39,19 +40,19 @@ def handle_ai_submit(args, default_rpc_url, default_coordinator_url, first, read
}
}
print(f"Submitting AI job to {coordinator_url}...")
click.echo(f"Submitting AI job to {coordinator_url}...")
try:
response = requests.post(f"{coordinator_url}/tasks/submit", json=job_data, timeout=30)
if response.status_code in (200, 201):
result = response.json()
print("AI job submitted successfully")
click.echo("AI job submitted successfully")
render_mapping("Job:", result)
else:
print(f"Job submission failed: {response.status_code}")
print(f"Error: {response.text}")
click.echo(f"Job submission failed: {response.status_code}")
click.echo(f"Error: {response.text}")
sys.exit(1)
except Exception as e:
print(f"Error submitting AI job: {e}")
click.echo(f"Error submitting AI job: {e}")
sys.exit(1)
@@ -60,7 +61,7 @@ def handle_ai_jobs(args, default_rpc_url, default_coordinator_url, output_format
coordinator_url = args.coordinator_url or default_coordinator_url
chain_id = getattr(args, "chain_id", None)
print(f"Getting AI jobs from {coordinator_url}...")
click.echo(f"Getting AI jobs from {coordinator_url}...")
try:
params = {}
if chain_id:
@@ -72,17 +73,17 @@ def handle_ai_jobs(args, default_rpc_url, default_coordinator_url, output_format
if response.status_code == 200:
jobs = response.json()
if output_format(args) == "json":
print(json.dumps(jobs, indent=2))
click.echo(json.dumps(jobs, indent=2))
else:
print("AI jobs:")
click.echo("AI jobs:")
if isinstance(jobs, list):
for job in jobs:
print(f" Job ID: {job.get('job_id', 'N/A')}, Model: {job.get('model', 'N/A')}, Status: {job.get('status', 'N/A')}")
click.echo(f" Job ID: {job.get('job_id', 'N/A')}, Model: {job.get('model', 'N/A')}, Status: {job.get('status', 'N/A')}")
else:
print(f" {jobs}")
click.echo(f" {jobs}")
else:
print(f"Query failed: {response.status_code}")
print(f"Error: {response.text}")
click.echo(f"Query failed: {response.status_code}")
click.echo(f"Error: {response.text}")
# Return stub data instead of failing
stub_jobs = {
"jobs": [
@@ -92,7 +93,7 @@ def handle_ai_jobs(args, default_rpc_url, default_coordinator_url, output_format
}
render_mapping("AI Jobs (stub):", stub_jobs)
except Exception as e:
print(f"Error querying AI jobs: {e}")
click.echo(f"Error querying AI jobs: {e}")
# Return stub data instead of failing
stub_jobs = {
"jobs": [
@@ -111,10 +112,10 @@ def handle_ai_job(args, default_rpc_url, output_format, render_mapping, first):
job_id = first(getattr(args, "job_id_arg", None), getattr(args, "job_id", None))
if not job_id:
print("Error: --job-id is required")
click.echo("Error: --job-id is required")
sys.exit(1)
print(f"Getting AI job {job_id} from {rpc_url}...")
click.echo(f"Getting AI job {job_id} from {rpc_url}...")
try:
params = {}
if chain_id:
@@ -124,15 +125,15 @@ def handle_ai_job(args, default_rpc_url, output_format, render_mapping, first):
if response.status_code == 200:
job = response.json()
if output_format(args) == "json":
print(json.dumps(job, indent=2))
click.echo(json.dumps(job, indent=2))
else:
render_mapping(f"Job {job_id}:", job)
else:
print(f"Query failed: {response.status_code}")
print(f"Error: {response.text}")
click.echo(f"Query failed: {response.status_code}")
click.echo(f"Error: {response.text}")
sys.exit(1)
except Exception as e:
print(f"Error getting AI job: {e}")
click.echo(f"Error getting AI job: {e}")
sys.exit(1)
@@ -145,7 +146,7 @@ def handle_ai_cancel(args, default_rpc_url, read_password, render_mapping, first
wallet = getattr(args, "wallet", None)
if not job_id or not wallet:
print("Error: --job-id and --wallet are required")
click.echo("Error: --job-id and --wallet are required")
sys.exit(1)
# Get auth headers
@@ -160,19 +161,19 @@ def handle_ai_cancel(args, default_rpc_url, read_password, render_mapping, first
if chain_id:
cancel_data["chain_id"] = chain_id
print(f"Cancelling AI job {job_id} on {rpc_url}...")
click.echo(f"Cancelling AI job {job_id} on {rpc_url}...")
try:
response = requests.post(f"{rpc_url}/rpc/ai/job/{job_id}/cancel", json=cancel_data, headers=headers, timeout=30)
if response.status_code == 200:
result = response.json()
print("AI job cancelled successfully")
click.echo("AI job cancelled successfully")
render_mapping("Cancel result:", result)
else:
print(f"Cancellation failed: {response.status_code}")
print(f"Error: {response.text}")
click.echo(f"Cancellation failed: {response.status_code}")
click.echo(f"Error: {response.text}")
sys.exit(1)
except Exception as e:
print(f"Error cancelling AI job: {e}")
click.echo(f"Error cancelling AI job: {e}")
sys.exit(1)
@@ -181,7 +182,7 @@ def handle_ai_stats(args, default_rpc_url, output_format, render_mapping):
rpc_url = args.rpc_url or default_rpc_url
chain_id = getattr(args, "chain_id", None)
print(f"Getting AI service statistics from {rpc_url}...")
click.echo(f"Getting AI service statistics from {rpc_url}...")
try:
params = {}
if chain_id:
@@ -191,15 +192,15 @@ def handle_ai_stats(args, default_rpc_url, output_format, render_mapping):
if response.status_code == 200:
stats = response.json()
if output_format(args) == "json":
print(json.dumps(stats, indent=2))
click.echo(json.dumps(stats, indent=2))
else:
render_mapping("AI service statistics:", stats)
else:
print(f"Query failed: {response.status_code}")
print(f"Error: {response.text}")
click.echo(f"Query failed: {response.status_code}")
click.echo(f"Error: {response.text}")
sys.exit(1)
except Exception as e:
print(f"Error getting AI stats: {e}")
click.echo(f"Error getting AI stats: {e}")
sys.exit(1)
@@ -207,21 +208,21 @@ def handle_ai_distribution_stats(args, default_coordinator_url, output_format, r
"""Handle task distribution statistics query from agent coordinator."""
coordinator_url = getattr(args, 'coordinator_url', None) or default_coordinator_url
print(f"Getting task distribution statistics from {coordinator_url}...")
click.echo(f"Getting task distribution statistics from {coordinator_url}...")
try:
response = requests.get(f"{coordinator_url}/tasks/status", timeout=10)
if response.status_code == 200:
stats = response.json()
if output_format(args) == "json":
print(json.dumps(stats, indent=2))
click.echo(json.dumps(stats, indent=2))
else:
render_mapping("Task distribution statistics:", stats)
else:
print(f"Query failed: {response.status_code}")
print(f"Error: {response.text}")
click.echo(f"Query failed: {response.status_code}")
click.echo(f"Error: {response.text}")
sys.exit(1)
except Exception as e:
print(f"Error getting distribution stats: {e}")
click.echo(f"Error getting distribution stats: {e}")
sys.exit(1)
@@ -270,20 +271,20 @@ def handle_ai_status(args, default_coordinator_url, default_rpc_url, output_form
}
# Check Agent Coordinator health
print(f"Checking Agent Coordinator at {coordinator_url}...")
click.echo(f"Checking Agent Coordinator at {coordinator_url}...")
try:
response = requests.get(f"{coordinator_url}/health", timeout=10)
if response.status_code == 200:
coordinator_data = response.json()
combined_status["agent_coordinator"] = coordinator_data
print(f" Agent Coordinator: {coordinator_data.get('status', 'unknown')} (v{coordinator_data.get('version', 'N/A')})")
click.echo(f" Agent Coordinator: {coordinator_data.get('status', 'unknown')} (v{coordinator_data.get('version', 'N/A')})")
else:
print(f" Agent Coordinator: Failed (HTTP {response.status_code})")
click.echo(f" Agent Coordinator: Failed (HTTP {response.status_code})")
except Exception as e:
print(f" Agent Coordinator: Error - {e}")
click.echo(f" Agent Coordinator: Error - {e}")
# Check Blockchain AI stats
print(f"Checking Blockchain AI stats at {rpc_url}...")
click.echo(f"Checking Blockchain AI stats at {rpc_url}...")
try:
params = {}
if hasattr(args, "chain_id") and args.chain_id:
@@ -292,11 +293,11 @@ def handle_ai_status(args, default_coordinator_url, default_rpc_url, output_form
if response.status_code == 200:
stats_data = response.json()
combined_status["blockchain_ai"] = stats_data
print(f" Blockchain AI Stats: Available")
click.echo(f" Blockchain AI Stats: Available")
else:
print(f" Blockchain AI Stats: Not available (HTTP {response.status_code})")
click.echo(f" Blockchain AI Stats: Not available (HTTP {response.status_code})")
except Exception as e:
print(f" Blockchain AI Stats: Error - {e}")
click.echo(f" Blockchain AI Stats: Error - {e}")
# Calculate overall status
if combined_status["agent_coordinator"].get("status") == "healthy" and combined_status["blockchain_ai"].get("status") != "unavailable":
@@ -306,17 +307,17 @@ def handle_ai_status(args, default_coordinator_url, default_rpc_url, output_form
# Render output
if output_format(args) == "json":
print(json.dumps(combined_status, indent=2))
click.echo(json.dumps(combined_status, indent=2))
else:
print(f"\nOverall Status: {combined_status['overall']}")
click.echo(f"\nOverall Status: {combined_status['overall']}")
if combined_status["agent_coordinator"].get("status") == "healthy":
print(" Agent Coordinator: Operational")
click.echo(" Agent Coordinator: Operational")
elif combined_status["agent_coordinator"].get("status") != "unavailable":
print(f" Agent Coordinator: {combined_status['agent_coordinator'].get('status')}")
click.echo(f" Agent Coordinator: {combined_status['agent_coordinator'].get('status')}")
else:
print(" Agent Coordinator: Unavailable")
click.echo(" Agent Coordinator: Unavailable")
if combined_status["blockchain_ai"].get("status") != "unavailable":
print(" Blockchain AI: Operational")
click.echo(" Blockchain AI: Operational")
else:
print(" Blockchain AI: Unavailable")
click.echo(" Blockchain AI: Unavailable")

View File

@@ -1,6 +1,9 @@
"""Analytics command handlers for AITBC CLI."""
import json
import logging
logger = logging.getLogger(__name__)
def handle_analytics_metrics(args, default_rpc_url, output_format, render_mapping):
@@ -16,7 +19,7 @@ def handle_analytics_metrics(args, default_rpc_url, output_format, render_mappin
}
if output_format(args) == "json":
print(json.dumps(metrics_data, indent=2))
logger.info(json.dumps(metrics_data, indent=2))
else:
render_mapping("Analytics Metrics:", metrics_data)
@@ -36,7 +39,7 @@ def handle_analytics_report(args, default_rpc_url, output_format, render_mapping
}
if output_format(args) == "json":
print(json.dumps(report_data, indent=2))
logger.info(json.dumps(report_data, indent=2))
else:
render_mapping("Analytics Report:", report_data)
@@ -52,7 +55,7 @@ def handle_analytics_export(args, default_rpc_url, render_mapping):
"timestamp": __import__('datetime').datetime.now().isoformat()
}
print(f"Analytics exported as {format_type}")
logger.info(f"Analytics exported as {format_type}")
render_mapping("Export:", export_data)
@@ -68,7 +71,7 @@ def handle_analytics_predict(args, default_rpc_url, render_mapping):
"timestamp": __import__('datetime').datetime.now().isoformat()
}
print(f"Prediction using {model} model for {target}")
logger.info(f"Prediction using {model} model for {target}")
render_mapping("Prediction:", prediction_data)
@@ -84,5 +87,5 @@ def handle_analytics_optimize(args, default_rpc_url, render_mapping):
"timestamp": __import__('datetime').datetime.now().isoformat()
}
print(f"Analytics optimization applied for {target}")
logger.info(f"Analytics optimization applied for {target}")
render_mapping("Optimization:", optimization_data)

View File

@@ -5,6 +5,9 @@ import os
import sys
import requests
import logging
logger = logging.getLogger(__name__)
def handle_blockchain_info(args, get_chain_info, render_mapping):
@@ -18,19 +21,16 @@ def handle_blockchain_info(args, get_chain_info, render_mapping):
def handle_blockchain_height(args, get_chain_info):
"""Handle blockchain height command."""
chain_info = get_chain_info(rpc_url=args.rpc_url)
print(chain_info.get("height", 0) if chain_info else 0)
logger.info(chain_info.get("height", 0) if chain_info else 0)
def handle_blockchain_block(args, default_rpc_url):
"""Handle blockchain block command."""
if args.number is None:
print("Error: block number is required")
logger.error("Error: block number is required")
sys.exit(1)
rpc_url = args.rpc_url or os.getenv("NODE_URL", default_rpc_url)
chain_id = getattr(args, 'chain_id', None) or os.getenv('CHAIN_ID', 'ait-mainnet')
print(f"Querying block #{args.number} from {rpc_url} (chain: {chain_id})...")
logger.info(f"Querying block #{args.number} from {rpc_url} (chain: {chain_id})...")
try:
params = {}
if chain_id:
@@ -38,40 +38,39 @@ def handle_blockchain_block(args, default_rpc_url):
response = requests.get(f"{rpc_url}/rpc/blocks/{args.number}", params=params, timeout=10)
if response.status_code == 200:
data = response.json()
print(f"Block #{args.number}:")
print(f" Hash: {data.get('hash', 'N/A')}")
print(f" Timestamp: {data.get('timestamp', 'N/A')}")
print(f" Transactions: {data.get('tx_count', len(data.get('transactions', [])))}")
print(f" Miner: {data.get('proposer', 'N/A')}")
logger.info(f"Block #{args.number}:")
logger.info(f" Hash: {data.get('hash', 'N/A')}")
logger.info(f" Timestamp: {data.get('timestamp', 'N/A')}")
logger.info(f" Transactions: {data.get('tx_count', len(data.get('transactions', [])))}")
logger.info(f" Miner: {data.get('proposer', 'N/A')}")
else:
print(f"Failed to get block: {response.status_code}")
logger.error(f"Failed to get block: {response.status_code}")
sys.exit(1)
except Exception as e:
print(f"Error getting block: {e}")
logger.error(f"Error getting block: {e}")
sys.exit(1)
def handle_blockchain_init(args, default_rpc_url):
"""Handle blockchain init command."""
rpc_url = args.rpc_url or os.getenv("NODE_URL", default_rpc_url)
print(f"Checking blockchain status on {rpc_url}...")
logger.info(f"Checking blockchain status on {rpc_url}...")
try:
# Check if blockchain is already initialized by checking for genesis block (block 0)
response = requests.get(f"{rpc_url}/rpc/blocks/0", timeout=10)
if response.status_code == 200:
data = response.json()
print("Blockchain already initialized")
print(f"Genesis block hash: {data.get('hash', 'N/A')}")
print(f"Block number: {data.get('number', 0)}")
logger.info("Blockchain already initialized")
logger.info(f"Genesis block hash: {data.get('hash', 'N/A')}")
logger.info(f"Block number: {data.get('number', 0)}")
if args.force:
print("Force flag ignored - blockchain already initialized")
logger.info("Force flag ignored - blockchain already initialized")
else:
print(f"Blockchain not initialized or endpoint unavailable: {response.status_code}")
logger.info(f"Blockchain not initialized or endpoint unavailable: {response.status_code}")
sys.exit(1)
except Exception as e:
print(f"Error checking blockchain status: {e}")
print("Note: Blockchain may not be initialized or RPC endpoint unavailable")
logger.error(f"Error checking blockchain status: {e}")
logger.info("Note: Blockchain may not be initialized or RPC endpoint unavailable")
sys.exit(1)
@@ -80,43 +79,43 @@ def handle_blockchain_genesis(args, default_rpc_url):
rpc_url = args.rpc_url or os.getenv("NODE_URL", default_rpc_url)
if args.create:
print(f"Creating genesis block on {rpc_url}...")
logger.info(f"Creating genesis block on {rpc_url}...")
try:
# Check if genesis block already exists
response = requests.get(f"{rpc_url}/rpc/blocks/0", timeout=10)
if response.status_code == 200:
data = response.json()
print("Genesis block already exists")
print(f"Block hash: {data.get('hash', 'N/A')}")
print(f"Block number: {data.get('number', 0)}")
print(f"Timestamp: {data.get('timestamp', 'N/A')}")
print("Skipping genesis block creation")
logger.info("Genesis block already exists")
logger.info(f"Block hash: {data.get('hash', 'N/A')}")
logger.info(f"Block number: {data.get('number', 0)}")
logger.info(f"Timestamp: {data.get('timestamp', 'N/A')}")
logger.info("Skipping genesis block creation")
return
else:
print(f"Cannot create genesis block - endpoint not available: {response.status_code}")
print("Note: Genesis block creation may not be supported in current RPC implementation")
logger.info(f"Cannot create genesis block - endpoint not available: {response.status_code}")
logger.info("Note: Genesis block creation may not be supported in current RPC implementation")
sys.exit(1)
except Exception as e:
print(f"Error checking genesis block: {e}")
print("Note: Genesis block creation may not be supported in current RPC implementation")
logger.error(f"Error checking genesis block: {e}")
logger.info("Note: Genesis block creation may not be supported in current RPC implementation")
sys.exit(1)
else:
print(f"Inspecting genesis block on {rpc_url}...")
logger.info(f"Inspecting genesis block on {rpc_url}...")
try:
response = requests.get(f"{rpc_url}/rpc/blocks/0", timeout=10)
if response.status_code == 200:
data = response.json()
print("Genesis block information:")
print(f" Hash: {data.get('hash', 'N/A')}")
print(f" Number: {data.get('number', 0)}")
print(f" Timestamp: {data.get('timestamp', 'N/A')}")
print(f" Miner: {data.get('miner', 'N/A')}")
print(f" Reward: {data.get('reward', 'N/A')} AIT")
logger.info("Genesis block information:")
logger.info(f" Hash: {data.get('hash', 'N/A')}")
logger.info(f" Number: {data.get('number', 0)}")
logger.info(f" Timestamp: {data.get('timestamp', 'N/A')}")
logger.info(f" Miner: {data.get('miner', 'N/A')}")
logger.info(f" Reward: {data.get('reward', 'N/A')} AIT")
else:
print(f"Failed to get genesis block: {response.status_code}")
logger.error(f"Failed to get genesis block: {response.status_code}")
sys.exit(1)
except Exception as e:
print(f"Error inspecting genesis block: {e}")
logger.error(f"Error inspecting genesis block: {e}")
sys.exit(1)
@@ -132,26 +131,26 @@ def handle_blockchain_import(args, default_rpc_url, render_mapping):
elif args.json:
block_data = json.loads(args.json)
else:
print("Error: --file or --json is required")
logger.error("Error: --file or --json is required")
sys.exit(1)
# Add chain_id if provided
if chain_id:
block_data["chain_id"] = chain_id
print(f"Importing block to {rpc_url}...")
logger.info(f"Importing block to {rpc_url}...")
try:
response = requests.post(f"{rpc_url}/rpc/importBlock", json=block_data, timeout=30)
if response.status_code == 200:
result = response.json()
print("Block imported successfully")
logger.info("Block imported successfully")
render_mapping("Import result:", result)
else:
print(f"Import failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Import failed: {response.status_code}")
logger.error(f"Error: {response.text}")
sys.exit(1)
except Exception as e:
print(f"Error importing block: {e}")
logger.error(f"Error importing block: {e}")
sys.exit(1)
@@ -160,7 +159,7 @@ def handle_blockchain_export(args, default_rpc_url):
rpc_url = args.rpc_url or default_rpc_url
chain_id = getattr(args, "chain_id", None)
print(f"Exporting chain from {rpc_url}...")
logger.info(f"Exporting chain from {rpc_url}...")
try:
params = {}
if chain_id:
@@ -172,15 +171,15 @@ def handle_blockchain_export(args, default_rpc_url):
if args.output:
with open(args.output, "w") as f:
json.dump(chain_data, f, indent=2)
print(f"Chain exported to {args.output}")
logger.info(f"Chain exported to {args.output}")
else:
print(json.dumps(chain_data, indent=2))
logger.info(json.dumps(chain_data, indent=2))
else:
print(f"Export failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Export failed: {response.status_code}")
logger.error(f"Error: {response.text}")
sys.exit(1)
except Exception as e:
print(f"Error exporting chain: {e}")
logger.error(f"Error exporting chain: {e}")
sys.exit(1)
@@ -189,25 +188,25 @@ def handle_blockchain_import_chain(args, default_rpc_url, render_mapping):
rpc_url = args.rpc_url or default_rpc_url
if not args.file:
print("Error: --file is required")
logger.error("Error: --file is required")
sys.exit(1)
with open(args.file) as f:
chain_data = json.load(f)
print(f"Importing chain state to {rpc_url}...")
logger.info(f"Importing chain state to {rpc_url}...")
try:
response = requests.post(f"{rpc_url}/rpc/import-chain", json=chain_data, timeout=120)
if response.status_code == 200:
result = response.json()
print("Chain state imported successfully")
logger.info("Chain state imported successfully")
render_mapping("Import result:", result)
else:
print(f"Import failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Import failed: {response.status_code}")
logger.error(f"Error: {response.text}")
sys.exit(1)
except Exception as e:
print(f"Error importing chain state: {e}")
logger.error(f"Error importing chain state: {e}")
sys.exit(1)
@@ -224,26 +223,26 @@ def handle_blockchain_blocks_range(args, default_rpc_url, output_format):
if chain_id:
params["chain_id"] = chain_id
print(f"Querying blocks range from {rpc_url}...")
logger.info(f"Querying blocks range from {rpc_url}...")
try:
response = requests.get(f"{rpc_url}/rpc/blocks-range", params=params, timeout=30)
if response.status_code == 200:
blocks_data = response.json()
if output_format(args) == "json":
print(json.dumps(blocks_data, indent=2))
logger.info(json.dumps(blocks_data, indent=2))
else:
print(f"Blocks range: {args.start or 'head'} to {args.end or 'limit ' + str(args.limit)}")
logger.info(f"Blocks range: {args.start or 'head'} to {args.end or 'limit ' + str(args.limit)}")
if isinstance(blocks_data, list):
for block in blocks_data:
print(f" - Block #{block.get('height', 'N/A')}: {block.get('hash', 'N/A')}")
logger.info(f" - Block #{block.get('height', 'N/A')}: {block.get('hash', 'N/A')}")
else:
print(json.dumps(blocks_data, indent=2))
logger.info(json.dumps(blocks_data, indent=2))
else:
print(f"Query failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Query failed: {response.status_code}")
logger.error(f"Error: {response.text}")
sys.exit(1)
except Exception as e:
print(f"Error querying blocks range: {e}")
logger.error(f"Error querying blocks range: {e}")
sys.exit(1)
@@ -252,7 +251,7 @@ def handle_blockchain_transactions(args, default_rpc_url):
rpc_url = args.rpc_url or default_rpc_url
chain_id = getattr(args, "chain_id", None)
print(f"Querying transactions from {rpc_url}...")
logger.info(f"Querying transactions from {rpc_url}...")
try:
params = {}
if args.address:
@@ -268,20 +267,20 @@ def handle_blockchain_transactions(args, default_rpc_url):
if response.status_code == 200:
transactions = response.json()
if isinstance(transactions, list):
print(f"Transactions: {len(transactions)} found")
logger.info(f"Transactions: {len(transactions)} found")
for tx in transactions[:args.limit]:
print(f" - Hash: {tx.get('hash', 'N/A')}")
print(f" From: {tx.get('from', 'N/A')}")
print(f" To: {tx.get('to', 'N/A')}")
print(f" Amount: {tx.get('value', 0)} AIT")
logger.info(f" - Hash: {tx.get('hash', 'N/A')}")
logger.info(f" From: {tx.get('from', 'N/A')}")
logger.info(f" To: {tx.get('to', 'N/A')}")
logger.info(f" Amount: {tx.get('value', 0)} AIT")
else:
print(json.dumps(transactions, indent=2))
logger.info(json.dumps(transactions, indent=2))
else:
print(f"Query failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Query failed: {response.status_code}")
logger.error(f"Error: {response.text}")
sys.exit(1)
except Exception as e:
print(f"Error querying transactions: {e}")
logger.error(f"Error querying transactions: {e}")
sys.exit(1)
@@ -290,7 +289,7 @@ def handle_blockchain_mempool(args, default_rpc_url):
rpc_url = args.rpc_url or default_rpc_url
chain_id = getattr(args, "chain_id", None)
print(f"Getting pending transactions from {rpc_url}...")
logger.info(f"Getting pending transactions from {rpc_url}...")
try:
params = {}
if chain_id:
@@ -300,17 +299,17 @@ def handle_blockchain_mempool(args, default_rpc_url):
if response.status_code == 200:
mempool = response.json()
if isinstance(mempool, list):
print(f"Pending transactions: {len(mempool)}")
logger.info(f"Pending transactions: {len(mempool)}")
for tx in mempool:
print(f" - Hash: {tx.get('hash', 'N/A')}")
print(f" From: {tx.get('from', 'N/A')}")
print(f" Amount: {tx.get('value', 0)} AIT")
logger.info(f" - Hash: {tx.get('hash', 'N/A')}")
logger.info(f" From: {tx.get('from', 'N/A')}")
logger.info(f" Amount: {tx.get('value', 0)} AIT")
else:
print(json.dumps(mempool, indent=2))
logger.info(json.dumps(mempool, indent=2))
else:
print(f"Query failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Query failed: {response.status_code}")
logger.error(f"Error: {response.text}")
sys.exit(1)
except Exception as e:
print(f"Error getting mempool: {e}")
logger.error(f"Error getting mempool: {e}")
sys.exit(1)

View File

@@ -3,6 +3,9 @@
import subprocess
from aitbc import AITBCHTTPClient, NetworkError
import logging
logger = logging.getLogger(__name__)
def handle_bridge_health(args):
@@ -12,24 +15,22 @@ def handle_bridge_health(args):
config = get_bridge_config()
if args.test_mode:
print("🏥 Blockchain Event Bridge Health (test mode):")
print("✅ Status: healthy")
print("📦 Service: blockchain-event-bridge")
logger.info("🏥 Blockchain Event Bridge Health (test mode):")
logger.info("✅ Status: healthy")
logger.info("📦 Service: blockchain-event-bridge")
return
bridge_url = getattr(config, "bridge_url", "http://localhost:8204")
http_client = AITBCHTTPClient(base_url=bridge_url, timeout=10)
health = http_client.get("/health")
print("🏥 Blockchain Event Bridge Health:")
logger.info("🏥 Blockchain Event Bridge Health:")
for key, value in health.items():
print(f" {key}: {value}")
logger.info(f" {key}: {value}")
except NetworkError as e:
print(f"❌ Health check failed: {e}")
logger.error(f"❌ Health check failed: {e}")
except Exception as e:
print(f"❌ Error checking health: {e}")
logger.error(f"❌ Error checking health: {e}")
def handle_bridge_metrics(args):
"""Get Prometheus metrics from blockchain event bridge service."""
try:
@@ -37,23 +38,21 @@ def handle_bridge_metrics(args):
config = get_bridge_config()
if args.test_mode:
print("📊 Prometheus Metrics (test mode):")
print(" bridge_events_total: 103691")
print(" bridge_events_processed_total: 103691")
logger.info("📊 Prometheus Metrics (test mode):")
logger.info(" bridge_events_total: 103691")
logger.info(" bridge_events_processed_total: 103691")
return
bridge_url = getattr(config, "bridge_url", "http://localhost:8204")
http_client = AITBCHTTPClient(base_url=bridge_url, timeout=10)
metrics = http_client.get("/metrics", return_response=True)
print("📊 Prometheus Metrics:")
print(metrics.text)
logger.info("📊 Prometheus Metrics:")
logger.info(metrics.text)
except NetworkError as e:
print(f"❌ Failed to get metrics: {e}")
logger.error(f"❌ Failed to get metrics: {e}")
except Exception as e:
print(f"❌ Error getting metrics: {e}")
logger.error(f"❌ Error getting metrics: {e}")
def handle_bridge_status(args):
"""Get detailed status of blockchain event bridge service."""
try:
@@ -61,24 +60,22 @@ def handle_bridge_status(args):
config = get_bridge_config()
if args.test_mode:
print("📊 Blockchain Event Bridge Status (test mode):")
print("✅ Status: running")
print("🔔 Subscriptions: blocks, transactions, contract_events")
logger.info("📊 Blockchain Event Bridge Status (test mode):")
logger.info("✅ Status: running")
logger.info("🔔 Subscriptions: blocks, transactions, contract_events")
return
bridge_url = getattr(config, "bridge_url", "http://localhost:8204")
http_client = AITBCHTTPClient(base_url=bridge_url, timeout=10)
status = http_client.get("/")
print("📊 Blockchain Event Bridge Status:")
logger.info("📊 Blockchain Event Bridge Status:")
for key, value in status.items():
print(f" {key}: {value}")
logger.info(f" {key}: {value}")
except NetworkError as e:
print(f"❌ Failed to get status: {e}")
logger.error(f"❌ Failed to get status: {e}")
except Exception as e:
print(f"❌ Error getting status: {e}")
logger.error(f"❌ Error getting status: {e}")
def handle_bridge_config(args):
"""Show current configuration of blockchain event bridge service."""
try:
@@ -86,30 +83,28 @@ def handle_bridge_config(args):
config = get_bridge_config()
if args.test_mode:
print("⚙️ Blockchain Event Bridge Configuration (test mode):")
print("🔗 Blockchain RPC URL: http://localhost:8006")
print("💬 Gossip Backend: redis")
logger.info("⚙️ Blockchain Event Bridge Configuration (test mode):")
logger.info("🔗 Blockchain RPC URL: http://localhost:8006")
logger.info("💬 Gossip Backend: redis")
return
bridge_url = getattr(config, "bridge_url", "http://localhost:8204")
http_client = AITBCHTTPClient(base_url=bridge_url, timeout=10)
service_config = http_client.get("/config")
print("⚙️ Blockchain Event Bridge Configuration:")
logger.info("⚙️ Blockchain Event Bridge Configuration:")
for key, value in service_config.items():
print(f" {key}: {value}")
logger.info(f" {key}: {value}")
except NetworkError as e:
print(f"❌ Failed to get config: {e}")
logger.error(f"❌ Failed to get config: {e}")
except Exception as e:
print(f"❌ Error getting config: {e}")
logger.error(f"❌ Error getting config: {e}")
def handle_bridge_restart(args):
"""Restart blockchain event bridge service (via systemd)."""
try:
if args.test_mode:
print("🔄 Blockchain event bridge restart triggered (test mode)")
print("✅ Restart completed successfully")
logger.info("🔄 Blockchain event bridge restart triggered (test mode)")
logger.info("✅ Restart completed successfully")
return
result = subprocess.run(
@@ -120,13 +115,13 @@ def handle_bridge_restart(args):
)
if result.returncode == 0:
print("🔄 Blockchain event bridge restart triggered")
print("✅ Restart completed successfully")
logger.info("🔄 Blockchain event bridge restart triggered")
logger.info("✅ Restart completed successfully")
else:
print(f"❌ Restart failed: {result.stderr}")
logger.error(f"❌ Restart failed: {result.stderr}")
except subprocess.TimeoutExpired:
print("❌ Restart timeout - service may be starting")
logger.info("❌ Restart timeout - service may be starting")
except FileNotFoundError:
print("❌ systemctl not found - cannot restart service")
logger.info("❌ systemctl not found - cannot restart service")
except Exception as e:
print(f"❌ Error restarting service: {e}")
logger.error(f"❌ Error restarting service: {e}")

View File

@@ -2,6 +2,9 @@
import requests
from typing import Optional, Dict, Any
import logging
logger = logging.getLogger(__name__)
def handle_contract_list(args, default_rpc_url: str):
@@ -16,21 +19,19 @@ def handle_contract_list(args, default_rpc_url: str):
if data.get("success") is not False:
contracts = data.get("contracts", [])
if contracts:
print(f"Deployed contracts ({len(contracts)}):")
logger.info(f"Deployed contracts ({len(contracts)}):")
for contract in contracts:
print(f" - Address: {contract.get('address', 'N/A')}")
print(f" Type: {contract.get('type', 'N/A')}")
print(f" Deployed: {contract.get('deployed_at', 'N/A')}")
logger.info(f" - Address: {contract.get('address', 'N/A')}")
logger.info(f" Type: {contract.get('type', 'N/A')}")
logger.info(f" Deployed: {contract.get('deployed_at', 'N/A')}")
else:
print("No contracts deployed")
logger.info("No contracts deployed")
else:
print(f"Error: {data.get('error', 'Unknown error')}")
logger.error(f"Error: {data.get('error', 'Unknown error')}")
else:
print(f"Error: RPC returned {response.status_code}")
logger.error(f"Error: RPC returned {response.status_code}")
except Exception as e:
print(f"Error listing contracts: {e}")
logger.error(f"Error listing contracts: {e}")
def handle_contract_deploy(args, default_rpc_url: str, read_password, render_mapping):
"""Handle contract deploy command"""
rpc_url = args.rpc_url if hasattr(args, 'rpc_url') and args.rpc_url else default_rpc_url
@@ -38,12 +39,12 @@ def handle_contract_deploy(args, default_rpc_url: str, read_password, render_map
contract_type = getattr(args, 'type', 'zk-verifier')
if not contract_name:
print("Error: Contract name is required (--name)")
logger.error("Error: Contract name is required (--name)")
return
password = read_password(args)
if not password:
print("Error: Wallet password is required (--password or --password-file)")
logger.error("Error: Wallet password is required (--password or --password-file)")
return
try:
@@ -64,13 +65,11 @@ def handle_contract_deploy(args, default_rpc_url: str, read_password, render_map
if data.get("success"):
render_mapping("Contract deployed successfully", data)
else:
print(f"Error: {data.get('error', 'Unknown error')}")
logger.error(f"Error: {data.get('error', 'Unknown error')}")
else:
print(f"Error: RPC returned {response.status_code}")
logger.error(f"Error: RPC returned {response.status_code}")
except Exception as e:
print(f"Error deploying contract: {e}")
logger.error(f"Error deploying contract: {e}")
def handle_contract_call(args, default_rpc_url: str, read_password):
"""Handle contract call command"""
rpc_url = args.rpc_url if hasattr(args, 'rpc_url') and args.rpc_url else default_rpc_url
@@ -78,11 +77,11 @@ def handle_contract_call(args, default_rpc_url: str, read_password):
method = getattr(args, 'method', None)
if not contract_address:
print("Error: Contract address is required (--address)")
logger.error("Error: Contract address is required (--address)")
return
if not method:
print("Error: Method name is required (--method)")
logger.error("Error: Method name is required (--method)")
return
password = read_password(args)
@@ -112,25 +111,23 @@ def handle_contract_call(args, default_rpc_url: str, read_password):
data = response.json()
if data.get("success"):
result = data.get("result")
print(f"Contract call result:")
print(f" Address: {contract_address}")
print(f" Method: {method}")
print(f" Result: {result}")
logger.info(f"Contract call result:")
logger.info(f" Address: {contract_address}")
logger.info(f" Method: {method}")
logger.info(f" Result: {result}")
else:
print(f"Error: {data.get('error', 'Unknown error')}")
logger.error(f"Error: {data.get('error', 'Unknown error')}")
else:
print(f"Error: RPC returned {response.status_code}")
logger.error(f"Error: RPC returned {response.status_code}")
except Exception as e:
print(f"Error calling contract: {e}")
logger.error(f"Error calling contract: {e}")
def handle_contract_verify(args, default_rpc_url: str, read_password):
"""Handle contract verify command (for ZK proofs)"""
rpc_url = args.rpc_url if hasattr(args, 'rpc_url') and args.rpc_url else default_rpc_url
contract_address = getattr(args, 'address', None)
if not contract_address:
print("Error: Contract address is required (--address)")
logger.error("Error: Contract address is required (--address)")
return
password = read_password(args)
@@ -162,14 +159,14 @@ def handle_contract_verify(args, default_rpc_url: str, read_password):
data = response.json()
if data.get("success"):
result = data.get("result")
print(f"Verification result:")
print(f" Address: {contract_address}")
print(f" Valid: {result.get('valid', False)}")
logger.info(f"Verification result:")
logger.info(f" Address: {contract_address}")
logger.info(f" Valid: {result.get('valid', False)}")
if result.get('receipt_hash'):
print(f" Receipt Hash: {result.get('receipt_hash')}")
logger.info(f" Receipt Hash: {result.get('receipt_hash')}")
else:
print(f"Error: {data.get('error', 'Unknown error')}")
logger.error(f"Error: {data.get('error', 'Unknown error')}")
else:
print(f"Error: RPC returned {response.status_code}")
logger.error(f"Error: RPC returned {response.status_code}")
except Exception as e:
print(f"Error verifying contract: {e}")
logger.error(f"Error verifying contract: {e}")

View File

@@ -4,6 +4,9 @@ import json
import os
import sys
import requests
import logging
logger = logging.getLogger(__name__)
def _marketplace_url(args, fallback=None):
@@ -38,7 +41,7 @@ def handle_market_listings(args, default_coordinator_url, output_format, render_
marketplace_url = _marketplace_url(args, default_coordinator_url)
chain_id = getattr(args, "chain_id", None)
print(f"Getting marketplace listings from {marketplace_url}...")
logger.info(f"Getting marketplace listings from {marketplace_url}...")
try:
params = {}
if chain_id:
@@ -48,26 +51,26 @@ def handle_market_listings(args, default_coordinator_url, output_format, render_
if response.status_code == 200:
listings = response.json()
if output_format(args) == "json":
print(json.dumps(listings, indent=2))
logger.info(json.dumps(listings, indent=2))
else:
print("Marketplace listings:")
logger.info("Marketplace listings:")
if isinstance(listings, list):
if listings:
for listing in listings:
print(f" - ID: {listing.get('id', 'N/A')}")
print(f" Model: {listing.get('model', 'N/A')}")
print(f" Price: {listing.get('price_per_hour', 0)} AIT/hour")
print(f" Status: {listing.get('status', 'N/A')}")
logger.info(f" - ID: {listing.get('id', 'N/A')}")
logger.info(f" Model: {listing.get('model', 'N/A')}")
logger.info(f" Price: {listing.get('price_per_hour', 0)} AIT/hour")
logger.info(f" Status: {listing.get('status', 'N/A')}")
else:
print(" No GPU listings found")
logger.info(" No GPU listings found")
else:
render_mapping("Listings:", listings)
else:
print(f"Query failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Query failed: {response.status_code}")
logger.error(f"Error: {response.text}")
return
except Exception as e:
print(f"Error getting listings: {e}")
logger.error(f"Error getting listings: {e}")
return
@@ -81,7 +84,7 @@ def handle_market_create(args, default_coordinator_url, read_password, render_ma
price = getattr(args, "price", None)
if not wallet or price is None:
print("Error: --wallet and --price are required")
logger.error("Error: --wallet and --price are required")
return
headers = _auth_headers(args, read_password)
@@ -96,19 +99,19 @@ def handle_market_create(args, default_coordinator_url, read_password, render_ma
if chain_id:
listing_data["chain_id"] = chain_id
print(f"Creating marketplace listing on {marketplace_url}...")
logger.info(f"Creating marketplace listing on {marketplace_url}...")
try:
response = requests.post(f"{marketplace_url}/v1/marketplace/offers", json=listing_data, headers=headers, timeout=30)
if response.status_code in (200, 201):
result = response.json()
print("Listing created successfully")
logger.info("Listing created successfully")
render_mapping("Listing:", result)
else:
print(f"Creation failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Creation failed: {response.status_code}")
logger.error(f"Error: {response.text}")
return
except Exception as e:
print(f"Error creating listing: {e}")
logger.error(f"Error creating listing: {e}")
return
@@ -118,22 +121,22 @@ def handle_market_get(args, default_rpc_url):
chain_id = getattr(args, "chain_id", None)
if not args.listing_id:
print("Error: --listing-id is required")
logger.error("Error: --listing-id is required")
return
print(f"Getting listing {args.listing_id} from {marketplace_url}...")
logger.info(f"Getting listing {args.listing_id} from {marketplace_url}...")
try:
import requests
response = requests.get(f"{marketplace_url}/v1/marketplace/offers/{args.listing_id}", timeout=10)
if response.status_code == 200:
listing = response.json()
print(json.dumps(listing, indent=2))
logger.info(json.dumps(listing, indent=2))
else:
print(f"Query failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Query failed: {response.status_code}")
logger.error(f"Error: {response.text}")
return
except Exception as e:
print(f"Error getting listing: {e}")
logger.error(f"Error getting listing: {e}")
return
@@ -143,25 +146,25 @@ def handle_market_delete(args, default_coordinator_url, read_password, render_ma
listing_id = getattr(args, "listing_id", None) or getattr(args, "order", None)
if not listing_id:
print("Error: --listing-id or --order is required")
logger.error("Error: --listing-id or --order is required")
return
headers = _auth_headers(args, read_password)
endpoint_type = "orders" if str(listing_id).startswith("order_") else "offers"
print(f"Deleting {endpoint_type[:-1]} {listing_id} on {marketplace_url}...")
logger.info(f"Deleting {endpoint_type[:-1]} {listing_id} on {marketplace_url}...")
try:
response = requests.delete(f"{marketplace_url}/v1/marketplace/{endpoint_type}/{listing_id}", headers=headers, timeout=30)
if response.status_code == 200:
result = response.json()
print("Marketplace item deleted successfully")
logger.info("Marketplace item deleted successfully")
render_mapping("Delete result:", result)
else:
print(f"Deletion failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Deletion failed: {response.status_code}")
logger.error(f"Error: {response.text}")
return
except Exception as e:
print(f"Error deleting listing: {e}")
logger.error(f"Error deleting listing: {e}")
return
@@ -176,7 +179,7 @@ def handle_market_gpu_register(args, default_coordinator_url):
compute_capability = getattr(args, "compute_capability", None)
if not gpu_name or memory_gb is None:
print("Auto-detecting GPU specifications from nvidia-smi...")
logger.info("Auto-detecting GPU specifications from nvidia-smi...")
try:
import subprocess
result = subprocess.run(
@@ -199,26 +202,25 @@ def handle_market_gpu_register(args, default_coordinator_url):
if not gpu_name:
gpu_name = detected_name
print(f" Detected GPU: {gpu_name}")
logger.info(f" Detected GPU: {gpu_name}")
if memory_gb is None:
memory_gb = memory_gb_detected
print(f" Detected Memory: {memory_gb} GB")
logger.info(f" Detected Memory: {memory_gb} GB")
if not compute_capability:
compute_capability = detected_compute
print(f" Detected Compute Capability: {compute_capability}")
logger.info(f" Detected Compute Capability: {compute_capability}")
else:
print(" Warning: nvidia-smi failed, using manual input or defaults")
logger.error(" Warning: nvidia-smi failed, using manual input or defaults")
except (subprocess.TimeoutExpired, FileNotFoundError, Exception) as e:
print(f" Warning: Could not run nvidia-smi: {e}")
logger.warning(f" Warning: Could not run nvidia-smi: {e}")
# Fallback to manual input if auto-detection failed
if not gpu_name or memory_gb is None:
print("Error: Could not auto-detect GPU specs. Please provide --name and --memory manually.")
print(" Example: aitbc-cli market gpu register --name 'NVIDIA GeForce RTX 4060 Ti' --memory 16 --price-per-hour 0.05")
logger.error("Error: Could not auto-detect GPU specs. Please provide --name and --memory manually.")
logger.info(" Example: aitbc-cli market gpu register --name 'NVIDIA GeForce RTX 4060 Ti' --memory 16 --price-per-hour 0.05")
return
if not args.price_per_hour:
print("Error: --price-per-hour is required (in AIT coins)")
logger.error("Error: --price-per-hour is required (in AIT coins)")
return
# Build GPU specs
@@ -233,7 +235,7 @@ def handle_market_gpu_register(args, default_coordinator_url):
"registered_at": __import__("datetime").datetime.now().isoformat()
}
print(f"Registering GPU on {gpu_url}...")
logger.info(f"Registering GPU on {gpu_url}...")
try:
response = requests.post(
f"{gpu_url}/v1/marketplace/gpu/register",
@@ -246,15 +248,15 @@ def handle_market_gpu_register(args, default_coordinator_url):
)
if response.status_code in (200, 201):
result = response.json()
print(f"GPU registered successfully: {result.get('gpu_id', 'N/A')}")
logger.info(f"GPU registered successfully: {result.get('gpu_id', 'N/A')}")
from ..utils import render_mapping
render_mapping("Registration result:", result)
else:
print(f"Registration failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Registration failed: {response.status_code}")
logger.error(f"Error: {response.text}")
return
except Exception as e:
print(f"Error registering GPU: {e}")
logger.error(f"Error registering GPU: {e}")
return
@@ -263,7 +265,7 @@ def handle_market_gpu_list(args, default_coordinator_url, output_format):
# Use GPU service URL instead of coordinator URL
gpu_url = getattr(args, 'gpu_url', 'http://localhost:8101')
print(f"Listing GPUs from {gpu_url}...")
logger.info(f"Listing GPUs from {gpu_url}...")
try:
params = {
"action": "offer",
@@ -284,30 +286,30 @@ def handle_market_gpu_list(args, default_coordinator_url, output_format):
if response.status_code == 200:
gpus = response.json()
if output_format(args) == "json":
print(json.dumps(gpus, indent=2))
logger.info(json.dumps(gpus, indent=2))
else:
print("GPU Listings:")
logger.info("GPU Listings:")
if isinstance(gpus, list):
if gpus:
for gpu in gpus:
if isinstance(gpu, dict):
print(f" - ID: {gpu.get('id', 'N/A')}")
print(f" Model: {gpu.get('model', 'N/A')}")
print(f" Memory: {gpu.get('memory_gb', 'N/A')} GB")
print(f" Price: {gpu.get('price_per_hour', 0)} AIT/hour")
print(f" Status: {gpu.get('status', 'N/A')}")
print(f" Region: {gpu.get('region', 'N/A')}")
logger.info(f" - ID: {gpu.get('id', 'N/A')}")
logger.info(f" Model: {gpu.get('model', 'N/A')}")
logger.info(f" Memory: {gpu.get('memory_gb', 'N/A')} GB")
logger.info(f" Price: {gpu.get('price_per_hour', 0)} AIT/hour")
logger.info(f" Status: {gpu.get('status', 'N/A')}")
logger.info(f" Region: {gpu.get('region', 'N/A')}")
else:
print(" No GPUs found")
logger.info(" No GPUs found")
else:
from ..utils import render_mapping
render_mapping("GPUs:", gpus)
else:
print(f"Query failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Query failed: {response.status_code}")
logger.error(f"Error: {response.text}")
return
except Exception as e:
print(f"Error listing GPUs: {e}")
logger.error(f"Error listing GPUs: {e}")
return
@@ -316,7 +318,7 @@ def handle_market_buy(args, default_coordinator_url, read_password, render_mappi
marketplace_url = _marketplace_url(args, default_coordinator_url)
if not args.item or not args.wallet:
print("Error: --item and --wallet are required")
logger.error("Error: --item and --wallet are required")
return
purchase_data = {
@@ -325,19 +327,19 @@ def handle_market_buy(args, default_coordinator_url, read_password, render_mappi
"price": getattr(args, "price", None)
}
print(f"Submitting purchase to {marketplace_url}...")
logger.info(f"Submitting purchase to {marketplace_url}...")
try:
response = requests.post(f"{marketplace_url}/v1/marketplace/offers/{args.item}/book", json=purchase_data, headers=_auth_headers(args, read_password), timeout=30)
if response.status_code in (200, 201):
result = response.json()
print("Purchase submitted successfully")
logger.info("Purchase submitted successfully")
render_mapping("Purchase:", result)
else:
print(f"Purchase failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Purchase failed: {response.status_code}")
logger.error(f"Error: {response.text}")
return
except Exception as e:
print(f"Error submitting purchase: {e}")
logger.error(f"Error submitting purchase: {e}")
return
@@ -354,32 +356,32 @@ def handle_market_orders(args, default_coordinator_url, output_format, render_ma
if wallet:
params["wallet"] = wallet
print(f"Getting marketplace orders from {marketplace_url}...")
logger.info(f"Getting marketplace orders from {marketplace_url}...")
try:
response = requests.get(f"{marketplace_url}/v1/marketplace/orders", params=params, timeout=10)
if response.status_code == 200:
orders = response.json()
if output_format(args) == "json":
print(json.dumps(orders, indent=2))
logger.info(json.dumps(orders, indent=2))
return
if isinstance(orders, dict):
orders = orders.get("orders", [])
print("Active marketplace orders:")
logger.info("Active marketplace orders:")
if not orders:
print(" No active orders found")
logger.info(" No active orders found")
return
for order in orders:
print(f" - ID: {order.get('id', 'N/A')}")
print(f" Type: {order.get('order_type', 'N/A')}")
print(f" Item: {order.get('item', 'N/A')}")
print(f" Price: {order.get('price', 0)} AIT")
print(f" Status: {order.get('status', 'N/A')}")
logger.info(f" - ID: {order.get('id', 'N/A')}")
logger.info(f" Type: {order.get('order_type', 'N/A')}")
logger.info(f" Item: {order.get('item', 'N/A')}")
logger.info(f" Price: {order.get('price', 0)} AIT")
logger.info(f" Status: {order.get('status', 'N/A')}")
else:
print(f"Query failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Query failed: {response.status_code}")
logger.error(f"Error: {response.text}")
return
except Exception as e:
print(f"Error getting orders: {e}")
logger.error(f"Error getting orders: {e}")
return
@@ -387,31 +389,31 @@ def handle_market_list_plugins(args, default_coordinator_url, output_format, ren
"""Handle marketplace plugin listing command."""
marketplace_url = _marketplace_url(args, default_coordinator_url)
print(f"Getting marketplace plugins from {marketplace_url}...")
logger.info(f"Getting marketplace plugins from {marketplace_url}...")
try:
response = requests.get(f"{marketplace_url}/v1/marketplace/plugins", timeout=10)
if response.status_code == 200:
plugins = response.json()
if output_format(args) == "json":
print(json.dumps(plugins, indent=2))
logger.info(json.dumps(plugins, indent=2))
return
if isinstance(plugins, dict):
plugins = plugins.get("plugins", [])
print("Available marketplace plugins:")
logger.info("Available marketplace plugins:")
if not plugins:
print(" No plugins found")
logger.info(" No plugins found")
return
for plugin in plugins:
print(f" - ID: {plugin.get('id', 'N/A')}")
print(f" Name: {plugin.get('name', 'N/A')}")
print(f" Type: {plugin.get('type', 'N/A')}")
print(f" Author: {plugin.get('author', 'N/A')}")
print(f" Description: {plugin.get('description', 'N/A')}")
print(f" Version: {plugin.get('version', 'N/A')}")
logger.info(f" - ID: {plugin.get('id', 'N/A')}")
logger.info(f" Name: {plugin.get('name', 'N/A')}")
logger.info(f" Type: {plugin.get('type', 'N/A')}")
logger.info(f" Author: {plugin.get('author', 'N/A')}")
logger.info(f" Description: {plugin.get('description', 'N/A')}")
logger.info(f" Version: {plugin.get('version', 'N/A')}")
else:
print(f"Query failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Query failed: {response.status_code}")
logger.error(f"Error: {response.text}")
return
except Exception as e:
print(f"Error getting plugins: {e}")
logger.error(f"Error getting plugins: {e}")
return

View File

@@ -4,6 +4,9 @@ import json
import sys
import requests
import logging
logger = logging.getLogger(__name__)
def handle_messaging_deploy(args, default_rpc_url, render_mapping):
@@ -11,7 +14,7 @@ def handle_messaging_deploy(args, default_rpc_url, render_mapping):
rpc_url = args.rpc_url or default_rpc_url
chain_id = getattr(args, "chain_id", None)
print(f"Deploying messaging contract to {rpc_url}...")
logger.info(f"Deploying messaging contract to {rpc_url}...")
try:
params = {}
if chain_id:
@@ -20,14 +23,14 @@ def handle_messaging_deploy(args, default_rpc_url, render_mapping):
response = requests.post(f"{rpc_url}/rpc/contracts/deploy/messaging", json={}, params=params, timeout=30)
if response.status_code == 200:
result = response.json()
print("Messaging contract deployed successfully")
logger.info("Messaging contract deployed successfully")
render_mapping("Deployment result:", result)
else:
print(f"Deployment failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Deployment failed: {response.status_code}")
logger.error(f"Error: {response.text}")
sys.exit(1)
except Exception as e:
print(f"Error deploying messaging contract: {e}")
logger.error(f"Error deploying messaging contract: {e}")
sys.exit(1)
@@ -36,7 +39,7 @@ def handle_messaging_state(args, default_rpc_url, output_format, render_mapping)
rpc_url = args.rpc_url or default_rpc_url
chain_id = getattr(args, "chain_id", None)
print(f"Getting messaging contract state from {rpc_url}...")
logger.info(f"Getting messaging contract state from {rpc_url}...")
try:
params = {}
if chain_id:
@@ -46,15 +49,15 @@ def handle_messaging_state(args, default_rpc_url, output_format, render_mapping)
if response.status_code == 200:
state = response.json()
if output_format(args) == "json":
print(json.dumps(state, indent=2))
logger.info(json.dumps(state, indent=2))
else:
render_mapping("Messaging contract state:", state)
else:
print(f"Query failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Query failed: {response.status_code}")
logger.error(f"Error: {response.text}")
sys.exit(1)
except Exception as e:
print(f"Error getting contract state: {e}")
logger.error(f"Error getting contract state: {e}")
sys.exit(1)
@@ -63,7 +66,7 @@ def handle_messaging_topics(args, default_rpc_url, output_format, render_mapping
rpc_url = args.rpc_url or default_rpc_url
chain_id = getattr(args, "chain_id", None)
print(f"Getting forum topics from {rpc_url}...")
logger.info(f"Getting forum topics from {rpc_url}...")
try:
params = {}
if chain_id:
@@ -73,20 +76,20 @@ def handle_messaging_topics(args, default_rpc_url, output_format, render_mapping
if response.status_code == 200:
topics = response.json()
if output_format(args) == "json":
print(json.dumps(topics, indent=2))
logger.info(json.dumps(topics, indent=2))
else:
print("Forum topics:")
logger.info("Forum topics:")
if isinstance(topics, list):
for topic in topics:
print(f" ID: {topic.get('topic_id', 'N/A')}, Title: {topic.get('title', 'N/A')}")
logger.info(f" ID: {topic.get('topic_id', 'N/A')}, Title: {topic.get('title', 'N/A')}")
else:
render_mapping("Topics:", topics)
else:
print(f"Query failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Query failed: {response.status_code}")
logger.error(f"Error: {response.text}")
sys.exit(1)
except Exception as e:
print(f"Error getting topics: {e}")
logger.error(f"Error getting topics: {e}")
sys.exit(1)
@@ -96,7 +99,7 @@ def handle_messaging_create_topic(args, default_rpc_url, read_password, render_m
chain_id = getattr(args, "chain_id", None)
if not args.title or not args.content:
print("Error: --title and --content are required")
logger.error("Error: --title and --content are required")
sys.exit(1)
# Get auth headers if wallet provided
@@ -113,19 +116,19 @@ def handle_messaging_create_topic(args, default_rpc_url, read_password, render_m
if chain_id:
topic_data["chain_id"] = chain_id
print(f"Creating forum topic on {rpc_url}...")
logger.info(f"Creating forum topic on {rpc_url}...")
try:
response = requests.post(f"{rpc_url}/rpc/messaging/topics/create", json=topic_data, headers=headers, timeout=30)
if response.status_code == 200:
result = response.json()
print("Topic created successfully")
logger.info("Topic created successfully")
render_mapping("Topic:", result)
else:
print(f"Creation failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Creation failed: {response.status_code}")
logger.error(f"Error: {response.text}")
sys.exit(1)
except Exception as e:
print(f"Error creating topic: {e}")
logger.error(f"Error creating topic: {e}")
sys.exit(1)
@@ -135,10 +138,10 @@ def handle_messaging_messages(args, default_rpc_url, output_format, render_mappi
chain_id = getattr(args, "chain_id", None)
if not args.topic_id:
print("Error: --topic-id is required")
logger.error("Error: --topic-id is required")
sys.exit(1)
print(f"Getting messages for topic {args.topic_id} from {rpc_url}...")
logger.info(f"Getting messages for topic {args.topic_id} from {rpc_url}...")
try:
params = {"topic_id": args.topic_id}
if chain_id:
@@ -148,20 +151,20 @@ def handle_messaging_messages(args, default_rpc_url, output_format, render_mappi
if response.status_code == 200:
messages = response.json()
if output_format(args) == "json":
print(json.dumps(messages, indent=2))
logger.info(json.dumps(messages, indent=2))
else:
print(f"Messages for topic {args.topic_id}:")
logger.info(f"Messages for topic {args.topic_id}:")
if isinstance(messages, list):
for msg in messages:
print(f" Message ID: {msg.get('message_id', 'N/A')}, Author: {msg.get('author', 'N/A')}")
logger.info(f" Message ID: {msg.get('message_id', 'N/A')}, Author: {msg.get('author', 'N/A')}")
else:
render_mapping("Messages:", messages)
else:
print(f"Query failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Query failed: {response.status_code}")
logger.error(f"Error: {response.text}")
sys.exit(1)
except Exception as e:
print(f"Error getting messages: {e}")
logger.error(f"Error getting messages: {e}")
sys.exit(1)
@@ -171,7 +174,7 @@ def handle_messaging_post(args, default_rpc_url, read_password, render_mapping):
chain_id = getattr(args, "chain_id", None)
if not args.topic_id or not args.content:
print("Error: --topic-id and --content are required")
logger.error("Error: --topic-id and --content are required")
sys.exit(1)
# Get auth headers if wallet provided
@@ -188,19 +191,19 @@ def handle_messaging_post(args, default_rpc_url, read_password, render_mapping):
if chain_id:
message_data["chain_id"] = chain_id
print(f"Posting message to topic {args.topic_id} on {rpc_url}...")
logger.info(f"Posting message to topic {args.topic_id} on {rpc_url}...")
try:
response = requests.post(f"{rpc_url}/rpc/messaging/messages/post", json=message_data, headers=headers, timeout=30)
if response.status_code == 200:
result = response.json()
print("Message posted successfully")
logger.info("Message posted successfully")
render_mapping("Message:", result)
else:
print(f"Post failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Post failed: {response.status_code}")
logger.error(f"Error: {response.text}")
sys.exit(1)
except Exception as e:
print(f"Error posting message: {e}")
logger.error(f"Error posting message: {e}")
sys.exit(1)
@@ -210,7 +213,7 @@ def handle_messaging_vote(args, default_rpc_url, read_password, render_mapping):
chain_id = getattr(args, "chain_id", None)
if not args.message_id or not args.vote:
print("Error: --message-id and --vote are required")
logger.error("Error: --message-id and --vote are required")
sys.exit(1)
# Get auth headers if wallet provided
@@ -227,19 +230,19 @@ def handle_messaging_vote(args, default_rpc_url, read_password, render_mapping):
if chain_id:
vote_data["chain_id"] = chain_id
print(f"Voting on message {args.message_id} on {rpc_url}...")
logger.info(f"Voting on message {args.message_id} on {rpc_url}...")
try:
response = requests.post(f"{rpc_url}/rpc/messaging/messages/{args.message_id}/vote", json=vote_data, headers=headers, timeout=30)
if response.status_code == 200:
result = response.json()
print("Vote recorded successfully")
logger.info("Vote recorded successfully")
render_mapping("Vote result:", result)
else:
print(f"Vote failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Vote failed: {response.status_code}")
logger.error(f"Error: {response.text}")
sys.exit(1)
except Exception as e:
print(f"Error voting on message: {e}")
logger.error(f"Error voting on message: {e}")
sys.exit(1)
@@ -249,10 +252,10 @@ def handle_messaging_search(args, default_rpc_url, output_format, render_mapping
chain_id = getattr(args, "chain_id", None)
if not args.query:
print("Error: --query is required")
logger.error("Error: --query is required")
sys.exit(1)
print(f"Searching messages for '{args.query}' on {rpc_url}...")
logger.info(f"Searching messages for '{args.query}' on {rpc_url}...")
try:
params = {"query": args.query}
if chain_id:
@@ -262,20 +265,20 @@ def handle_messaging_search(args, default_rpc_url, output_format, render_mapping
if response.status_code == 200:
results = response.json()
if output_format(args) == "json":
print(json.dumps(results, indent=2))
logger.info(json.dumps(results, indent=2))
else:
print(f"Search results for '{args.query}':")
logger.info(f"Search results for '{args.query}':")
if isinstance(results, list):
for msg in results:
print(f" Message ID: {msg.get('message_id', 'N/A')}, Topic: {msg.get('topic_id', 'N/A')}")
logger.info(f" Message ID: {msg.get('message_id', 'N/A')}, Topic: {msg.get('topic_id', 'N/A')}")
else:
render_mapping("Search results:", results)
else:
print(f"Search failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Search failed: {response.status_code}")
logger.error(f"Error: {response.text}")
sys.exit(1)
except Exception as e:
print(f"Error searching messages: {e}")
logger.error(f"Error searching messages: {e}")
sys.exit(1)
@@ -285,10 +288,10 @@ def handle_messaging_reputation(args, default_rpc_url, output_format, render_map
chain_id = getattr(args, "chain_id", None)
if not args.agent_id:
print("Error: --agent-id is required")
logger.error("Error: --agent-id is required")
sys.exit(1)
print(f"Getting reputation for agent {args.agent_id} from {rpc_url}...")
logger.info(f"Getting reputation for agent {args.agent_id} from {rpc_url}...")
try:
params = {}
if chain_id:
@@ -298,15 +301,15 @@ def handle_messaging_reputation(args, default_rpc_url, output_format, render_map
if response.status_code == 200:
reputation = response.json()
if output_format(args) == "json":
print(json.dumps(reputation, indent=2))
logger.info(json.dumps(reputation, indent=2))
else:
render_mapping(f"Agent {args.agent_id} reputation:", reputation)
else:
print(f"Query failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Query failed: {response.status_code}")
logger.error(f"Error: {response.text}")
sys.exit(1)
except Exception as e:
print(f"Error getting reputation: {e}")
logger.error(f"Error getting reputation: {e}")
sys.exit(1)
@@ -316,7 +319,7 @@ def handle_messaging_moderate(args, default_rpc_url, read_password, render_mappi
chain_id = getattr(args, "chain_id", None)
if not args.message_id or not args.action:
print("Error: --message-id and --action are required")
logger.error("Error: --message-id and --action are required")
sys.exit(1)
# Get auth headers if wallet provided
@@ -333,17 +336,17 @@ def handle_messaging_moderate(args, default_rpc_url, read_password, render_mappi
if chain_id:
moderation_data["chain_id"] = chain_id
print(f"Moderating message {args.message_id} on {rpc_url}...")
logger.info(f"Moderating message {args.message_id} on {rpc_url}...")
try:
response = requests.post(f"{rpc_url}/rpc/messaging/messages/{args.message_id}/moderate", json=moderation_data, headers=headers, timeout=30)
if response.status_code == 200:
result = response.json()
print("Moderation action completed successfully")
logger.info("Moderation action completed successfully")
render_mapping("Moderation result:", result)
else:
print(f"Moderation failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Moderation failed: {response.status_code}")
logger.error(f"Error: {response.text}")
sys.exit(1)
except Exception as e:
print(f"Error moderating message: {e}")
logger.error(f"Error moderating message: {e}")
sys.exit(1)

View File

@@ -5,42 +5,39 @@ import sys
from urllib.parse import urlparse
import requests
import logging
logger = logging.getLogger(__name__)
def handle_network_status(args, default_rpc_url, get_network_snapshot):
"""Handle network status query."""
snapshot = get_network_snapshot(getattr(args, "rpc_url", default_rpc_url))
print("Network status:")
print(f" Connected nodes: {snapshot['connected_count']}")
logger.info("Network status:")
logger.info(f" Connected nodes: {snapshot['connected_count']}")
for index, node in enumerate(snapshot["nodes"]):
label = "Local" if index == 0 else f"Peer {node['name']}"
health = "healthy" if node["healthy"] else "unreachable"
print(f" {label}: {health}")
print(f" Sync status: {snapshot['sync_status']}")
logger.info(f" {label}: {health}")
logger.info(f" Sync status: {snapshot['sync_status']}")
def handle_network_peers(args, default_rpc_url, get_network_snapshot):
"""Handle network peers query."""
snapshot = get_network_snapshot(getattr(args, "rpc_url", default_rpc_url))
print("Network peers:")
logger.info("Network peers:")
for node in snapshot["nodes"]:
endpoint = urlparse(node["rpc_url"]).netloc
status = "Connected" if node["healthy"] else f"Unreachable ({node['error'] or 'unknown error'})"
print(f" - {node['name']} ({endpoint}) - {status}")
logger.info(f" - {node['name']} ({endpoint}) - {status}")
def handle_network_sync(args, default_rpc_url, get_network_snapshot):
"""Handle network sync status query."""
snapshot = get_network_snapshot(getattr(args, "rpc_url", default_rpc_url))
print("Network sync status:")
print(f" Status: {snapshot['sync_status']}")
logger.info("Network sync status:")
logger.info(f" Status: {snapshot['sync_status']}")
for node in snapshot["nodes"]:
height = node["height"] if node["height"] is not None else "unknown"
print(f" {node['name']} height: {height}")
logger.info(f" {node['name']} height: {height}")
local_timestamp = snapshot["nodes"][0].get("timestamp") if snapshot["nodes"] else None
print(f" Last local block: {local_timestamp or 'unknown'}")
logger.info(f" Last local block: {local_timestamp or 'unknown'}")
def handle_network_ping(args, default_rpc_url, read_blockchain_env, normalize_rpc_url, first, probe_rpc_node):
"""Handle network ping command."""
env_config = read_blockchain_env()
@@ -55,29 +52,25 @@ def handle_network_ping(args, default_rpc_url, read_blockchain_env, normalize_rp
target_url = node if "://" in node else f"http://{node}:{peer_rpc_port}"
target = probe_rpc_node(node, target_url, chain_id=env_config.get("chain_id") or None)
print(f"Ping: Node {node} {'reachable' if target['healthy'] else 'unreachable'}")
print(f" Endpoint: {urlparse(target['rpc_url']).netloc}")
logger.info(f"Ping: Node {node} {'reachable' if target['healthy'] else 'unreachable'}")
logger.info(f" Endpoint: {urlparse(target['rpc_url']).netloc}")
if target["latency_ms"] is not None:
print(f" Latency: {target['latency_ms']}ms")
print(f" Status: {'connected' if target['healthy'] else 'error'}")
logger.info(f" Latency: {target['latency_ms']}ms")
logger.error(f" Status: {'connected' if target['healthy'] else 'error'}")
def handle_network_propagate(args, default_rpc_url, get_network_snapshot, first):
"""Handle network data propagation."""
data = first(getattr(args, "data_opt", None), getattr(args, "data", None), "test-data")
snapshot = get_network_snapshot(getattr(args, "rpc_url", default_rpc_url))
print("Data propagation: Complete")
print(f" Data: {data}")
print(f" Nodes: {snapshot['connected_count']}/{len(snapshot['nodes'])} reachable")
logger.info("Data propagation: Complete")
logger.info(f" Data: {data}")
logger.info(f" Nodes: {snapshot['connected_count']}/{len(snapshot['nodes'])} reachable")
def handle_network_force_sync(args, default_rpc_url, render_mapping):
"""Handle network force sync command."""
rpc_url = args.rpc_url or default_rpc_url
chain_id = getattr(args, "chain_id", None)
if not args.peer:
print("Error: --peer is required")
logger.error("Error: --peer is required")
sys.exit(1)
sync_data = {
@@ -86,17 +79,17 @@ def handle_network_force_sync(args, default_rpc_url, render_mapping):
if chain_id:
sync_data["chain_id"] = chain_id
print(f"Forcing sync to peer {args.peer} on {rpc_url}...")
logger.info(f"Forcing sync to peer {args.peer} on {rpc_url}...")
try:
response = requests.post(f"{rpc_url}/rpc/force-sync", json=sync_data, timeout=60)
if response.status_code == 200:
result = response.json()
print("Force sync initiated successfully")
logger.info("Force sync initiated successfully")
render_mapping("Sync result:", result)
else:
print(f"Force sync failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Force sync failed: {response.status_code}")
logger.error(f"Error: {response.text}")
sys.exit(1)
except Exception as e:
print(f"Error forcing sync: {e}")
logger.error(f"Error forcing sync: {e}")
sys.exit(1)

View File

@@ -1,6 +1,9 @@
"""Performance command handlers for AITBC CLI."""
import json
import logging
logger = logging.getLogger(__name__)
def handle_performance_benchmark(args, output_format, render_mapping):
@@ -15,16 +18,14 @@ def handle_performance_benchmark(args, output_format, render_mapping):
}
if output_format(args) == "json":
print(json.dumps(benchmark_data, indent=2))
logger.info(json.dumps(benchmark_data, indent=2))
else:
print("Performance Benchmark:")
print(f" TPS: {benchmark_data['tps']}")
print(f" Latency: {benchmark_data['latency_ms']}ms")
print(f" Throughput: {benchmark_data['throughput_mbps']}Mbps")
print(f" CPU Usage: {benchmark_data['cpu_usage']}%")
print(f" Memory Usage: {benchmark_data['memory_usage']}%")
logger.info("Performance Benchmark:")
logger.info(f" TPS: {benchmark_data['tps']}")
logger.info(f" Latency: {benchmark_data['latency_ms']}ms")
logger.info(f" Throughput: {benchmark_data['throughput_mbps']}Mbps")
logger.info(f" CPU Usage: {benchmark_data['cpu_usage']}%")
logger.info(f" Memory Usage: {benchmark_data['memory_usage']}%")
def handle_performance_optimize(args, render_mapping):
"""Handle performance optimize command."""
target = getattr(args, "target", "general")
@@ -36,7 +37,7 @@ def handle_performance_optimize(args, render_mapping):
"timestamp": __import__('datetime').datetime.now().isoformat()
}
print(f"Performance optimization applied for {target}")
logger.info(f"Performance optimization applied for {target}")
render_mapping("Optimization:", optimization_data)
@@ -52,5 +53,5 @@ def handle_performance_tune(args, render_mapping):
"timestamp": __import__('datetime').datetime.now().isoformat()
}
print("Performance tuning applied")
logger.info("Performance tuning applied")
render_mapping("Tuning:", tune_data)

View File

@@ -1,6 +1,9 @@
"""Pool hub SLA and capacity management handlers."""
from aitbc import AITBCHTTPClient, NetworkError
import logging
logger = logging.getLogger(__name__)
def handle_pool_hub_sla_metrics(args):
@@ -10,10 +13,10 @@ def handle_pool_hub_sla_metrics(args):
config = get_pool_hub_config()
if args.test_mode:
print(" SLA Metrics (test mode):")
print(" Uptime: 97.5%")
print(" Response Time: 850ms")
print(" Job Completion Rate: 92.3%")
logger.info(" SLA Metrics (test mode):")
logger.info(" Uptime: 97.5%")
logger.info(" Response Time: 850ms")
logger.info(" Job Completion Rate: 92.3%")
return
pool_hub_url = getattr(config, "pool_hub_url", "http://localhost:8012")
@@ -25,15 +28,13 @@ def handle_pool_hub_sla_metrics(args):
else:
metrics = http_client.get("/v1/sla/metrics")
print(" SLA Metrics:")
logger.info(" SLA Metrics:")
for key, value in metrics.items():
print(f" {key}: {value}")
logger.info(f" {key}: {value}")
except NetworkError as e:
print(f"❌ Failed to get SLA metrics: {e}")
logger.error(f"❌ Failed to get SLA metrics: {e}")
except Exception as e:
print(f"❌ Error getting SLA metrics: {e}")
logger.error(f"❌ Error getting SLA metrics: {e}")
def handle_pool_hub_sla_violations(args):
"""Get SLA violations across all miners."""
try:
@@ -41,23 +42,21 @@ def handle_pool_hub_sla_violations(args):
config = get_pool_hub_config()
if args.test_mode:
print("⚠️ SLA Violations (test mode):")
print(" miner_001: response_time violation")
logger.info("⚠️ SLA Violations (test mode):")
logger.info(" miner_001: response_time violation")
return
pool_hub_url = getattr(config, "pool_hub_url", "http://localhost:8012")
http_client = AITBCHTTPClient(base_url=pool_hub_url, timeout=30)
violations = http_client.get("/v1/sla/violations")
print("⚠️ SLA Violations:")
logger.info("⚠️ SLA Violations:")
for v in violations:
print(f" {v}")
logger.info(f" {v}")
except NetworkError as e:
print(f"❌ Failed to get violations: {e}")
logger.error(f"❌ Failed to get violations: {e}")
except Exception as e:
print(f"❌ Error getting violations: {e}")
logger.error(f"❌ Error getting violations: {e}")
def handle_pool_hub_capacity_snapshots(args):
"""Get capacity planning snapshots."""
try:
@@ -65,24 +64,22 @@ def handle_pool_hub_capacity_snapshots(args):
config = get_pool_hub_config()
if args.test_mode:
print("📊 Capacity Snapshots (test mode):")
print(" Total Capacity: 1250 GPU")
print(" Available: 320 GPU")
logger.info("📊 Capacity Snapshots (test mode):")
logger.info(" Total Capacity: 1250 GPU")
logger.info(" Available: 320 GPU")
return
pool_hub_url = getattr(config, "pool_hub_url", "http://localhost:8012")
http_client = AITBCHTTPClient(base_url=pool_hub_url, timeout=30)
snapshots = http_client.get("/v1/sla/capacity/snapshots")
print("📊 Capacity Snapshots:")
logger.info("📊 Capacity Snapshots:")
for s in snapshots:
print(f" {s}")
logger.info(f" {s}")
except NetworkError as e:
print(f"❌ Failed to get snapshots: {e}")
logger.error(f"❌ Failed to get snapshots: {e}")
except Exception as e:
print(f"❌ Error getting snapshots: {e}")
logger.error(f"❌ Error getting snapshots: {e}")
def handle_pool_hub_capacity_forecast(args):
"""Get capacity forecast."""
try:
@@ -90,24 +87,22 @@ def handle_pool_hub_capacity_forecast(args):
config = get_pool_hub_config()
if args.test_mode:
print("🔮 Capacity Forecast (test mode):")
print(" Projected Capacity: 1400 GPU")
print(" Growth Rate: 12%")
logger.info("🔮 Capacity Forecast (test mode):")
logger.info(" Projected Capacity: 1400 GPU")
logger.info(" Growth Rate: 12%")
return
pool_hub_url = getattr(config, "pool_hub_url", "http://localhost:8012")
http_client = AITBCHTTPClient(base_url=pool_hub_url, timeout=30)
forecast = http_client.get("/v1/sla/capacity/forecast")
print("🔮 Capacity Forecast:")
logger.info("🔮 Capacity Forecast:")
for key, value in forecast.items():
print(f" {key}: {value}")
logger.info(f" {key}: {value}")
except NetworkError as e:
print(f"❌ Failed to get forecast: {e}")
logger.error(f"❌ Failed to get forecast: {e}")
except Exception as e:
print(f"❌ Error getting forecast: {e}")
logger.error(f"❌ Error getting forecast: {e}")
def handle_pool_hub_capacity_recommendations(args):
"""Get scaling recommendations."""
try:
@@ -115,24 +110,22 @@ def handle_pool_hub_capacity_recommendations(args):
config = get_pool_hub_config()
if args.test_mode:
print("💡 Capacity Recommendations (test mode):")
print(" Type: scale_up")
print(" Action: Add 50 GPU capacity")
logger.info("💡 Capacity Recommendations (test mode):")
logger.info(" Type: scale_up")
logger.info(" Action: Add 50 GPU capacity")
return
pool_hub_url = getattr(config, "pool_hub_url", "http://localhost:8012")
http_client = AITBCHTTPClient(base_url=pool_hub_url, timeout=30)
recommendations = http_client.get("/v1/sla/capacity/recommendations")
print("💡 Capacity Recommendations:")
logger.info("💡 Capacity Recommendations:")
for r in recommendations:
print(f" {r}")
logger.info(f" {r}")
except NetworkError as e:
print(f"❌ Failed to get recommendations: {e}")
logger.error(f"❌ Failed to get recommendations: {e}")
except Exception as e:
print(f"❌ Error getting recommendations: {e}")
logger.error(f"❌ Error getting recommendations: {e}")
def handle_pool_hub_billing_usage(args):
"""Get billing usage data."""
try:
@@ -140,24 +133,22 @@ def handle_pool_hub_billing_usage(args):
config = get_pool_hub_config()
if args.test_mode:
print("💰 Billing Usage (test mode):")
print(" Total GPU Hours: 45678")
print(" Total Cost: $12500.50")
logger.info("💰 Billing Usage (test mode):")
logger.info(" Total GPU Hours: 45678")
logger.info(" Total Cost: $12500.50")
return
pool_hub_url = getattr(config, "pool_hub_url", "http://localhost:8012")
http_client = AITBCHTTPClient(base_url=pool_hub_url, timeout=30)
usage = http_client.get("/v1/sla/billing/usage")
print("💰 Billing Usage:")
logger.info("💰 Billing Usage:")
for key, value in usage.items():
print(f" {key}: {value}")
logger.info(f" {key}: {value}")
except NetworkError as e:
print(f"❌ Failed to get billing usage: {e}")
logger.error(f"❌ Failed to get billing usage: {e}")
except Exception as e:
print(f"❌ Error getting billing usage: {e}")
logger.error(f"❌ Error getting billing usage: {e}")
def handle_pool_hub_billing_sync(args):
"""Trigger billing sync with coordinator-api."""
try:
@@ -165,22 +156,20 @@ def handle_pool_hub_billing_sync(args):
config = get_pool_hub_config()
if args.test_mode:
print("🔄 Billing sync triggered (test mode)")
print("✅ Sync completed successfully")
logger.info("🔄 Billing sync triggered (test mode)")
logger.info("✅ Sync completed successfully")
return
pool_hub_url = getattr(config, "pool_hub_url", "http://localhost:8012")
http_client = AITBCHTTPClient(base_url=pool_hub_url, timeout=60)
result = http_client.post("/v1/sla/billing/sync")
print("🔄 Billing sync triggered")
print(f"{result.get('message', 'Success')}")
logger.info("🔄 Billing sync triggered")
logger.info(f"{result.get('message', 'Success')}")
except NetworkError as e:
print(f"❌ Billing sync failed: {e}")
logger.error(f"❌ Billing sync failed: {e}")
except Exception as e:
print(f"❌ Error triggering billing sync: {e}")
logger.error(f"❌ Error triggering billing sync: {e}")
def handle_pool_hub_collect_metrics(args):
"""Trigger SLA metrics collection."""
try:
@@ -188,17 +177,17 @@ def handle_pool_hub_collect_metrics(args):
config = get_pool_hub_config()
if args.test_mode:
print("📊 SLA metrics collection triggered (test mode)")
print("✅ Collection completed successfully")
logger.info("📊 SLA metrics collection triggered (test mode)")
logger.info("✅ Collection completed successfully")
return
pool_hub_url = getattr(config, "pool_hub_url", "http://localhost:8012")
http_client = AITBCHTTPClient(base_url=pool_hub_url, timeout=60)
result = http_client.post("/v1/sla/metrics/collect")
print("📊 SLA metrics collection triggered")
print(f"{result.get('message', 'Success')}")
logger.info("📊 SLA metrics collection triggered")
logger.info(f"{result.get('message', 'Success')}")
except NetworkError as e:
print(f"❌ Metrics collection failed: {e}")
logger.error(f"❌ Metrics collection failed: {e}")
except Exception as e:
print(f"❌ Error triggering metrics collection: {e}")
logger.error(f"❌ Error triggering metrics collection: {e}")

View File

@@ -1,6 +1,9 @@
"""Resource command handlers for AITBC CLI."""
import json
import logging
logger = logging.getLogger(__name__)
def handle_resource_status(args, output_format, render_mapping):
@@ -14,7 +17,7 @@ def handle_resource_status(args, output_format, render_mapping):
}
if output_format(args) == "json":
print(json.dumps(status_data, indent=2))
logger.info(json.dumps(status_data, indent=2))
else:
render_mapping("Resource Status:", status_data)
@@ -33,7 +36,7 @@ def handle_resource_allocate(args, render_mapping):
"timestamp": __import__('datetime').datetime.now().isoformat()
}
print(f"Resources allocated to {agent_id}")
logger.info(f"Resources allocated to {agent_id}")
render_mapping("Allocation:", allocation_data)
@@ -50,7 +53,7 @@ def handle_resource_monitor(args, render_mapping):
"timestamp": __import__('datetime').datetime.now().isoformat()
}
print(f"Resource monitoring started (interval: {interval}s, duration: {duration}s)")
logger.info(f"Resource monitoring started (interval: {interval}s, duration: {duration}s)")
render_mapping("Monitor:", monitor_data)
@@ -65,7 +68,7 @@ def handle_resource_optimize(args, render_mapping):
"timestamp": __import__('datetime').datetime.now().isoformat()
}
print(f"Resource optimization applied for {target}")
logger.info(f"Resource optimization applied for {target}")
render_mapping("Optimization:", optimization_data)
@@ -80,5 +83,5 @@ def handle_resource_benchmark(args, render_mapping):
"timestamp": __import__('datetime').datetime.now().isoformat()
}
print(f"Resource benchmark completed for {benchmark_type}")
logger.info(f"Resource benchmark completed for {benchmark_type}")
render_mapping("Benchmark:", benchmark_data)

View File

@@ -1,16 +1,17 @@
"""System and utility handlers."""
import sys
import logging
logger = logging.getLogger(__name__)
def handle_system_status(args, cli_version):
"""Handle system status command."""
print("System status: OK")
print(f" Version: aitbc-cli v{cli_version}")
print(" Services: Running")
print(" Nodes: 2 connected")
logger.info("System status: OK")
logger.info(f" Version: aitbc-cli v{cli_version}")
logger.info(" Services: Running")
logger.info(" Nodes: 2 connected")
def handle_analytics(args, default_rpc_url, get_blockchain_analytics):
"""Handle analytics command."""
analytics_type = getattr(args, "analytics_type", None) or getattr(args, "analytics_action", None) or getattr(args, "type", "blocks")
@@ -63,10 +64,10 @@ def handle_analytics(args, default_rpc_url, get_blockchain_analytics):
else:
analytics = get_blockchain_analytics(analytics_type, limit, rpc_url=rpc_url)
if analytics:
print(f"Blockchain Analytics ({analytics['type']}):")
logger.info(f"Blockchain Analytics ({analytics['type']}):")
for key, value in analytics.items():
if key != "type":
print(f" {key}: {value}")
logger.info(f" {key}: {value}")
else:
sys.exit(1)
@@ -88,7 +89,7 @@ def handle_agent_action(args, agent_operations, render_mapping):
"status": "simulated",
"timestamp": __import__('datetime').datetime.now().isoformat()
}
print(f"Agent {args.agent_action} (simulated)")
logger.info(f"Agent {args.agent_action} (simulated)")
render_mapping(f"Agent {args.agent_action}:", stub_result)
return
# Handle case where result doesn't have 'action' field (e.g., message send)
@@ -96,7 +97,7 @@ def handle_agent_action(args, agent_operations, render_mapping):
render_mapping(f"Agent {result['action']}:", result)
else:
# Just print success message for message send
print("Agent operation completed successfully")
logger.info("Agent operation completed successfully")
except Exception as e:
# Return stub data on error
stub_result = {
@@ -105,7 +106,7 @@ def handle_agent_action(args, agent_operations, render_mapping):
"error": str(e),
"timestamp": __import__('datetime').datetime.now().isoformat()
}
print(f"Agent {args.agent_action} (simulated - error: {e})")
logger.error(f"Agent {args.agent_action} (simulated - error: {e})")
render_mapping(f"Agent {args.agent_action}:", stub_result)
@@ -125,7 +126,7 @@ def handle_agent_sdk_action(args, render_mapping):
"timestamp": __import__('datetime').datetime.now().isoformat()
}
print(f"Agent SDK created: {name}")
logger.info(f"Agent SDK created: {name}")
render_mapping("Agent SDK:", sdk_data)
elif action == "update-status":
@@ -135,7 +136,7 @@ def handle_agent_sdk_action(args, render_mapping):
coordinator_url = getattr(args, "coordinator_url", "http://localhost:9001")
if not agent_id or not status:
print("Error: --agent-id and --status are required")
logger.error("Error: --agent-id and --status are required")
sys.exit(1)
status_update_request = {
@@ -143,8 +144,7 @@ def handle_agent_sdk_action(args, render_mapping):
"load_metrics": load_metrics if isinstance(load_metrics, dict) else {}
}
print(f"Updating agent {agent_id} status to {status}...")
logger.info(f"Updating agent {agent_id} status to {status}...")
try:
import requests
response = requests.put(
@@ -155,14 +155,14 @@ def handle_agent_sdk_action(args, render_mapping):
if response.status_code == 200:
result = response.json()
print(f"Agent status updated successfully")
logger.info(f"Agent status updated successfully")
render_mapping("Status Update:", result)
else:
print(f"Status update failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Status update failed: {response.status_code}")
logger.error(f"Error: {response.text}")
sys.exit(1)
except Exception as e:
print(f"Error updating agent status: {e}")
logger.error(f"Error updating agent status: {e}")
sys.exit(1)
elif action == "register":
@@ -184,8 +184,7 @@ def handle_agent_sdk_action(args, render_mapping):
"metadata": metadata if isinstance(metadata, dict) else (json.loads(metadata) if metadata else {})
}
print(f"Registering agent {agent_id} with coordinator at {coordinator_url}...")
logger.info(f"Registering agent {agent_id} with coordinator at {coordinator_url}...")
try:
import requests
response = requests.post(
@@ -196,14 +195,14 @@ def handle_agent_sdk_action(args, render_mapping):
if response.status_code in (200, 201):
result = response.json()
print(f"Agent registered successfully")
logger.info(f"Agent registered successfully")
render_mapping("Registration:", result)
else:
print(f"Registration failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Registration failed: {response.status_code}")
logger.error(f"Error: {response.text}")
sys.exit(1)
except Exception as e:
print(f"Error registering agent: {e}")
logger.error(f"Error registering agent: {e}")
sys.exit(1)
elif action == "list":
@@ -218,8 +217,7 @@ def handle_agent_sdk_action(args, render_mapping):
if agent_type:
query["agent_type"] = agent_type
print(f"Discovering agents from coordinator at {coordinator_url}...")
logger.info(f"Discovering agents from coordinator at {coordinator_url}...")
try:
import requests
response = requests.post(
@@ -230,22 +228,21 @@ def handle_agent_sdk_action(args, render_mapping):
if response.status_code == 200:
result = response.json()
print(f"Found {result.get('count', 0)} agents")
logger.info(f"Found {result.get('count', 0)} agents")
render_mapping("Agents:", result)
else:
print(f"Discovery failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Discovery failed: {response.status_code}")
logger.error(f"Error: {response.text}")
sys.exit(1)
except Exception as e:
print(f"Error discovering agents: {e}")
logger.error(f"Error discovering agents: {e}")
sys.exit(1)
elif action == "status":
agent_id = getattr(args, "agent_id", None)
coordinator_url = getattr(args, "coordinator_url", "http://localhost:9001")
print(f"Getting agent info for {agent_id} from coordinator at {coordinator_url}...")
logger.info(f"Getting agent info for {agent_id} from coordinator at {coordinator_url}...")
try:
import requests
response = requests.get(
@@ -255,17 +252,17 @@ def handle_agent_sdk_action(args, render_mapping):
if response.status_code == 200:
result = response.json()
print(f"Agent info retrieved")
logger.info(f"Agent info retrieved")
render_mapping("Agent:", result)
elif response.status_code == 404:
print(f"Agent not found: {agent_id}")
logger.info(f"Agent not found: {agent_id}")
sys.exit(1)
else:
print(f"Query failed: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Query failed: {response.status_code}")
logger.error(f"Error: {response.text}")
sys.exit(1)
except Exception as e:
print(f"Error getting agent info: {e}")
logger.error(f"Error getting agent info: {e}")
sys.exit(1)
elif action == "capabilities":
@@ -276,7 +273,7 @@ def handle_agent_sdk_action(args, render_mapping):
"max_concurrent_jobs": 2
}
print("System capabilities")
logger.info("System capabilities")
render_mapping("Capabilities:", caps_data)
else:
@@ -287,7 +284,7 @@ def handle_agent_sdk_action(args, render_mapping):
"timestamp": __import__('datetime').datetime.now().isoformat()
}
print(f"Agent SDK {action} (simulated)")
logger.info(f"Agent SDK {action} (simulated)")
render_mapping("SDK Operation:", sdk_result)
@@ -369,7 +366,7 @@ def handle_simulate_action(args, simulate_blockchain, simulate_wallets, simulate
elif args.simulate_command == "ai-jobs":
simulate_ai_jobs(args.jobs, args.models, args.duration_range)
else:
print(f"Unknown simulate command: {args.simulate_command}")
logger.info(f"Unknown simulate command: {args.simulate_command}")
sys.exit(1)
@@ -440,7 +437,7 @@ def handle_economics_action(args, render_mapping):
}
render_mapping("Token Balance:", result)
else:
print(f"Unknown economics action: {action}")
logger.info(f"Unknown economics action: {action}")
sys.exit(1)
@@ -466,7 +463,7 @@ def handle_cluster_action(args, render_mapping):
}
render_mapping("Cluster Status:", result)
else:
print(f"Unknown cluster action: {action}")
logger.info(f"Unknown cluster action: {action}")
sys.exit(1)
@@ -491,7 +488,7 @@ def handle_performance_action(args, render_mapping):
}
render_mapping("Performance Profile:", result)
else:
print(f"Unknown performance action: {action}")
logger.info(f"Unknown performance action: {action}")
sys.exit(1)
@@ -523,7 +520,7 @@ def handle_security_action(args, render_mapping):
}
render_mapping("Security Patch:", result)
else:
print(f"Unknown security action: {action}")
logger.info(f"Unknown security action: {action}")
sys.exit(1)
@@ -538,7 +535,7 @@ def handle_compliance_check(args, render_mapping):
"issues_found": 0
}
print(f"Compliance check for {standard}")
logger.info(f"Compliance check for {standard}")
render_mapping("Compliance:", compliance_data)
@@ -553,7 +550,7 @@ def handle_compliance_report(args, render_mapping):
"overall_status": "compliant"
}
print(f"Compliance report ({format_type})")
logger.info(f"Compliance report ({format_type})")
render_mapping("Report:", report_data)
@@ -583,7 +580,7 @@ def handle_cluster_sync(args, render_mapping):
"last_sync": __import__('datetime').datetime.now().isoformat()
}
print("Cluster sync completed")
logger.info("Cluster sync completed")
render_mapping("Cluster Sync:", sync_data)
@@ -598,7 +595,7 @@ def handle_cluster_balance(args, render_mapping):
"timestamp": __import__('datetime').datetime.now().isoformat()
}
print("Workload balanced across cluster")
logger.info("Workload balanced across cluster")
render_mapping("Cluster Balance:", balance_data)
@@ -614,7 +611,7 @@ def handle_script_run(args, render_mapping):
"timestamp": __import__('datetime').datetime.now().isoformat()
}
print(f"Script executed: {file_path}")
logger.info(f"Script executed: {file_path}")
render_mapping("Script:", script_data)

View File

@@ -4,6 +4,9 @@ import json
import requests
import sys
from aitbc.utils.paths import get_data_path
import logging
logger = logging.getLogger(__name__)
def handle_wallet_create(args, create_wallet, read_password, first):
@@ -11,65 +14,59 @@ def handle_wallet_create(args, create_wallet, read_password, first):
wallet_name = first(getattr(args, "wallet_name", None), getattr(args, "wallet_name_opt", None))
password = read_password(args, "wallet_password")
if not wallet_name or not password:
print("Error: Wallet name and password are required")
logger.error("Error: Wallet name and password are required")
sys.exit(1)
address = create_wallet(wallet_name, password)
print(f"Wallet address: {address}")
logger.info(f"Wallet address: {address}")
def handle_wallet_list(args, list_wallets, output_format):
"""Handle wallet list command."""
wallets = list_wallets()
if output_format(args) == "json":
print(json.dumps(wallets, indent=2))
logger.info(json.dumps(wallets, indent=2))
return
print("Wallets:")
logger.info("Wallets:")
for wallet in wallets:
print(f" {wallet['name']}: {wallet['address']}")
logger.info(f" {wallet['name']}: {wallet['address']}")
def handle_wallet_balance(args, default_rpc_url, list_wallets, get_balance, first):
"""Handle wallet balance command."""
rpc_url = getattr(args, "rpc_url", default_rpc_url)
if getattr(args, "all", False):
print("All wallet balances:")
logger.info("All wallet balances:")
for wallet in list_wallets():
balance_info = get_balance(wallet["name"], rpc_url=rpc_url)
if balance_info:
print(f" {wallet['name']}: {balance_info['balance']} AIT")
logger.info(f" {wallet['name']}: {balance_info['balance']} AIT")
else:
print(f" {wallet['name']}: unavailable")
logger.info(f" {wallet['name']}: unavailable")
return
wallet_name = first(getattr(args, "wallet_name", None), getattr(args, "wallet_name_opt", None))
if not wallet_name:
print("Error: Wallet name is required")
logger.error("Error: Wallet name is required")
sys.exit(1)
balance_info = get_balance(wallet_name, rpc_url=rpc_url)
if not balance_info:
sys.exit(1)
print(f"Wallet: {balance_info['wallet_name']}")
print(f"Address: {balance_info['address']}")
print(f"Balance: {balance_info['balance']} AIT")
print(f"Nonce: {balance_info['nonce']}")
logger.info(f"Wallet: {balance_info['wallet_name']}")
logger.info(f"Address: {balance_info['address']}")
logger.info(f"Balance: {balance_info['balance']} AIT")
logger.info(f"Nonce: {balance_info['nonce']}")
def handle_wallet_transactions(args, get_transactions, output_format, first):
"""Handle wallet transactions command."""
wallet_name = first(getattr(args, "wallet_name", None), getattr(args, "wallet_name_opt", None))
if not wallet_name:
print("Error: Wallet name is required")
logger.error("Error: Wallet name is required")
sys.exit(1)
transactions = get_transactions(wallet_name, limit=args.limit, rpc_url=args.rpc_url)
if output_format(args) == "json":
print(json.dumps(transactions, indent=2))
logger.info(json.dumps(transactions, indent=2))
return
print(f"Transactions for {wallet_name}:")
logger.info(f"Transactions for {wallet_name}:")
for index, tx in enumerate(transactions, 1):
print(f" {index}. Hash: {tx.get('hash', 'N/A')}")
print(f" Amount: {tx.get('value', 0)} AIT")
print(f" Fee: {tx.get('fee', 0)} AIT")
print(f" Type: {tx.get('type', 'N/A')}")
print()
logger.info(f" {index}. Hash: {tx.get('hash', 'N/A')}")
logger.info(f" Amount: {tx.get('value', 0)} AIT")
logger.info(f" Fee: {tx.get('fee', 0)} AIT")
logger.info(f" Type: {tx.get('type', 'N/A')}")
logger.info("")
def handle_wallet_send(args, send_transaction, read_password, first):
@@ -86,11 +83,11 @@ def handle_wallet_send(args, send_transaction, read_password, first):
password = read_password(args, "wallet_password")
if not from_wallet or not to_address or amount_value is None:
print("Error: From wallet, destination, and amount are required")
logger.error("Error: From wallet, destination, and amount are required")
sys.exit(1)
if not password:
print("Error: Password is required for signing transaction")
logger.error("Error: Password is required for signing transaction")
sys.exit(1)
# Use default fee if not specified
@@ -103,7 +100,7 @@ def handle_wallet_send(args, send_transaction, read_password, first):
sender_keystore = keystore_dir / f"{from_wallet}.json"
if not sender_keystore.exists():
print(f"Error: Wallet '{from_wallet}' not found")
logger.error(f"Error: Wallet '{from_wallet}' not found")
sys.exit(1)
with open(sender_keystore) as f:
@@ -121,7 +118,7 @@ def handle_wallet_send(args, send_transaction, read_password, first):
private_key_hex = aitbc_cli_module.decrypt_private_key(sender_keystore, password)
private_key = ed25519.Ed25519PrivateKey.from_private_bytes(bytes.fromhex(private_key_hex))
except Exception as e:
print(f"Error decrypting wallet: {e}")
logger.error(f"Error decrypting wallet: {e}")
sys.exit(1)
# Get RPC URL
@@ -173,17 +170,17 @@ def handle_wallet_send(args, send_transaction, read_password, first):
if response.status_code == 200:
result = response.json()
if result.get("success"):
print("Transaction sent successfully")
print(f"Transaction hash: {result.get('transaction_hash')}")
logger.info("Transaction sent successfully")
logger.info(f"Transaction hash: {result.get('transaction_hash')}")
else:
print(f"Transaction failed: {result.get('message', 'Unknown error')}")
logger.error(f"Transaction failed: {result.get('message', 'Unknown error')}")
sys.exit(1)
else:
print(f"Error submitting transaction: {response.status_code}")
print(f"Error: {response.text}")
logger.error(f"Error submitting transaction: {response.status_code}")
logger.error(f"Error: {response.text}")
sys.exit(1)
except Exception as e:
print(f"Error submitting transaction: {e}")
logger.error(f"Error submitting transaction: {e}")
sys.exit(1)
@@ -193,32 +190,28 @@ def handle_wallet_import(args, import_wallet, read_password, first):
private_key = first(getattr(args, "private_key_arg", None), getattr(args, "private_key_opt", None))
password = read_password(args, "wallet_password")
if not wallet_name or not private_key or not password:
print("Error: Wallet name, private key, and password are required")
logger.error("Error: Wallet name, private key, and password are required")
sys.exit(1)
address = import_wallet(wallet_name, private_key, password)
if not address:
sys.exit(1)
print(f"Wallet address: {address}")
logger.info(f"Wallet address: {address}")
def handle_wallet_export(args, export_wallet, read_password, first):
"""Handle wallet export command."""
wallet_name = first(getattr(args, "wallet_name", None), getattr(args, "wallet_name_opt", None))
password = read_password(args, "wallet_password")
if not wallet_name or not password:
print("Error: Wallet name and password are required")
logger.error("Error: Wallet name and password are required")
sys.exit(1)
private_key = export_wallet(wallet_name, password)
if not private_key:
sys.exit(1)
print(private_key)
logger.info(private_key)
def handle_wallet_delete(args, delete_wallet, first):
"""Handle wallet delete command."""
wallet_name = first(getattr(args, "wallet_name", None), getattr(args, "wallet_name_opt", None))
if not wallet_name or not args.confirm:
print("Error: Wallet name and --confirm are required")
logger.error("Error: Wallet name and --confirm are required")
sys.exit(1)
if not delete_wallet(wallet_name):
sys.exit(1)
@@ -229,7 +222,7 @@ def handle_wallet_rename(args, rename_wallet, first):
old_name = first(getattr(args, "old_name_arg", None), getattr(args, "old_name", None))
new_name = first(getattr(args, "new_name_arg", None), getattr(args, "new_name", None))
if not old_name or not new_name:
print("Error: Old and new wallet names are required")
logger.error("Error: Old and new wallet names are required")
sys.exit(1)
if not rename_wallet(old_name, new_name):
sys.exit(1)
@@ -239,33 +232,29 @@ def handle_wallet_backup(args, first):
"""Handle wallet backup command."""
wallet_name = first(getattr(args, "wallet_name", None), getattr(args, "wallet_name_opt", None))
if not wallet_name:
print("Error: Wallet name is required")
logger.error("Error: Wallet name is required")
sys.exit(1)
print(f"Wallet backup: {wallet_name}")
logger.info(f"Wallet backup: {wallet_name}")
backup_path = get_data_path("backups")
print(f" Backup created: {backup_path}/{wallet_name}_$(date +%Y%m%d).json")
print(" Status: completed")
logger.info(f" Backup created: {backup_path}/{wallet_name}_$(date +%Y%m%d).json")
logger.info(" Status: completed")
def handle_wallet_sync(args, first):
"""Handle wallet sync command."""
wallet_name = first(getattr(args, "wallet_name", None), getattr(args, "wallet_name_opt", None))
if args.all:
print("Wallet sync: All wallets")
logger.info("Wallet sync: All wallets")
elif wallet_name:
print(f"Wallet sync: {wallet_name}")
logger.info(f"Wallet sync: {wallet_name}")
else:
print("Error: Wallet name or --all is required")
logger.error("Error: Wallet name or --all is required")
sys.exit(1)
print(" Sync status: completed")
print(" Last sync: $(date)")
logger.info(" Sync status: completed")
logger.info(" Last sync: $(date)")
def handle_wallet_batch(args, send_batch_transactions, read_password):
"""Handle wallet batch command."""
password = read_password(args)
if not password:
print("Error: Password is required")
logger.error("Error: Password is required")
sys.exit(1)
with open(args.file) as handle:
transactions = json.load(handle)

View File

@@ -1,6 +1,9 @@
"""Workflow command handlers for AITBC CLI."""
import json
import logging
logger = logging.getLogger(__name__)
def handle_workflow_create(args, render_mapping):
@@ -18,7 +21,7 @@ def handle_workflow_create(args, render_mapping):
"estimated_duration": f"{steps * 2}-{steps * 3} minutes"
}
print(f"Workflow created: {workflow_data['workflow_id']}")
logger.info(f"Workflow created: {workflow_data['workflow_id']}")
render_mapping("Workflow:", workflow_data)
@@ -37,7 +40,7 @@ def handle_workflow_schedule(args, render_mapping):
"next_run": "pending"
}
print(f"Workflow scheduled: {schedule_data['schedule_id']}")
logger.info(f"Workflow scheduled: {schedule_data['schedule_id']}")
render_mapping("Schedule:", schedule_data)
@@ -54,6 +57,6 @@ def handle_workflow_monitor(args, output_format, render_mapping):
}
if output_format(args) == "json":
print(json.dumps(monitor_data, indent=2))
logger.info(json.dumps(monitor_data, indent=2))
else:
render_mapping("Workflow Monitor:", monitor_data)