Spaces:
Paused
Paused
| """ | |
| FastAPI server for Bitcoin mining dashboard | |
| """ | |
| from fastapi import FastAPI, HTTPException | |
| from fastapi.staticfiles import StaticFiles | |
| from fastapi.responses import FileResponse | |
| import uvicorn | |
| from parallel_miner_v3 import ParallelMiner | |
| import threading | |
| from typing import Dict, Optional | |
| import logging | |
| # Configure logging | |
| logging.basicConfig( | |
| level=logging.INFO, | |
| format='%(asctime)s - %(levelname)s - %(message)s' | |
| ) | |
| app = FastAPI(title="Bitcoin Mining Dashboard") | |
| # Mount static files | |
| app.mount("/static", StaticFiles(directory="static"), name="static") | |
| app.mount("/css", StaticFiles(directory="static/css"), name="css") | |
| app.mount("/js", StaticFiles(directory="static/js"), name="js") | |
| # Global state | |
| miner_instance: Optional[ParallelMiner] = None | |
| mining_thread: Optional[threading.Thread] = None | |
| is_mining: bool = False | |
| async def get_index(): | |
| """Serve the dashboard HTML""" | |
| return FileResponse("static/index.html") | |
| async def start_mining(): | |
| """Start the mining process""" | |
| global miner_instance, mining_thread, is_mining | |
| if is_mining: | |
| raise HTTPException(status_code=400, detail="Mining is already running") | |
| try: | |
| miner_instance = ParallelMiner(num_cores=5) | |
| miner_instance.mining = True | |
| is_mining = True | |
| # Start mining in background thread | |
| mining_thread = threading.Thread( | |
| target=miner_instance.start_mining, | |
| kwargs={"duration": None} | |
| ) | |
| mining_thread.daemon = True | |
| mining_thread.start() | |
| return {"message": "Mining started successfully"} | |
| except Exception as e: | |
| logging.error(f"Error starting mining: {e}") | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| async def stop_mining(): | |
| """Stop the mining process""" | |
| global miner_instance, is_mining | |
| if not is_mining: | |
| raise HTTPException(status_code=400, detail="Mining is not running") | |
| try: | |
| if miner_instance: | |
| # Log final stats | |
| logging.info("\n=== Final Mining Statistics ===") | |
| grand_total = 0 | |
| for core_idx, core in enumerate(miner_instance.cores): | |
| core_total = core.total_hashes | |
| grand_total += core_total | |
| logging.info(f"Core {core_idx}: {core_total:,} hashes") | |
| logging.info(f"Grand Total: {grand_total:,} hashes") | |
| logging.info(f"Overall Hashrate: {miner_instance.current_hashrate/1000:.2f} KH/s") | |
| logging.info(f"Blocks Found: {miner_instance.blocks_found}") | |
| logging.info("============================\n") | |
| miner_instance.mining = False | |
| is_mining = False | |
| return {"message": "Mining stopped successfully"} | |
| raise HTTPException(status_code=400, detail="No active mining instance") | |
| except Exception as e: | |
| logging.error(f"Error stopping mining: {e}") | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| async def get_mining_stats(): | |
| """Get current mining statistics""" | |
| global miner_instance, is_mining | |
| if not miner_instance or not is_mining: | |
| return { | |
| "status": "Stopped", | |
| "hashrate": "0 H/s", | |
| "total_hashes": "0", | |
| "blocks_found": "0", | |
| "best_hash": "None", | |
| "difficulty": "0", | |
| "block_alert": "Mining stopped" | |
| } | |
| # Create block alert message | |
| if miner_instance.blocks_found > 0: | |
| block_alert = f"π FOUND {miner_instance.blocks_found} BLOCK(S)! Last block hash: {miner_instance.best_hash.hex() if miner_instance.best_hash else 'None'}" | |
| else: | |
| progress = miner_instance.best_hash_difficulty * 100 if miner_instance.best_hash_difficulty else 0 | |
| block_alert = f"Mining in progress... Best hash difficulty: {progress:.8f}%" | |
| return { | |
| "status": "Running" if is_mining else "Stopped", | |
| "hashrate": f"{miner_instance.current_hashrate/1000:.2f} KH/s", | |
| "total_hashes": f"{miner_instance.total_hashes:,}", | |
| "blocks_found": str(miner_instance.blocks_found), | |
| "best_hash": miner_instance.best_hash.hex() if miner_instance.best_hash else "None", | |
| "difficulty": f"{miner_instance.best_hash_difficulty:,}", | |
| "block_alert": block_alert | |
| } | |
| processing_thread = None | |
| async def startup_event(): | |
| global processing_thread | |
| if not (processing_thread and processing_thread.is_alive()): | |
| processing_thread = threading.Thread(target=get_index()) | |
| processing_thread.daemon = True | |
| processing_thread.start() | |
| if __name__ == "__main__": | |
| uvicorn.run("app", host="0.0.0.0", port=7868, reload=False) |