Spaces:
Running
Running
| #!/usr/bin/env python3 | |
| """ | |
| external_server.py โ ุณูุฑูุฑ ู ุฑูุฒู ูุชูุฒูุน ุงูู ูุงู + Dashboard ุชูุงุนูู | |
| """ | |
| import logging | |
| import requests | |
| import socket | |
| from flask import Flask, request, jsonify, render_template | |
| from flask_cors import CORS | |
| from flask_socketio import SocketIO, emit | |
| from peer_discovery import PEERS | |
| from peer_discovery import PORT | |
| logging.basicConfig(level=logging.INFO) | |
| app = Flask(__name__) | |
| CORS(app, resources={r"/*": {"origins": "*"}}) | |
| socketio = SocketIO(app, cors_allowed_origins="*") | |
| connected_peers = {} # {node_id: {"cpu":%, "ram":%, "gpu":%}} | |
| # โโโโโโโโโโโโโโโ ุงูุชุญูู ู ู ุชููุฑ ุงูู ููุฐ โโโโโโโโโโโโโโโ | |
| def is_port_available(port): | |
| try: | |
| with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: | |
| s.bind(('0.0.0.0', port)) | |
| return True | |
| except OSError: | |
| return False | |
| # โโโโโโโโโโโโโโโ ุงุฎุชูุงุฑ ุฃูุถู Peer โโโโโโโโโโโโโโโ | |
| def select_best_peer(): | |
| if not PEERS: | |
| logging.warning("โ ๏ธ ูุง ุชูุฌุฏ ุฃุฌูุฒุฉ ู ุณุฌูุฉ ุญุงููุงู.") | |
| return None | |
| try: | |
| peer_loads = [] | |
| for peer_url in PEERS: | |
| try: | |
| # ุจูุงุก URL ููุญุต ุงูุญุงูุฉ | |
| status_url = peer_url.replace('/run_task', '/health') | |
| if '/run_task' not in peer_url: | |
| status_url = f"{peer_url}/health" | |
| resp = requests.get(status_url, timeout=2) | |
| if resp.ok: | |
| data = resp.json() | |
| # ุงูุชุฑุงุถ ุฃู ุงูุฎุงุฏู ูุนูุฏ cpu_load ุฃู ุงุณุชุฎุฏุงู ููู ุฉ ุงูุชุฑุงุถูุฉ | |
| cpu_load = data.get("cpu_load", 50) | |
| peer_loads.append((peer_url, cpu_load)) | |
| logging.info(f"โ {peer_url} - ุงูุญู ู: {cpu_load}%") | |
| except Exception as e: | |
| logging.warning(f"โ ูุง ูู ูู ุงููุตูู ุฅูู {peer_url}: {e}") | |
| continue | |
| if not peer_loads: | |
| return None | |
| # ุงุฎุชูุงุฑ ุงูุฃูู ุญู ููุง | |
| best_peer = min(peer_loads, key=lambda x: x[1]) | |
| logging.info(f"๐ฏ ุฃูุถู ุฌูุงุฒ: {best_peer[0]} ู ุน ุญู ู {best_peer[1]}%") | |
| return best_peer[0] | |
| except Exception as e: | |
| logging.error(f"โ ุฎุทุฃ ูู ุงุฎุชูุงุฑ ุงูู Peer: {e}") | |
| return None | |
| # โโโโโโโโโโโโโโโ API ุชูุฒูุน ุงูู ูุงู โโโโโโโโโโโโโโโ | |
| def submit_task(): | |
| data = request.get_json() | |
| if not data or "func" not in data: | |
| return jsonify({"error": "ูุฌุจ ุชุญุฏูุฏ ุงุณู ุงูุฏุงูุฉ (func)"}), 400 | |
| peer = select_best_peer() | |
| if not peer: | |
| return jsonify({"error": "ูุง ุชูุฌุฏ ุฃุฌูุฒุฉ ู ุชุงุญุฉ ุญุงููุงู"}), 503 | |
| try: | |
| # ุชุฃูุฏ ู ู ุฃู ุนููุงู ุงูู Peer ุตุญูุญ | |
| if not peer.startswith('http'): | |
| peer = f"http://{peer}" | |
| logging.info(f"๐ค ุฅุฑุณุงู ุงูู ูู ุฉ ุฅูู: {peer}") | |
| resp = requests.post(peer, json=data, timeout=30) | |
| if resp.ok: | |
| result = resp.json() | |
| logging.info(f"โ ุชู ุชูููุฐ ุงูู ูู ุฉ ุจูุฌุงุญ ุนูู {peer}") | |
| return jsonify({"status": "success", "result": result, "executed_on": peer}) | |
| else: | |
| logging.error(f"โ ูุดู ุชูููุฐ ุงูู ูู ุฉ ุนูู {peer}: {resp.status_code}") | |
| return jsonify({"error": f"ูุดู ุฅุฑุณุงู ุงูู ูู ุฉ: {resp.text}"}), 500 | |
| except requests.exceptions.Timeout: | |
| logging.error(f"โฐ ุงูุชูุช ุงูู ููุฉ ุฃุซูุงุก ุงูุงุชุตุงู ุจู {peer}") | |
| return jsonify({"error": "ุงูุชูุช ู ููุฉ ุงูุงุชุตุงู"}), 408 | |
| except Exception as e: | |
| logging.error(f"โ ุฎุทุฃ ูู ุฅุฑุณุงู ุงูู ูู ุฉ ุฅูู {peer}: {e}") | |
| return jsonify({"error": str(e)}), 500 | |
| # โโโโโโโโโโโโโโโ API ุชุญุฏูุซ ุญุงูุฉ ุงูุฃุฌูุฒุฉ โโโโโโโโโโโโโโโ | |
| def update_status(): | |
| data = request.json | |
| node_id = data.get("node_id") | |
| if not node_id: | |
| return jsonify({"error": "node_id ู ุทููุจ"}), 400 | |
| connected_peers[node_id] = { | |
| "cpu": data.get("cpu", 0), | |
| "ram": data.get("ram", 0), | |
| "gpu": data.get("gpu", 0), | |
| "last_update": "now" # ูู ูู ุฅุถุงูุฉ timestamp | |
| } | |
| socketio.emit("update_peers", connected_peers, broadcast=True) | |
| logging.info(f"๐ ุชู ุชุญุฏูุซ ุญุงูุฉ {node_id}") | |
| return jsonify({"status": "ok"}) | |
| # โโโโโโโโโโโโโโโ ุตูุญุฉ ุงูุญุงูุฉ โโโโโโโโโโโโโโโ | |
| def status(): | |
| return jsonify({ | |
| "connected_peers": connected_peers, | |
| "available_peers": list(PEERS), | |
| "total_peers": len(PEERS) | |
| }) | |
| # โโโโโโโโโโโโโโโ ุตูุญุฉ Dashboard โโโโโโโโโโโโโโโ | |
| def index(): | |
| return render_template("dashboard.html", peers=connected_peers) | |
| # โโโโโโโโโโโโโโโ ุงุณุชูุจุงู ุชุญุฏูุซุงุช ุงูุญุงูุฉ ุนุจุฑ WebSocket โโโโโโโโโโโโโโโ | |
| def handle_status_update(data): | |
| connected_peers.update(data) | |
| emit("update_peers", connected_peers, broadcast=True) | |
| # โโโโโโโโโโโโโโโ ุฏุฑุฏุดุฉ โโโโโโโโโโโโโโโ | |
| def handle_message(data): | |
| emit("receive_message", data, broadcast=True) | |
| # โโโโโโโโโโโโโโโ ุชุดุบูู ุงูุณูุฑูุฑ โโโโโโโโโโโโโโโ | |
| if __name__ == "__main__": | |
| # ู ุญุงููุฉ ู ูุงูุฐ ู ุฎุชููุฉ | |
| ports_to_try = [5005, 5006, 5007, 5008, 5009] | |
| selected_port = None | |
| for port in ports_to_try: | |
| if is_port_available(port): | |
| selected_port = port | |
| break | |
| if selected_port is None: | |
| logging.error("โ ูุง ุชูุฌุฏ ู ูุงูุฐ ู ุชุงุญุฉ. ุญุงูู ุฅุบูุงู ุงูุชุทุจููุงุช ุงูุฃุฎุฑู.") | |
| exit(1) | |
| logging.info(f"๐ ุจุฏุก ุงูุณูุฑูุฑ ุงูู ุฑูุฒู ู ุน Dashboard ุนูู ุงูู ููุฐ {selected_port}") | |
| try: | |
| socketio.run(app, host="0.0.0.0", port=selected_port, debug=False) | |
| except OSError as e: | |
| logging.error(f"โ ูุดู ุชุดุบูู ุงูุณูุฑูุฑ ุนูู ุงูู ููุฐ {selected_port}: {e}") | |
| except KeyboardInterrupt: | |
| logging.info("โน๏ธ ุฅููุงู ุงูุณูุฑูุฑ...") | |
| except Exception as e: | |
| logging.error(f"โ ุฎุทุฃ ุบูุฑ ู ุชููุน: {e}") | |