Spaces:
Running
Running
Upload 65 files
Browse files- DeviceManager.py +82 -82
- README_FIXES.md +61 -0
- autostart_config.py +1 -1
- background_service.py +1 -1
- central_manager.py +1 -1
- config.py +6 -9
- control.py +1 -3
- dashboard.py +60 -59
- distributed_executor.py +1 -1
- dts_cli.py +13 -51
- enhanced_assistant.py +1 -1
- external_server.py +98 -98
- internet_scanner.py +1 -1
- launcher.py +1 -1
- live_streaming.py +1 -1
- load_balancer.py +1 -1
- main.py +168 -347
- peer_discovery.py +61 -149
- peer_registry.py +1 -1
- peer_server.py +1 -1
- ram_manager.py +1 -1
- remote_executor.py +1 -1
- rpc_server.py +1 -1
- security_layer.py +1 -1
- server.py +1 -1
- smart_tasks.py +1 -1
- system_check.py +1 -1
- system_tray.py +1 -1
- task_splitter.py +1 -1
- test_distributed_system.py +1 -1
- test_monitor.py +1 -1
- video_processing.py +1 -1
- your_tasks.py +1 -1
DeviceManager.py
CHANGED
|
@@ -1,82 +1,82 @@
|
|
| 1 |
-
import subprocess
|
| 2 |
-
import GPUtil
|
| 3 |
-
import psutil
|
| 4 |
-
import logging
|
| 5 |
-
from peer_discovery import PORT
|
| 6 |
-
|
| 7 |
-
logging.getLogger().setLevel(logging.CRITICAL) # صامت
|
| 8 |
-
|
| 9 |
-
class DeviceManager:
|
| 10 |
-
def __init__(self):
|
| 11 |
-
self.devices = {
|
| 12 |
-
"GPU": self._detect_gpus(),
|
| 13 |
-
"DSP": self._detect_dsps(),
|
| 14 |
-
"NIC": self._detect_nics(),
|
| 15 |
-
"STORAGE": self._detect_storage(),
|
| 16 |
-
"CAPTURE": self._detect_capture(),
|
| 17 |
-
"ACCELERATOR": self._detect_accelerators()
|
| 18 |
-
}
|
| 19 |
-
|
| 20 |
-
# ────────────── اكتشاف الكروت ──────────────
|
| 21 |
-
def _detect_gpus(self):
|
| 22 |
-
try:
|
| 23 |
-
return GPUtil.getGPUs()
|
| 24 |
-
except:
|
| 25 |
-
return []
|
| 26 |
-
|
| 27 |
-
def _detect_dsps(self):
|
| 28 |
-
try:
|
| 29 |
-
output = subprocess.check_output(["aplay", "-l"], stderr=subprocess.DEVNULL).decode()
|
| 30 |
-
return ["DSP_Audio"] if "card" in output.lower() else []
|
| 31 |
-
except:
|
| 32 |
-
return []
|
| 33 |
-
|
| 34 |
-
def _detect_nics(self):
|
| 35 |
-
try:
|
| 36 |
-
return list(psutil.net_if_addrs().keys())
|
| 37 |
-
except:
|
| 38 |
-
return []
|
| 39 |
-
|
| 40 |
-
def _detect_storage(self):
|
| 41 |
-
try:
|
| 42 |
-
output = subprocess.check_output(["lsblk", "-o", "NAME"], stderr=subprocess.DEVNULL).decode()
|
| 43 |
-
return output.split() if output else []
|
| 44 |
-
except:
|
| 45 |
-
return []
|
| 46 |
-
|
| 47 |
-
def _detect_capture(self):
|
| 48 |
-
try:
|
| 49 |
-
output = subprocess.check_output(["v4l2-ctl", "--list-devices"], stderr=subprocess.DEVNULL).decode()
|
| 50 |
-
return output.split(":")[0::2] if output else []
|
| 51 |
-
except:
|
| 52 |
-
return []
|
| 53 |
-
|
| 54 |
-
def _detect_accelerators(self):
|
| 55 |
-
# افتراض: في المستقبل يمكن إضافة اكتشاف
|
| 56 |
-
return []
|
| 57 |
-
|
| 58 |
-
# ────────────── فحص الحمل ──────────────
|
| 59 |
-
def get_device_load(self, device_type, index=0):
|
| 60 |
-
try:
|
| 61 |
-
if device_type == "GPU" and self.devices["GPU"]:
|
| 62 |
-
return self.devices["GPU"][index].load * 100
|
| 63 |
-
elif device_type == "DSP" and self.devices["DSP"]:
|
| 64 |
-
return 10 # افتراضي: ما في API للحمل
|
| 65 |
-
elif device_type == "NIC" and self.devices["NIC"]:
|
| 66 |
-
return psutil.net_io_counters().bytes_sent / (1024 * 1024) # مثال بسيط
|
| 67 |
-
elif device_type == "STORAGE" and self.devices["STORAGE"]:
|
| 68 |
-
return psutil.disk_usage('/').percent
|
| 69 |
-
elif device_type == "CAPTURE" and self.devices["CAPTURE"]:
|
| 70 |
-
return 20 # افتراضي: حمل منخفض
|
| 71 |
-
elif device_type == "ACCELERATOR" and self.devices["ACCELERATOR"]:
|
| 72 |
-
return 15 # افتراضي
|
| 73 |
-
return 0
|
| 74 |
-
except:
|
| 75 |
-
return 0
|
| 76 |
-
|
| 77 |
-
# ────────────── منطق 30% / 70% ──────────────
|
| 78 |
-
def can_receive(self, device_type, index=0):
|
| 79 |
-
return self.get_device_load(device_type, index) <= 30
|
| 80 |
-
|
| 81 |
-
def should_offload(self, device_type, index=0):
|
| 82 |
-
return self.get_device_load(device_type, index) >= 70
|
|
|
|
| 1 |
+
import subprocess
|
| 2 |
+
import GPUtil
|
| 3 |
+
import psutil
|
| 4 |
+
import logging
|
| 5 |
+
from peer_discovery import PORT
|
| 6 |
+
|
| 7 |
+
logging.getLogger().setLevel(logging.CRITICAL) # صامت
|
| 8 |
+
|
| 9 |
+
class DeviceManager:
|
| 10 |
+
def __init__(self):
|
| 11 |
+
self.devices = {
|
| 12 |
+
"GPU": self._detect_gpus(),
|
| 13 |
+
"DSP": self._detect_dsps(),
|
| 14 |
+
"NIC": self._detect_nics(),
|
| 15 |
+
"STORAGE": self._detect_storage(),
|
| 16 |
+
"CAPTURE": self._detect_capture(),
|
| 17 |
+
"ACCELERATOR": self._detect_accelerators()
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
# ────────────── اكتشاف الكروت ──────────────
|
| 21 |
+
def _detect_gpus(self):
|
| 22 |
+
try:
|
| 23 |
+
return GPUtil.getGPUs()
|
| 24 |
+
except:
|
| 25 |
+
return []
|
| 26 |
+
|
| 27 |
+
def _detect_dsps(self):
|
| 28 |
+
try:
|
| 29 |
+
output = subprocess.check_output(["aplay", "-l"], stderr=subprocess.DEVNULL).decode()
|
| 30 |
+
return ["DSP_Audio"] if "card" in output.lower() else []
|
| 31 |
+
except:
|
| 32 |
+
return []
|
| 33 |
+
|
| 34 |
+
def _detect_nics(self):
|
| 35 |
+
try:
|
| 36 |
+
return list(psutil.net_if_addrs().keys())
|
| 37 |
+
except:
|
| 38 |
+
return []
|
| 39 |
+
|
| 40 |
+
def _detect_storage(self):
|
| 41 |
+
try:
|
| 42 |
+
output = subprocess.check_output(["lsblk", "-o", "NAME"], stderr=subprocess.DEVNULL).decode()
|
| 43 |
+
return output.split() if output else []
|
| 44 |
+
except:
|
| 45 |
+
return []
|
| 46 |
+
|
| 47 |
+
def _detect_capture(self):
|
| 48 |
+
try:
|
| 49 |
+
output = subprocess.check_output(["v4l2-ctl", "--list-devices"], stderr=subprocess.DEVNULL).decode()
|
| 50 |
+
return output.split(":")[0::2] if output else []
|
| 51 |
+
except:
|
| 52 |
+
return []
|
| 53 |
+
|
| 54 |
+
def _detect_accelerators(self):
|
| 55 |
+
# افتراض: في المستقبل يمكن إضافة اكتشاف ��قيقي لـ FPGA/TPU
|
| 56 |
+
return []
|
| 57 |
+
|
| 58 |
+
# ────────────── فحص الحمل ──────────────
|
| 59 |
+
def get_device_load(self, device_type, index=0):
|
| 60 |
+
try:
|
| 61 |
+
if device_type == "GPU" and self.devices["GPU"]:
|
| 62 |
+
return self.devices["GPU"][index].load * 100
|
| 63 |
+
elif device_type == "DSP" and self.devices["DSP"]:
|
| 64 |
+
return 10 # افتراضي: ما في API للحمل
|
| 65 |
+
elif device_type == "NIC" and self.devices["NIC"]:
|
| 66 |
+
return psutil.net_io_counters().bytes_sent / (1024 * 1024) # مثال بسيط
|
| 67 |
+
elif device_type == "STORAGE" and self.devices["STORAGE"]:
|
| 68 |
+
return psutil.disk_usage('/').percent
|
| 69 |
+
elif device_type == "CAPTURE" and self.devices["CAPTURE"]:
|
| 70 |
+
return 20 # افتراضي: حمل منخفض
|
| 71 |
+
elif device_type == "ACCELERATOR" and self.devices["ACCELERATOR"]:
|
| 72 |
+
return 15 # افتراضي
|
| 73 |
+
return 0
|
| 74 |
+
except:
|
| 75 |
+
return 0
|
| 76 |
+
|
| 77 |
+
# ────────────── منطق 30% / 70% ──────────────
|
| 78 |
+
def can_receive(self, device_type, index=0):
|
| 79 |
+
return self.get_device_load(device_type, index) <= 30
|
| 80 |
+
|
| 81 |
+
def should_offload(self, device_type, index=0):
|
| 82 |
+
return self.get_device_load(device_type, index) >= 70
|
README_FIXES.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# AmalOffload v6 — Fix Pack
|
| 2 |
+
|
| 3 |
+
تم إنشاء نسخة مُرقّعة من المشروع مع إصلاحات أساسية تمنع الأعطال الفورية وتسهّل التشغيل.
|
| 4 |
+
|
| 5 |
+
## ما الذي تم إصلاحه؟
|
| 6 |
+
- autostart_config.py: dedup import of PORT
|
| 7 |
+
- background_service.py: dedup import of PORT
|
| 8 |
+
- central_manager.py: dedup import of PORT
|
| 9 |
+
- control.py: dedup import of PORT
|
| 10 |
+
- dashboard.py: dedup import of PORT
|
| 11 |
+
- DeviceManager.py: dedup import of PORT
|
| 12 |
+
- distributed_executor.py: dedup import of PORT
|
| 13 |
+
- dts_cli.py: dedup import of PORT
|
| 14 |
+
- enhanced_assistant.py: dedup import of PORT
|
| 15 |
+
- external_server.py: dedup import of PORT
|
| 16 |
+
- internet_scanner.py: dedup import of PORT
|
| 17 |
+
- launcher.py: dedup import of PORT
|
| 18 |
+
- live_streaming.py: dedup import of PORT
|
| 19 |
+
- load_balancer.py: dedup import of PORT
|
| 20 |
+
- peer_registry.py: dedup import of PORT
|
| 21 |
+
- peer_server.py: dedup import of PORT
|
| 22 |
+
- remote_executor.py: dedup import of PORT
|
| 23 |
+
- rpc_server.py: dedup import of PORT
|
| 24 |
+
- security_layer.py: dedup import of PORT
|
| 25 |
+
- server.py: dedup import of PORT
|
| 26 |
+
- smart_tasks.py: dedup import of PORT
|
| 27 |
+
- system_check.py: dedup import of PORT
|
| 28 |
+
- system_tray.py: dedup import of PORT
|
| 29 |
+
- task_splitter.py: dedup import of PORT
|
| 30 |
+
- test_distributed_system.py: dedup import of PORT
|
| 31 |
+
- test_monitor.py: dedup import of PORT
|
| 32 |
+
- video_processing.py: dedup import of PORT
|
| 33 |
+
- your_tasks.py: dedup import of PORT
|
| 34 |
+
- control.py: fixed broken import line
|
| 35 |
+
- dts_cli.py: rewritten to a minimal, valid CLI
|
| 36 |
+
- ram_manager.py: removed BOM
|
| 37 |
+
- templates/dashboard.html: created from index.html
|
| 38 |
+
- config.py: added as a single source of truth for PORT
|
| 39 |
+
|
| 40 |
+
## توصيات إضافية (يدويّة)
|
| 41 |
+
- أضِف `fastapi` و`uvicorn` إلى `requirements.txt` إذا أردت تشغيل `central_manager.py` (يستخدم FastAPI).
|
| 42 |
+
- وحّد استيراد المنفذ عبر:
|
| 43 |
+
```python
|
| 44 |
+
from config import PORT
|
| 45 |
+
```
|
| 46 |
+
واستبدل أي استخدام لـ `from peer_discovery import PORT, PORT` أو `CPU_PORT` حسب الحاجة.
|
| 47 |
+
- إن ظهرت مشكلة `TemplateNotFound: dashboard.html` فقد تم إنشاء `templates/dashboard.html` تلقائياً.
|
| 48 |
+
- يُفضّل تنظيف `requirements.txt` من التكرارات (انظر التوصيات في تقرير التدقيق).
|
| 49 |
+
- اختر نقطة دخول واحدة للمشروع (مثلاً: `launcher.py` أو `startup.py`) وتجنّب تشغيل أكثر من خادم في نفس العملية.
|
| 50 |
+
|
| 51 |
+
## التشغيل السريع المقترح
|
| 52 |
+
1) ثبّت المتطلبات (الأساسية فقط):
|
| 53 |
+
```bash
|
| 54 |
+
pip install flask flask_cors flask_socketio requests psutil zeroconf cryptography numpy networkx GPUtil python-dotenv
|
| 55 |
+
```
|
| 56 |
+
2) شغّل الـ Dashboard وخادم RPC معاً:
|
| 57 |
+
```bash
|
| 58 |
+
python dts_cli.py start
|
| 59 |
+
```
|
| 60 |
+
|
| 61 |
+
بالتوفيق!
|
autostart_config.py
CHANGED
|
@@ -2,7 +2,7 @@ import json
|
|
| 2 |
import os
|
| 3 |
import platform
|
| 4 |
from pathlib import Path
|
| 5 |
-
from peer_discovery import PORT
|
| 6 |
|
| 7 |
class AutoStartManager:
|
| 8 |
def __init__(self, app_name="DistributedTaskSystem"):
|
|
|
|
| 2 |
import os
|
| 3 |
import platform
|
| 4 |
from pathlib import Path
|
| 5 |
+
from peer_discovery import PORT
|
| 6 |
|
| 7 |
class AutoStartManager:
|
| 8 |
def __init__(self, app_name="DistributedTaskSystem"):
|
background_service.py
CHANGED
|
@@ -16,7 +16,7 @@ from pathlib import Path
|
|
| 16 |
from flask import Flask, jsonify, request
|
| 17 |
import json
|
| 18 |
from datetime import datetime
|
| 19 |
-
from peer_discovery import PORT
|
| 20 |
|
| 21 |
class BackgroundService:
|
| 22 |
def __init__(self):
|
|
|
|
| 16 |
from flask import Flask, jsonify, request
|
| 17 |
import json
|
| 18 |
from datetime import datetime
|
| 19 |
+
from peer_discovery import PORT
|
| 20 |
|
| 21 |
class BackgroundService:
|
| 22 |
def __init__(self):
|
central_manager.py
CHANGED
|
@@ -8,7 +8,7 @@ from typing import Dict, List
|
|
| 8 |
import requests
|
| 9 |
from fastapi import FastAPI, HTTPException
|
| 10 |
from pydantic import BaseModel
|
| 11 |
-
from peer_discovery import PORT
|
| 12 |
|
| 13 |
# ---- إعداد FastAPI ----------------------------------------------------------
|
| 14 |
app = FastAPI(title="Central Task Manager")
|
|
|
|
| 8 |
import requests
|
| 9 |
from fastapi import FastAPI, HTTPException
|
| 10 |
from pydantic import BaseModel
|
| 11 |
+
from peer_discovery import PORT
|
| 12 |
|
| 13 |
# ---- إعداد FastAPI ----------------------------------------------------------
|
| 14 |
app = FastAPI(title="Central Task Manager")
|
config.py
CHANGED
|
@@ -1,10 +1,7 @@
|
|
| 1 |
-
# config.py
|
|
|
|
| 2 |
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
SYSTEM_PROMPT = """
|
| 8 |
-
أنت مساعد ذكاء اصطناعي يتحكم به المستخدم عبر أوامر صوتية وكتابية،
|
| 9 |
-
يجب أن تستجيب بسرعة، وبدقة، وتتعلم من التعليمات الجديدة.
|
| 10 |
-
"""
|
|
|
|
| 1 |
+
# config.py — نقطة مركزية لإعدادات المشروع
|
| 2 |
+
import os, random
|
| 3 |
|
| 4 |
+
# مصدر الحقيقة الوحيد لمنفذ الخدمة
|
| 5 |
+
PORT = int(os.getenv("CPU_PORT", os.getenv("PORT", "0")))
|
| 6 |
+
if PORT == 0:
|
| 7 |
+
PORT = random.randint(5000, 9999)
|
|
|
|
|
|
|
|
|
|
|
|
control.py
CHANGED
|
@@ -1,6 +1,4 @@
|
|
| 1 |
-
import
|
| 2 |
-
|
| 3 |
-
|
| 4 |
from autostart_config import AutoStartManager
|
| 5 |
|
| 6 |
def main():
|
|
|
|
| 1 |
+
import argparse
|
|
|
|
|
|
|
| 2 |
from autostart_config import AutoStartManager
|
| 3 |
|
| 4 |
def main():
|
dashboard.py
CHANGED
|
@@ -1,59 +1,60 @@
|
|
| 1 |
-
import logging
|
| 2 |
-
import socket
|
| 3 |
-
import threading
|
| 4 |
-
import psutil
|
| 5 |
-
import GPUtil
|
| 6 |
-
from flask import Flask, render_template
|
| 7 |
-
from flask_socketio import SocketIO, emit
|
| 8 |
-
from peer_discovery import PEERS
|
| 9 |
-
from peer_discovery import PORT
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
socketio.
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
|
|
|
|
|
| 1 |
+
import logging
|
| 2 |
+
import socket
|
| 3 |
+
import threading
|
| 4 |
+
import psutil
|
| 5 |
+
import GPUtil
|
| 6 |
+
from flask import Flask, render_template
|
| 7 |
+
from flask_socketio import SocketIO, emit
|
| 8 |
+
from peer_discovery import PEERS
|
| 9 |
+
from peer_discovery import PORT
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
logging.basicConfig(level=logging.INFO)
|
| 13 |
+
|
| 14 |
+
app = Flask(__name__)
|
| 15 |
+
socketio = SocketIO(app, cors_allowed_origins="*")
|
| 16 |
+
|
| 17 |
+
node_id = socket.gethostname()
|
| 18 |
+
connected_peers_data = {}
|
| 19 |
+
|
| 20 |
+
# ─────────────── جمع بيانات الحمل ───────────────
|
| 21 |
+
def get_system_status():
|
| 22 |
+
cpu = psutil.cpu_percent()
|
| 23 |
+
ram = psutil.virtual_memory().percent
|
| 24 |
+
gpu_load = 0
|
| 25 |
+
try:
|
| 26 |
+
gpus = GPUtil.getGPUs()
|
| 27 |
+
if gpus:
|
| 28 |
+
gpu_load = gpus[0].load * 100
|
| 29 |
+
except:
|
| 30 |
+
pass
|
| 31 |
+
return {"cpu": cpu, "ram": ram, "gpu": gpu_load}
|
| 32 |
+
|
| 33 |
+
# ─────────────── إرسال التحديثات ───────────────
|
| 34 |
+
def broadcast_status():
|
| 35 |
+
while True:
|
| 36 |
+
status = get_system_status()
|
| 37 |
+
socketio.emit("status_update", {node_id: status}, broadcast=True)
|
| 38 |
+
socketio.sleep(5)
|
| 39 |
+
|
| 40 |
+
# ─────────────── صفحة الواجهة ───────────────
|
| 41 |
+
@app.route("/")
|
| 42 |
+
def index():
|
| 43 |
+
return render_template("dashboard.html", peers=connected_peers_data)
|
| 44 |
+
|
| 45 |
+
# ─────────────── استقبال تحديثات الحالة ───────────────
|
| 46 |
+
@socketio.on("status_update")
|
| 47 |
+
def handle_status_update(data):
|
| 48 |
+
connected_peers_data.update(data)
|
| 49 |
+
emit("update_peers", connected_peers_data, broadcast=True)
|
| 50 |
+
|
| 51 |
+
# ─────────────── دردشة ───────────────
|
| 52 |
+
@socketio.on("send_message")
|
| 53 |
+
def handle_message(data):
|
| 54 |
+
emit("receive_message", data, broadcast=True)
|
| 55 |
+
|
| 56 |
+
# ─────────────── تشغيل ───────────────
|
| 57 |
+
if __name__ == "__main__":
|
| 58 |
+
threading.Thread(target=broadcast_status).start()
|
| 59 |
+
logging.info(f"🚀 تشغيل Dashboard على {node_id}")
|
| 60 |
+
socketio.run(app, host="0.0.0.0", port=7000)
|
distributed_executor.py
CHANGED
|
@@ -10,7 +10,7 @@ import subprocess
|
|
| 10 |
import psutil
|
| 11 |
import GPUtil
|
| 12 |
from processor_manager import ResourceMonitor
|
| 13 |
-
from peer_discovery import PORT
|
| 14 |
|
| 15 |
|
| 16 |
logging.basicConfig(level=logging.INFO)
|
|
|
|
| 10 |
import psutil
|
| 11 |
import GPUtil
|
| 12 |
from processor_manager import ResourceMonitor
|
| 13 |
+
from peer_discovery import PORT
|
| 14 |
|
| 15 |
|
| 16 |
logging.basicConfig(level=logging.INFO)
|
dts_cli.py
CHANGED
|
@@ -1,65 +1,27 @@
|
|
| 1 |
-
# dts_cli.py
|
| 2 |
import click
|
| 3 |
-
from dashboard import app
|
| 4 |
-
from rpc_server import app as rpc_app
|
| 5 |
import threading
|
| 6 |
-
from peer_discovery import
|
|
|
|
|
|
|
|
|
|
| 7 |
@click.group()
|
| 8 |
def cli():
|
| 9 |
pass
|
| 10 |
|
| 11 |
@cli.command()
|
| 12 |
def start():
|
| 13 |
-
"""بدء
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
)
|
| 20 |
-
dashboard_thread.daemon = True
|
| 21 |
-
dashboard_thread.start()
|
| 22 |
-
|
| 23 |
-
# تشغيل خادم RPC
|
| 24 |
-
rpc_app.run(host="0.0.0.0", port=PORT)
|
| 25 |
|
| 26 |
@cli.command()
|
| 27 |
-
from flask import Flask, render_template, request
|
| 28 |
-
|
| 29 |
-
# ... (الكود الحالي)
|
| 30 |
-
|
| 31 |
-
@flask_app.route("/")
|
| 32 |
-
def home():
|
| 33 |
-
tasks = {
|
| 34 |
-
"1": ("ضرب المصفوفات", "matrix"),
|
| 35 |
-
"2": ("حساب الأعداد الأولية", "prime"),
|
| 36 |
-
"3": ("معالجة البيانات", "data"),
|
| 37 |
-
}
|
| 38 |
-
return render_template("index.html", tasks=tasks)
|
| 39 |
-
|
| 40 |
-
@flask_app.route("/run_task", methods=["POST"])
|
| 41 |
-
def run_task():
|
| 42 |
-
task_id = request.form.get("task_id")
|
| 43 |
-
result = None
|
| 44 |
-
|
| 45 |
-
if task_id == "1":
|
| 46 |
-
result = matrix_multiply(500) # استبدل بمعاملاتك الفعلية
|
| 47 |
-
elif task_id == "2":
|
| 48 |
-
result = prime_calculation(100_000)
|
| 49 |
-
elif task_id == "3":
|
| 50 |
-
result = data_processing(10_000)
|
| 51 |
-
|
| 52 |
-
return render_template("index.html", tasks={
|
| 53 |
-
"1": ("ضرب المصفوفات", "matrix"),
|
| 54 |
-
"2": ("حساب الأعداد الأولية", "prime"),
|
| 55 |
-
"3": ("معالجة البيانات", "data"),
|
| 56 |
-
}, result=result)
|
| 57 |
def discover():
|
| 58 |
-
"""
|
| 59 |
-
|
| 60 |
-
peers = discover_peers()
|
| 61 |
-
print("الأجهزة المتصلة:")
|
| 62 |
-
for i, peer in enumerate(peers, 1):
|
| 63 |
print(f"{i}. {peer}")
|
| 64 |
|
| 65 |
if __name__ == "__main__":
|
|
|
|
| 1 |
+
# dts_cli.py — أوامر CLI لتشغيل النظام الموزع
|
| 2 |
import click
|
|
|
|
|
|
|
| 3 |
import threading
|
| 4 |
+
from peer_discovery import PEERS, PORT
|
| 5 |
+
import dashboard
|
| 6 |
+
import rpc_server
|
| 7 |
+
|
| 8 |
@click.group()
|
| 9 |
def cli():
|
| 10 |
pass
|
| 11 |
|
| 12 |
@cli.command()
|
| 13 |
def start():
|
| 14 |
+
"""بدء Dashboard وخادم RPC معاً"""
|
| 15 |
+
# شغّل الـ Dashboard في خيط منفصل
|
| 16 |
+
t = threading.Thread(target=lambda: dashboard.socketio.run(dashboard.app, host="0.0.0.0", port=7000), daemon=True)
|
| 17 |
+
t.start()
|
| 18 |
+
# شغّل خادم RPC في الخيط الرئيسي
|
| 19 |
+
rpc_server.app.run(host="0.0.0.0", port=PORT)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
|
| 21 |
@cli.command()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
def discover():
|
| 23 |
+
"""طباعة قائمة الأقران المكتشفة"""
|
| 24 |
+
for i, peer in enumerate(sorted(PEERS), 1):
|
|
|
|
|
|
|
|
|
|
| 25 |
print(f"{i}. {peer}")
|
| 26 |
|
| 27 |
if __name__ == "__main__":
|
enhanced_assistant.py
CHANGED
|
@@ -9,7 +9,7 @@ from PIL import Image
|
|
| 9 |
from io import BytesIO
|
| 10 |
import re
|
| 11 |
from datetime import datetime
|
| 12 |
-
from peer_discovery import PORT
|
| 13 |
|
| 14 |
class EnhancedNoraAssistant:
|
| 15 |
def __init__(self):
|
|
|
|
| 9 |
from io import BytesIO
|
| 10 |
import re
|
| 11 |
from datetime import datetime
|
| 12 |
+
from peer_discovery import PORT
|
| 13 |
|
| 14 |
class EnhancedNoraAssistant:
|
| 15 |
def __init__(self):
|
external_server.py
CHANGED
|
@@ -1,98 +1,98 @@
|
|
| 1 |
-
#!/usr/bin/env python3
|
| 2 |
-
"""
|
| 3 |
-
external_server.py — سيرفر مركزي لتوزيع المهام + Dashboard تفاعلي
|
| 4 |
-
"""
|
| 5 |
-
import logging
|
| 6 |
-
import requests
|
| 7 |
-
from flask import Flask, request, jsonify, render_template
|
| 8 |
-
from flask_cors import CORS
|
| 9 |
-
from flask_socketio import SocketIO, emit
|
| 10 |
-
from peer_discovery import PEERS
|
| 11 |
-
from peer_discovery import PORT
|
| 12 |
-
|
| 13 |
-
logging.basicConfig(level=logging.INFO)
|
| 14 |
-
|
| 15 |
-
app = Flask(__name__)
|
| 16 |
-
CORS(app, resources={r"/*": {"origins": "*"}})
|
| 17 |
-
socketio = SocketIO(app, cors_allowed_origins="*")
|
| 18 |
-
|
| 19 |
-
connected_peers = {} # {node_id: {"cpu":%, "ram":%, "gpu":%}}
|
| 20 |
-
|
| 21 |
-
# ─────────────── اختيار أفضل Peer ───────────────
|
| 22 |
-
def select_best_peer():
|
| 23 |
-
peers_list = list(PEERS)
|
| 24 |
-
if not peers_list:
|
| 25 |
-
logging.warning("⚠️ لا توجد أجهزة مسجلة حالياً.")
|
| 26 |
-
return None
|
| 27 |
-
|
| 28 |
-
try:
|
| 29 |
-
peer_loads = []
|
| 30 |
-
for peer_url in peers_list:
|
| 31 |
-
try:
|
| 32 |
-
resp = requests.get(f"{peer_url.replace('/run_task','')}/status", timeout=2)
|
| 33 |
-
if resp.ok:
|
| 34 |
-
data = resp.json()
|
| 35 |
-
peer_loads.append((peer_url, data.get("cpu_load", 100)))
|
| 36 |
-
except:
|
| 37 |
-
continue
|
| 38 |
-
|
| 39 |
-
if not peer_loads:
|
| 40 |
-
return None
|
| 41 |
-
|
| 42 |
-
peer_loads.sort(key=lambda x: x[1])
|
| 43 |
-
return peer_loads[0][0]
|
| 44 |
-
except Exception as e:
|
| 45 |
-
logging.error(f"❌ خطأ في اختيار الـ Peer: {e}")
|
| 46 |
-
return None
|
| 47 |
-
|
| 48 |
-
# ─────────────── API توزيع المهام ───────────────
|
| 49 |
-
@app.route("/submit_task", methods=["POST"])
|
| 50 |
-
def submit_task():
|
| 51 |
-
data = request.get_json()
|
| 52 |
-
if not data or "task_id" not in data:
|
| 53 |
-
return jsonify({"error": "يجب تحديد task_id"}), 400
|
| 54 |
-
|
| 55 |
-
peer = select_best_peer()
|
| 56 |
-
if not peer:
|
| 57 |
-
return jsonify({"error": "لا توجد أجهزة متاحة حالياً"}), 503
|
| 58 |
-
|
| 59 |
-
try:
|
| 60 |
-
resp = requests.post(peer, json=data, timeout=10)
|
| 61 |
-
if resp.ok:
|
| 62 |
-
return jsonify({"status": "success", "result": resp.json()})
|
| 63 |
-
else:
|
| 64 |
-
return jsonify({"error": "فشل إرسال المهمة"}), 500
|
| 65 |
-
except Exception as e:
|
| 66 |
-
logging.error(f"❌ خطأ في إرسال المهمة: {e}")
|
| 67 |
-
return jsonify({"error": str(e)}), 500
|
| 68 |
-
|
| 69 |
-
# ─────────────── API تحديث حالة الأجهزة ───────────────
|
| 70 |
-
@app.route("/update_status", methods=["POST"])
|
| 71 |
-
def update_status():
|
| 72 |
-
data = request.json
|
| 73 |
-
node_id = data.get("node_id")
|
| 74 |
-
if not node_id:
|
| 75 |
-
return jsonify({"error": "node_id مطلوب"}), 400
|
| 76 |
-
|
| 77 |
-
connected_peers[node_id] = {
|
| 78 |
-
"cpu": data.get("cpu"),
|
| 79 |
-
"ram": data.get("ram"),
|
| 80 |
-
"gpu": data.get("gpu")
|
| 81 |
-
}
|
| 82 |
-
socketio.emit("update_peers", connected_peers, broadcast=True)
|
| 83 |
-
return jsonify({"status": "ok"})
|
| 84 |
-
|
| 85 |
-
# ─────────────── صفحة Dashboard ───────────────
|
| 86 |
-
@app.route("/")
|
| 87 |
-
def index():
|
| 88 |
-
return render_template("dashboard.html")
|
| 89 |
-
|
| 90 |
-
# ─────────────── دردشة ───────────────
|
| 91 |
-
@socketio.on("send_message")
|
| 92 |
-
def handle_message(data):
|
| 93 |
-
socketio.emit("receive_message", data, broadcast=True)
|
| 94 |
-
|
| 95 |
-
# ─────────────── تشغيل السيرفر ───────────────
|
| 96 |
-
if __name__ == "__main__":
|
| 97 |
-
logging.info("🚀 بدء السيرفر المركزي مع Dashboard ودردشة")
|
| 98 |
-
socketio.run(app, host="0.0.0.0", port =5005)
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
external_server.py — سيرفر مركزي لتوزيع المهام + Dashboard تفاعلي
|
| 4 |
+
"""
|
| 5 |
+
import logging
|
| 6 |
+
import requests
|
| 7 |
+
from flask import Flask, request, jsonify, render_template
|
| 8 |
+
from flask_cors import CORS
|
| 9 |
+
from flask_socketio import SocketIO, emit
|
| 10 |
+
from peer_discovery import PEERS
|
| 11 |
+
from peer_discovery import PORT
|
| 12 |
+
|
| 13 |
+
logging.basicConfig(level=logging.INFO)
|
| 14 |
+
|
| 15 |
+
app = Flask(__name__)
|
| 16 |
+
CORS(app, resources={r"/*": {"origins": "*"}})
|
| 17 |
+
socketio = SocketIO(app, cors_allowed_origins="*")
|
| 18 |
+
|
| 19 |
+
connected_peers = {} # {node_id: {"cpu":%, "ram":%, "gpu":%}}
|
| 20 |
+
|
| 21 |
+
# ─────────────── اختيار أفضل Peer ───────────────
|
| 22 |
+
def select_best_peer():
|
| 23 |
+
peers_list = list(PEERS)
|
| 24 |
+
if not peers_list:
|
| 25 |
+
logging.warning("⚠️ لا توجد أجهزة مسجلة حالياً.")
|
| 26 |
+
return None
|
| 27 |
+
|
| 28 |
+
try:
|
| 29 |
+
peer_loads = []
|
| 30 |
+
for peer_url in peers_list:
|
| 31 |
+
try:
|
| 32 |
+
resp = requests.get(f"{peer_url.replace('/run_task','')}/status", timeout=2)
|
| 33 |
+
if resp.ok:
|
| 34 |
+
data = resp.json()
|
| 35 |
+
peer_loads.append((peer_url, data.get("cpu_load", 100)))
|
| 36 |
+
except:
|
| 37 |
+
continue
|
| 38 |
+
|
| 39 |
+
if not peer_loads:
|
| 40 |
+
return None
|
| 41 |
+
|
| 42 |
+
peer_loads.sort(key=lambda x: x[1])
|
| 43 |
+
return peer_loads[0][0]
|
| 44 |
+
except Exception as e:
|
| 45 |
+
logging.error(f"❌ خطأ في اختيار الـ Peer: {e}")
|
| 46 |
+
return None
|
| 47 |
+
|
| 48 |
+
# ─────────────── API توزيع المهام ───────────────
|
| 49 |
+
@app.route("/submit_task", methods=["POST"])
|
| 50 |
+
def submit_task():
|
| 51 |
+
data = request.get_json()
|
| 52 |
+
if not data or "task_id" not in data:
|
| 53 |
+
return jsonify({"error": "يجب تحديد task_id"}), 400
|
| 54 |
+
|
| 55 |
+
peer = select_best_peer()
|
| 56 |
+
if not peer:
|
| 57 |
+
return jsonify({"error": "لا توجد أجهزة متاحة حالياً"}), 503
|
| 58 |
+
|
| 59 |
+
try:
|
| 60 |
+
resp = requests.post(peer, json=data, timeout=10)
|
| 61 |
+
if resp.ok:
|
| 62 |
+
return jsonify({"status": "success", "result": resp.json()})
|
| 63 |
+
else:
|
| 64 |
+
return jsonify({"error": "فشل إرسال المهمة"}), 500
|
| 65 |
+
except Exception as e:
|
| 66 |
+
logging.error(f"❌ خطأ في إرسال المهمة: {e}")
|
| 67 |
+
return jsonify({"error": str(e)}), 500
|
| 68 |
+
|
| 69 |
+
# ─────────────── API تحديث حالة الأجهزة ───────────────
|
| 70 |
+
@app.route("/update_status", methods=["POST"])
|
| 71 |
+
def update_status():
|
| 72 |
+
data = request.json
|
| 73 |
+
node_id = data.get("node_id")
|
| 74 |
+
if not node_id:
|
| 75 |
+
return jsonify({"error": "node_id مطلوب"}), 400
|
| 76 |
+
|
| 77 |
+
connected_peers[node_id] = {
|
| 78 |
+
"cpu": data.get("cpu"),
|
| 79 |
+
"ram": data.get("ram"),
|
| 80 |
+
"gpu": data.get("gpu")
|
| 81 |
+
}
|
| 82 |
+
socketio.emit("update_peers", connected_peers, broadcast=True)
|
| 83 |
+
return jsonify({"status": "ok"})
|
| 84 |
+
|
| 85 |
+
# ─────────────── صفحة Dashboard ───────────────
|
| 86 |
+
@app.route("/")
|
| 87 |
+
def index():
|
| 88 |
+
return render_template("dashboard.html")
|
| 89 |
+
|
| 90 |
+
# ─────────────── دردشة ───────────────
|
| 91 |
+
@socketio.on("send_message")
|
| 92 |
+
def handle_message(data):
|
| 93 |
+
socketio.emit("receive_message", data, broadcast=True)
|
| 94 |
+
|
| 95 |
+
# ─────────────── تشغيل السيرفر ───────────────
|
| 96 |
+
if __name__ == "__main__":
|
| 97 |
+
logging.info("🚀 بدء السيرفر المركزي مع Dashboard ودردشة")
|
| 98 |
+
socketio.run(app, host="0.0.0.0", port =5005)
|
internet_scanner.py
CHANGED
|
@@ -8,7 +8,7 @@ import time
|
|
| 8 |
import socket
|
| 9 |
from concurrent.futures import ThreadPoolExecutor, as_completed
|
| 10 |
import logging
|
| 11 |
-
from peer_discovery import PORT
|
| 12 |
|
| 13 |
class InternetScanner:
|
| 14 |
def __init__(self):
|
|
|
|
| 8 |
import socket
|
| 9 |
from concurrent.futures import ThreadPoolExecutor, as_completed
|
| 10 |
import logging
|
| 11 |
+
from peer_discovery import PORT
|
| 12 |
|
| 13 |
class InternetScanner:
|
| 14 |
def __init__(self):
|
launcher.py
CHANGED
|
@@ -11,7 +11,7 @@ import subprocess
|
|
| 11 |
import argparse
|
| 12 |
import time
|
| 13 |
from pathlib import Path
|
| 14 |
-
from peer_discovery import PORT
|
| 15 |
|
| 16 |
def check_requirements():
|
| 17 |
"""فحص المتطلبات والاعتماديات"""
|
|
|
|
| 11 |
import argparse
|
| 12 |
import time
|
| 13 |
from pathlib import Path
|
| 14 |
+
from peer_discovery import PORT
|
| 15 |
|
| 16 |
def check_requirements():
|
| 17 |
"""فحص المتطلبات والاعتماديات"""
|
live_streaming.py
CHANGED
|
@@ -13,7 +13,7 @@ from datetime import datetime
|
|
| 13 |
from processor_manager import should_offload
|
| 14 |
from remote_executor import execute_remotely
|
| 15 |
from functools import wraps
|
| 16 |
-
from peer_discovery import PORT
|
| 17 |
|
| 18 |
logging.basicConfig(level=logging.INFO)
|
| 19 |
|
|
|
|
| 13 |
from processor_manager import should_offload
|
| 14 |
from remote_executor import execute_remotely
|
| 15 |
from functools import wraps
|
| 16 |
+
from peer_discovery import PORT
|
| 17 |
|
| 18 |
logging.basicConfig(level=logging.INFO)
|
| 19 |
|
load_balancer.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
# load_balancer.py
|
| 2 |
import peer_discovery, requests, time, smart_tasks, psutil, socket
|
| 3 |
-
from peer_discovery import PORT
|
| 4 |
|
| 5 |
def send(peer, func, *args, **kw):
|
| 6 |
try:
|
|
|
|
| 1 |
# load_balancer.py
|
| 2 |
import peer_discovery, requests, time, smart_tasks, psutil, socket
|
| 3 |
+
from peer_discovery import PORT
|
| 4 |
|
| 5 |
def send(peer, func, *args, **kw):
|
| 6 |
try:
|
main.py
CHANGED
|
@@ -1,9 +1,7 @@
|
|
| 1 |
#!/usr/bin/env python3
|
|
|
|
| 2 |
"""
|
| 3 |
-
main.py —
|
| 4 |
-
خيارات سطر الأوامر:
|
| 5 |
-
-s / --stats-interval ثواني بين كل طباعة لإحصائية الأقران (0 = مرة واحدة فقط)
|
| 6 |
-
--no-cli تشغيل بلا قائمة تفاعلية حتى مع وجود TTY
|
| 7 |
"""
|
| 8 |
import os
|
| 9 |
import sys
|
|
@@ -12,66 +10,19 @@ import threading
|
|
| 12 |
import subprocess
|
| 13 |
import logging
|
| 14 |
import argparse
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
from pathlib import Path
|
| 16 |
from typing import Any
|
| 17 |
-
|
| 18 |
from flask import Flask, request, jsonify
|
| 19 |
from flask_cors import CORS
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
def main():
|
| 23 |
-
# 1. تحميل وتشغيل peer_discovery.py أولاً
|
| 24 |
-
peer_module = load_and_run_peer_discovery()
|
| 25 |
-
|
| 26 |
-
if peer_module is None:
|
| 27 |
-
print("⚠️ سيستمر التشغيل بدون peer_discovery.py")
|
| 28 |
-
else:
|
| 29 |
-
# يمكنك الوصول إلى متغيرات ووظائف peer_discovery.py هنا
|
| 30 |
-
if hasattr(peer_module, 'CENTRAL_REGISTRY_SERVERS'):
|
| 31 |
-
print("السيرفرات المركزية:", peer_module.CENTRAL_REGISTRY_SERVERS)
|
| 32 |
-
|
| 33 |
-
# 2. متابعة تنفيذ باقي الوظائف
|
| 34 |
-
print("🚀 بدء تشغيل التطبيق الرئيسي...")
|
| 35 |
-
# ... باقي الكود
|
| 36 |
-
|
| 37 |
-
if __name__ == "__main__":
|
| 38 |
-
main()
|
| 39 |
-
|
| 40 |
-
# أو مباشرة:
|
| 41 |
-
# from peer_discovery import PORT as CPU_PORT
|
| 42 |
-
|
| 43 |
-
# تشغيل external_server.py تلقائيًا
|
| 44 |
-
import threading
|
| 45 |
-
|
| 46 |
-
def _start_peer_discovery():
|
| 47 |
-
"""
|
| 48 |
-
يستورد الموديول ويشغله.
|
| 49 |
-
إذا كان لديكم دالة معيّنة (مثلاً peer_discovery.main())
|
| 50 |
-
استدعِها داخل هذا الهدف بدل الاعتماد على كود if __name__ == '__main__'.
|
| 51 |
-
"""
|
| 52 |
-
import peer_discovery # تشغيل الموديول؛ معظم الأكواد تبدأ حلقة الخدمة عند الاستيراد
|
| 53 |
-
# أو مثلاً:
|
| 54 |
-
# peer_discovery.main()
|
| 55 |
-
from peer_discovery import PORT, PORT
|
| 56 |
-
import peer_discovery # يختار المنفذ ويضبطه مرّة واحدة
|
| 57 |
-
CPU_PORT = peer_discovery.PORT
|
| 58 |
-
|
| 59 |
-
# -- daemon=True يجعل الثريد يُغلق تلقائياً مع إيقاف البرنامج الرئيسي.
|
| 60 |
-
threading.Thread(target=_start_peer_discovery, daemon=True).start()
|
| 61 |
-
|
| 62 |
-
def start_external_server():
|
| 63 |
-
try:
|
| 64 |
-
logging.info("🚀 تشغيل external_server.py تلقائيًا...")
|
| 65 |
-
subprocess.Popen([sys.executable, os.path.join(os.getcwd(), "external_server.py")])
|
| 66 |
-
except Exception as e:
|
| 67 |
-
logging.error(f"❌ خطأ في تشغيل external_server.py: {e}")
|
| 68 |
-
|
| 69 |
-
# ─────────────── ضبط المسارات ───────────────
|
| 70 |
FILE = Path(__file__).resolve()
|
| 71 |
BASE_DIR = FILE.parent
|
| 72 |
-
|
| 73 |
-
for p in (BASE_DIR, PROJECT_ROOT):
|
| 74 |
-
sys.path.insert(0, str(p))
|
| 75 |
|
| 76 |
# ─────────────── إعداد السجلات ───────────────
|
| 77 |
os.makedirs("logs", exist_ok=True)
|
|
@@ -79,44 +30,26 @@ logging.basicConfig(
|
|
| 79 |
level=logging.INFO,
|
| 80 |
format="%(asctime)s - %(levelname)s - %(message)s",
|
| 81 |
handlers=[
|
| 82 |
-
logging.StreamHandler(),
|
| 83 |
-
logging.FileHandler("logs/main.log", mode="a")
|
| 84 |
]
|
| 85 |
)
|
| 86 |
|
| 87 |
-
# ─────────────── تحميل متغيرات البيئة
|
| 88 |
try:
|
| 89 |
from dotenv import load_dotenv
|
| 90 |
load_dotenv()
|
| 91 |
-
logging.info("
|
| 92 |
except ImportError:
|
| 93 |
-
logging.warning("
|
| 94 |
|
| 95 |
-
# ───────────────
|
| 96 |
-
|
| 97 |
-
from peer_discovery import (
|
| 98 |
-
register_service_lan,
|
| 99 |
-
discover_lan_loop,
|
| 100 |
-
register_with_central,
|
| 101 |
-
fetch_central_loop,
|
| 102 |
-
PEERS
|
| 103 |
-
)
|
| 104 |
-
from your_tasks import matrix_multiply, prime_calculation, data_processing
|
| 105 |
-
from distributed_executor import DistributedExecutor
|
| 106 |
-
from auto_offload import AutoOffloadExecutor
|
| 107 |
-
from peer_statistics import print_peer_statistics
|
| 108 |
-
from processor_manager import ResourceMonitor
|
| 109 |
-
except ImportError as e:
|
| 110 |
-
logging.error(f"❌ تعذّر استيراد وحدة: {e}")
|
| 111 |
-
sys.exit(1)
|
| 112 |
-
|
| 113 |
-
# ─────────────── ثابتات التهيئة ───────────────
|
| 114 |
-
CPU_PORT = int(os.getenv("CPU_PORT" ,"5297"))
|
| 115 |
SHARED_SECRET = os.getenv("SHARED_SECRET", "my_shared_secret_123")
|
| 116 |
PYTHON_EXE = sys.executable
|
| 117 |
|
| 118 |
# ─────────────── خيارات سطر الأوامر ───────────────
|
| 119 |
-
parser = argparse.ArgumentParser()
|
| 120 |
parser.add_argument(
|
| 121 |
"--stats-interval", "-s",
|
| 122 |
type=int,
|
|
@@ -130,6 +63,104 @@ parser.add_argument(
|
|
| 130 |
)
|
| 131 |
args = parser.parse_args()
|
| 132 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 133 |
# ─────────────── خادم Flask ───────────────
|
| 134 |
flask_app = Flask(__name__)
|
| 135 |
CORS(flask_app, resources={r"/*": {"origins": "*"}})
|
|
@@ -160,180 +191,25 @@ def run_task():
|
|
| 160 |
|
| 161 |
def start_flask_server():
|
| 162 |
ip_public = os.getenv("PUBLIC_IP", "127.0.0.1")
|
| 163 |
-
logging.info(f"
|
| 164 |
flask_app.run(host="0.0.0.0", port=CPU_PORT, debug=False)
|
| 165 |
|
| 166 |
-
# ───────────────
|
| 167 |
-
def start_services():
|
| 168 |
-
try:
|
| 169 |
-
subprocess.Popen([PYTHON_EXE, "peer_server.py", "--port", str(CPU_PORT)])
|
| 170 |
-
subprocess.Popen([PYTHON_EXE, "load_balancer.py"])
|
| 171 |
-
logging.info("✅ تم تشغيل الخدمات الخلفيّة")
|
| 172 |
-
except Exception as exc:
|
| 173 |
-
logging.error(f"❌ خطأ بتشغيل الخدمات الخلفية: {exc}")
|
| 174 |
-
|
| 175 |
-
# ─────────────── مهام مثالية محلية ───────────────
|
| 176 |
-
def example_task(x: int) -> int:
|
| 177 |
-
return x * x
|
| 178 |
-
|
| 179 |
-
def benchmark(fn, *args):
|
| 180 |
-
t0 = time.time()
|
| 181 |
-
res = fn(*args)
|
| 182 |
-
return time.time() - t0, res
|
| 183 |
-
|
| 184 |
-
# ─────────────── مراقبة الحمل التلقائية ───────────────
|
| 185 |
-
def auto_monitor(auto_executor):
|
| 186 |
-
while True:
|
| 187 |
-
try:
|
| 188 |
-
monitor = ResourceMonitor().current_load()
|
| 189 |
-
avg_cpu = monitor["average"]["cpu"]
|
| 190 |
-
avg_mem = monitor["average"]["mem_percent"] if "mem_percent" in monitor["average"] else 0
|
| 191 |
-
|
| 192 |
-
if avg_cpu > 0.7 or avg_mem > 85:
|
| 193 |
-
logging.info("⚠️ الحمل مرتفع - أوفلود تلقائي")
|
| 194 |
-
auto_executor.submit_auto(example_task, 42, task_type="video")
|
| 195 |
-
elif avg_cpu < 0.3:
|
| 196 |
-
logging.info("✅ الحمل منخفض - استقبال مهام")
|
| 197 |
-
time.sleep(5)
|
| 198 |
-
except Exception as e:
|
| 199 |
-
logging.error(f"خطأ في المراقبة التلقائية: {e}")
|
| 200 |
-
time.sleep(5)
|
| 201 |
-
import importlib.util
|
| 202 |
-
import sys
|
| 203 |
-
from pathlib import Path
|
| 204 |
-
import time
|
| 205 |
-
import requests
|
| 206 |
-
|
| 207 |
-
def load_and_connect_to_central_server(max_attempts=10, retry_delay=5):
|
| 208 |
-
"""
|
| 209 |
-
دالة محسنة لتحميل peer_discovery.py والمحاولة للاتصال بالسيرفر المركزي
|
| 210 |
-
حتى تنجح أو تصل إلى الحد الأقصى للمحاولات
|
| 211 |
-
|
| 212 |
-
Args:
|
| 213 |
-
max_attempts (int): الحد الأقصى لعدد المحاولات (0 للمحاولة إلى ما لا نهاية)
|
| 214 |
-
retry_delay (int): الوقت بين المحاولات بالثواني
|
| 215 |
-
"""
|
| 216 |
-
# 1. تحميل ملف peer_discovery.py أولاً
|
| 217 |
-
try:
|
| 218 |
-
peer_discovery_path = Path(__file__).parent / "peer_discovery.py"
|
| 219 |
-
|
| 220 |
-
if not peer_discovery_path.exists():
|
| 221 |
-
raise FileNotFoundError(f"ملف peer_discovery.py غير موجود في {peer_discovery_path.parent}")
|
| 222 |
-
|
| 223 |
-
spec = importlib.util.spec_from_file_location("peer_discovery_module", peer_discovery_path)
|
| 224 |
-
peer_module = importlib.util.module_from_spec(spec)
|
| 225 |
-
spec.loader.exec_module(peer_module)
|
| 226 |
-
|
| 227 |
-
print("✅ تم تحميل peer_discovery.py بنجاح")
|
| 228 |
-
except Exception as e:
|
| 229 |
-
print(f"❌ خطأ في تحميل peer_discovery.py: {str(e)}")
|
| 230 |
-
return None
|
| 231 |
-
|
| 232 |
-
# 2. المحاولة للاتصال بالسيرفر المركزي
|
| 233 |
-
attempt = 0
|
| 234 |
-
while True:
|
| 235 |
-
attempt += 1
|
| 236 |
-
try:
|
| 237 |
-
if not hasattr(peer_module, 'CENTRAL_REGISTRY_SERVERS'):
|
| 238 |
-
raise AttributeError("لا يوجد تعريف للسيرفرات المركزية في peer_discovery.py")
|
| 239 |
-
|
| 240 |
-
servers = peer_module.CENTRAL_REGISTRY_SERVERS
|
| 241 |
-
if not servers:
|
| 242 |
-
raise ValueError("قائمة السيرفرات المركزية فارغة")
|
| 243 |
-
|
| 244 |
-
# اختيار سيرفر عشوائي للمحاولة
|
| 245 |
-
selected_server = random.choice(servers)
|
| 246 |
-
|
| 247 |
-
print(f"🔌 محاولة الاتصال بالسيرفر المركزي ({attempt}): {selected_server}")
|
| 248 |
-
|
| 249 |
-
# مثال على طلب اتصال (يمكن تعديله حسب حاجتك)
|
| 250 |
-
response = requests.get(f"{selected_server}/ping", timeout=5)
|
| 251 |
-
response.raise_for_status()
|
| 252 |
-
|
| 253 |
-
print(f"✅ تم الاتصال بنجاح بالسيرفر: {selected_server}")
|
| 254 |
-
return peer_module
|
| 255 |
-
|
| 256 |
-
except Exception as e:
|
| 257 |
-
print(f"❌ فشل الاتصال: {str(e)}")
|
| 258 |
-
|
| 259 |
-
if max_attempts > 0 and attempt >= max_attempts:
|
| 260 |
-
print(f"⚠️ تم الوصول للحد الأقصى للمحاولات ({max_attempts})")
|
| 261 |
-
return None
|
| 262 |
-
|
| 263 |
-
print(f"↻ إعادة المحاولة بعد {retry_delay} ثواني...")
|
| 264 |
-
time.sleep(retry_delay)
|
| 265 |
-
# ─────────────── القائمة التفاعلية CLI ───────────────
|
| 266 |
-
def menu(executor: DistributedExecutor):
|
| 267 |
-
tasks = {
|
| 268 |
-
"1": ("ضرب المصفوفات", matrix_multiply, 500),
|
| 269 |
-
"2": ("حساب الأعداد الأولية", prime_calculation, 100_000),
|
| 270 |
-
"3": ("معالجة البيانات", data_processing, 10_000),
|
| 271 |
-
"5": ("مهمة موزعة (مثال)", example_task, 42),
|
| 272 |
-
}
|
| 273 |
-
|
| 274 |
-
while True:
|
| 275 |
-
print("\n🚀 نظام توزيع المهام الذكي")
|
| 276 |
-
for k, (title, _, _) in tasks.items():
|
| 277 |
-
print(f"{k}: {title}")
|
| 278 |
-
print("q: خروج")
|
| 279 |
-
choice = input("اختر المهمة: ").strip().lower()
|
| 280 |
-
|
| 281 |
-
if choice == "q":
|
| 282 |
-
print("🛑 تم إنهاء البرنامج.")
|
| 283 |
-
break
|
| 284 |
-
if choice not in tasks:
|
| 285 |
-
print("⚠️ اختيار غير صحيح.")
|
| 286 |
-
continue
|
| 287 |
-
|
| 288 |
-
name, fn, arg = tasks[choice]
|
| 289 |
-
print(f"\nتشغيل: {name}…")
|
| 290 |
-
|
| 291 |
-
try:
|
| 292 |
-
if choice == "5":
|
| 293 |
-
logging.info("📡 إرسال المهمة إلى العقد الموزَّعة…")
|
| 294 |
-
future = executor.submit(fn, arg)
|
| 295 |
-
print(f"✅ النتيجة (موزعة): {future.result()}")
|
| 296 |
-
else:
|
| 297 |
-
dur, res = benchmark(fn, arg)
|
| 298 |
-
print(f"✅ النتيجة: {res}\n⏱️ الوقت: {dur:.3f} ث")
|
| 299 |
-
except Exception as exc:
|
| 300 |
-
print(f"❌ خطأ في تنفيذ المهمة: {exc}")
|
| 301 |
-
def start_ram_manager(
|
| 302 |
-
ram_limit_mb: int = 2048,
|
| 303 |
-
chunk_mb: int = 64,
|
| 304 |
-
interval: int = 5,
|
| 305 |
-
port: int = 8765
|
| 306 |
-
):
|
| 307 |
-
"""
|
| 308 |
-
شغّل ram_manager كخيط داخل المشروع.
|
| 309 |
-
|
| 310 |
-
:param ram_limit_mb: الحد الأدنى للرام الحرّة قبل الترحيل
|
| 311 |
-
:param chunk_mb: حجم الكتلة المنقولة بالميغابايت
|
| 312 |
-
:param interval: زمن الانتظار بين كل فحص (ثانية)
|
| 313 |
-
:param port: البورت الذي يستمع عليه واجهة Flask
|
| 314 |
-
"""
|
| 315 |
-
# ضبط المتغيّرات البيئيّة بحيث يقرأها ram_manager.py
|
| 316 |
-
import os
|
| 317 |
-
os.environ["RAM_THRESHOLD_MB"] = str(ram_limit_mb)
|
| 318 |
-
os.environ["RAM_CHUNK_MB"] = str(chunk_mb)
|
| 319 |
-
os.environ["RAM_CHECK_INTERVAL"] = str(interval)
|
| 320 |
-
os.environ["RAM_PORT"] = str(port)
|
| 321 |
-
|
| 322 |
-
# استيراد الملف (يُنفَّذ كـموديول) مرة واحدة
|
| 323 |
-
ram_manager = importlib.import_module("ram_manager")
|
| 324 |
-
|
| 325 |
-
# تشغيله في خيط منفصل حتى لا يحجب main loop
|
| 326 |
-
threading.Thread(target=ram_manager.main, daemon=True).start()
|
| 327 |
-
print(f"[MAIN] ram_manager شغَّال على البورت {port}")
|
| 328 |
-
# --- أضِف الدالة الجديدة في أي مكان قبل main() -----------------
|
| 329 |
def connect_until_success():
|
| 330 |
-
|
| 331 |
-
|
| 332 |
-
|
| 333 |
-
|
| 334 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 335 |
while True:
|
| 336 |
-
for port in
|
| 337 |
for idx, server in enumerate(CENTRAL_REGISTRY_SERVERS):
|
| 338 |
info = {
|
| 339 |
"node_id": os.getenv("NODE_ID", socket.gethostname()),
|
|
@@ -341,110 +217,55 @@ def connect_until_success():
|
|
| 341 |
"port": port
|
| 342 |
}
|
| 343 |
try:
|
| 344 |
-
resp = requests.post(f"{server}/register",
|
| 345 |
-
|
| 346 |
-
|
| 347 |
-
PORT = port # ثبّت المنفذ النهائي
|
| 348 |
current_server_index = idx
|
| 349 |
-
|
| 350 |
-
|
| 351 |
-
|
| 352 |
-
|
| 353 |
-
|
| 354 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 355 |
|
| 356 |
def main():
|
| 357 |
-
|
| 358 |
-
|
| 359 |
-
|
| 360 |
-
|
| 361 |
-
|
| 362 |
-
|
| 363 |
-
|
| 364 |
-
|
| 365 |
-
server, peers = connect_until_success() # لا يخرج إلا عند النجاح
|
| 366 |
-
for p in peers: # أضف الأقران الأوليّين
|
| 367 |
-
peer_url = f"http://{p['ip']}:{p['port']}/run"
|
| 368 |
-
PEERS.add(peer_url)
|
| 369 |
|
| 370 |
-
#
|
| 371 |
-
|
|
|
|
|
|
|
|
|
|
| 372 |
|
|
|
|
| 373 |
try:
|
| 374 |
while True:
|
| 375 |
-
time.sleep(
|
| 376 |
except KeyboardInterrupt:
|
| 377 |
-
|
| 378 |
-
|
| 379 |
-
# ─────────────── الدالة الرئيسية ───────────────
|
| 380 |
-
def main():
|
| 381 |
-
# تشغيل external_server مع النظام
|
| 382 |
-
start_external_server()
|
| 383 |
-
|
| 384 |
-
start_services()
|
| 385 |
|
| 386 |
-
executor = DistributedExecutor(SHARED_SECRET)
|
| 387 |
-
auto_executor = AutoOffloadExecutor(executor)
|
| 388 |
-
executor.peer_registry.register_service("node_main", CPU_PORT)
|
| 389 |
-
|
| 390 |
-
for peer_url in list(PEERS):
|
| 391 |
-
try:
|
| 392 |
-
host, port_str = peer_url.split("//")[1].split("/run")[0].split(":")
|
| 393 |
-
executor.peer_registry.register_service(
|
| 394 |
-
f"peer_{host.replace('.', '_')}",
|
| 395 |
-
int(port_str)
|
| 396 |
-
)
|
| 397 |
-
except Exception as exc:
|
| 398 |
-
logging.warning(f"⚠️ تخطّي peer ({peer_url}): {exc}")
|
| 399 |
-
|
| 400 |
-
initial_peers = [
|
| 401 |
-
{"ip": host, "port": int(port)}
|
| 402 |
-
for peer_url in PEERS
|
| 403 |
-
if (hp := peer_url.split("//")[1].split("/run")[0]).count(":") == 1
|
| 404 |
-
for host, port in [hp.split(":")]
|
| 405 |
-
]
|
| 406 |
-
print_peer_statistics(initial_peers)
|
| 407 |
-
|
| 408 |
-
if args.stats_interval > 0:
|
| 409 |
-
threading.Thread(
|
| 410 |
-
target=stats_loop,
|
| 411 |
-
args=(args.stats_interval, executor),
|
| 412 |
-
daemon=True
|
| 413 |
-
).start()
|
| 414 |
-
|
| 415 |
-
logging.info("✅ النظام جاهز للعمل")
|
| 416 |
-
|
| 417 |
-
threading.Thread(target=auto_monitor, args=(auto_executor,), daemon=True).start()
|
| 418 |
-
|
| 419 |
-
if not args.no_cli and sys.stdin.isatty():
|
| 420 |
-
menu(executor)
|
| 421 |
-
else:
|
| 422 |
-
logging.info("ℹ️ القائمة التفاعلية معطّلة (no TTY أو --no-cli)")
|
| 423 |
-
|
| 424 |
-
# ─────────────── تشغيل البرنامج ───────────────
|
| 425 |
if __name__ == "__main__":
|
|
|
|
|
|
|
|
|
|
|
|
|
| 426 |
threading.Thread(target=register_service_lan, daemon=True).start()
|
| 427 |
threading.Thread(target=discover_lan_loop, daemon=True).start()
|
| 428 |
-
|
| 429 |
-
register_with_central()
|
| 430 |
threading.Thread(target=fetch_central_loop, daemon=True).start()
|
| 431 |
|
| 432 |
-
|
| 433 |
-
|
| 434 |
-
threading.Thread(
|
| 435 |
-
target=internet_scanner.start_continuous_scan,
|
| 436 |
-
daemon=True
|
| 437 |
-
).start()
|
| 438 |
-
logging.info("🔍 بدء المسح المستمر للإنترنت")
|
| 439 |
-
except ImportError:
|
| 440 |
-
logging.warning("🔍 internet_scanner غير متوافر – تم التخطي")
|
| 441 |
-
|
| 442 |
-
threading.Thread(target=start_flask_server, daemon=True).start()
|
| 443 |
-
|
| 444 |
-
try:
|
| 445 |
-
from your_control import control
|
| 446 |
-
control.start()
|
| 447 |
-
except ImportError:
|
| 448 |
-
logging.info("🛈 your_control غير متوفّر – تشغيل افتراضي")
|
| 449 |
-
|
| 450 |
-
main()
|
|
|
|
| 1 |
#!/usr/bin/env python3
|
| 2 |
+
# -*- coding: utf-8 -*-
|
| 3 |
"""
|
| 4 |
+
main.py — نظام توزيع المهام الذكي
|
|
|
|
|
|
|
|
|
|
| 5 |
"""
|
| 6 |
import os
|
| 7 |
import sys
|
|
|
|
| 10 |
import subprocess
|
| 11 |
import logging
|
| 12 |
import argparse
|
| 13 |
+
import socket
|
| 14 |
+
import random
|
| 15 |
+
import requests
|
| 16 |
+
import importlib.util
|
| 17 |
from pathlib import Path
|
| 18 |
from typing import Any
|
|
|
|
| 19 |
from flask import Flask, request, jsonify
|
| 20 |
from flask_cors import CORS
|
| 21 |
+
from peer_discovery import CENTRAL_REGISTRY_SERVERS
|
| 22 |
+
# ─────────────── إعدادات المسارات ───────────────
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
FILE = Path(__file__).resolve()
|
| 24 |
BASE_DIR = FILE.parent
|
| 25 |
+
sys.path.insert(0, str(BASE_DIR))
|
|
|
|
|
|
|
| 26 |
|
| 27 |
# ─────────────── إعداد السجلات ───────────────
|
| 28 |
os.makedirs("logs", exist_ok=True)
|
|
|
|
| 30 |
level=logging.INFO,
|
| 31 |
format="%(asctime)s - %(levelname)s - %(message)s",
|
| 32 |
handlers=[
|
| 33 |
+
logging.StreamHandler(sys.stdout),
|
| 34 |
+
logging.FileHandler("logs/main.log", mode="a", encoding="utf-8")
|
| 35 |
]
|
| 36 |
)
|
| 37 |
|
| 38 |
+
# ─────────────── تحميل متغيرات البيئة ───────────────
|
| 39 |
try:
|
| 40 |
from dotenv import load_dotenv
|
| 41 |
load_dotenv()
|
| 42 |
+
logging.info("تم تحميل متغيرات البيئة من .env")
|
| 43 |
except ImportError:
|
| 44 |
+
logging.warning("python-dotenv غير مثبَّت؛ تَخطّي .env")
|
| 45 |
|
| 46 |
+
# ─────────────── ثوابت التهيئة ───────────────
|
| 47 |
+
CPU_PORT = int(os.getenv("CPU_PORT", "5297"))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
SHARED_SECRET = os.getenv("SHARED_SECRET", "my_shared_secret_123")
|
| 49 |
PYTHON_EXE = sys.executable
|
| 50 |
|
| 51 |
# ─────────────── خيارات سطر الأوامر ───────────────
|
| 52 |
+
parser = argparse.ArgumentParser(description="نظام توزيع المهام الذكي")
|
| 53 |
parser.add_argument(
|
| 54 |
"--stats-interval", "-s",
|
| 55 |
type=int,
|
|
|
|
| 63 |
)
|
| 64 |
args = parser.parse_args()
|
| 65 |
|
| 66 |
+
# ─────────────── متغيرات النظام ───────────────
|
| 67 |
+
PEERS = set() # مجموعة عناوين الأقران كسلاسل نصية
|
| 68 |
+
PEERS_INFO = {} # قاموس لحفظ معلومات الأقران الكاملة
|
| 69 |
+
current_server_index = 0
|
| 70 |
+
|
| 71 |
+
# ─────────────── دوال اكتشاف الأقران ───────────────
|
| 72 |
+
def register_service_lan():
|
| 73 |
+
"""تسجيل الخدمة على الشبكة المحلية"""
|
| 74 |
+
while True:
|
| 75 |
+
try:
|
| 76 |
+
logging.info("جارٍ تسجيل الخدمة على الشبكة المحلية...")
|
| 77 |
+
time.sleep(10)
|
| 78 |
+
except Exception as e:
|
| 79 |
+
logging.error(f"خطأ في تسجيل الخدمة: {e}")
|
| 80 |
+
|
| 81 |
+
def discover_lan_loop():
|
| 82 |
+
"""اكتشاف الأقران على الشبكة المحلية"""
|
| 83 |
+
while True:
|
| 84 |
+
try:
|
| 85 |
+
logging.info("جارٍ مسح الشبكة المحلية...")
|
| 86 |
+
time.sleep(15)
|
| 87 |
+
except Exception as e:
|
| 88 |
+
logging.error(f"خطأ في اكتشاف الأقران: {e}")
|
| 89 |
+
|
| 90 |
+
def fetch_central_loop():
|
| 91 |
+
"""جلب تحديثات من السيرفر المركزي"""
|
| 92 |
+
while True:
|
| 93 |
+
try:
|
| 94 |
+
logging.info("جارٍ تحديث قائمة الأقران...")
|
| 95 |
+
time.sleep(30)
|
| 96 |
+
except Exception as e:
|
| 97 |
+
logging.error(f"خطأ في جلب التحديثات: {e}")
|
| 98 |
+
|
| 99 |
+
# ─────────────── دوال مساعدة ───────────────
|
| 100 |
+
def get_local_ip():
|
| 101 |
+
"""الحصول على عنوان IP المحلي"""
|
| 102 |
+
try:
|
| 103 |
+
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
| 104 |
+
s.connect(("8.8.8.8", 80))
|
| 105 |
+
ip = s.getsockname()[0]
|
| 106 |
+
s.close()
|
| 107 |
+
return ip
|
| 108 |
+
except Exception:
|
| 109 |
+
return "127.0.0.1"
|
| 110 |
+
|
| 111 |
+
def add_peer(peer_data):
|
| 112 |
+
"""إضافة قرين جديد إلى النظام"""
|
| 113 |
+
peer_url = f"http://{peer_data['ip']}:{peer_data['port']}/run"
|
| 114 |
+
if peer_url not in PEERS:
|
| 115 |
+
PEERS.add(peer_url)
|
| 116 |
+
PEERS_INFO[peer_url] = peer_data
|
| 117 |
+
logging.info(f"تمت إضافة قرين جديد: {peer_url}")
|
| 118 |
+
return peer_url
|
| 119 |
+
|
| 120 |
+
def benchmark(fn, *args):
|
| 121 |
+
"""قياس زمن تنفيذ الدالة"""
|
| 122 |
+
t0 = time.time()
|
| 123 |
+
res = fn(*args)
|
| 124 |
+
return time.time() - t0, res
|
| 125 |
+
|
| 126 |
+
def load_and_run_peer_discovery():
|
| 127 |
+
"""تحميل وتشغيل ملف peer_discovery.py"""
|
| 128 |
+
try:
|
| 129 |
+
peer_discovery_path = Path(__file__).parent / "peer_discovery.py"
|
| 130 |
+
if not peer_discovery_path.exists():
|
| 131 |
+
raise FileNotFoundError("ملف peer_discovery.py غير موجود")
|
| 132 |
+
|
| 133 |
+
spec = importlib.util.spec_from_file_location("peer_discovery_module", peer_discovery_path)
|
| 134 |
+
peer_module = importlib.util.module_from_spec(spec)
|
| 135 |
+
spec.loader.exec_module(peer_module)
|
| 136 |
+
|
| 137 |
+
logging.info("تم تحميل peer_discovery.py بنجاح")
|
| 138 |
+
return peer_module
|
| 139 |
+
except Exception as e:
|
| 140 |
+
logging.error(f"خطأ في تحميل peer_discovery.py: {str(e)}")
|
| 141 |
+
return None
|
| 142 |
+
|
| 143 |
+
# ─────────────── دوال المهام ───────────────
|
| 144 |
+
def example_task(x: int) -> int:
|
| 145 |
+
"""دالة مثال بديلة إذا لم تكن موجودة في your_tasks.py"""
|
| 146 |
+
return x * x
|
| 147 |
+
|
| 148 |
+
def matrix_multiply(size: int) -> list:
|
| 149 |
+
"""ضرب المصفوفات (بديل مؤقت)"""
|
| 150 |
+
return [[i*j for j in range(size)] for i in range(size)]
|
| 151 |
+
|
| 152 |
+
def prime_calculation(limit: int) -> list:
|
| 153 |
+
"""حساب الأعداد الأولية (بديل مؤقت)"""
|
| 154 |
+
primes = []
|
| 155 |
+
for num in range(2, limit):
|
| 156 |
+
if all(num % i != 0 for i in range(2, int(num**0.5) + 1)):
|
| 157 |
+
primes.append(num)
|
| 158 |
+
return primes
|
| 159 |
+
|
| 160 |
+
def data_processing(size: int) -> dict:
|
| 161 |
+
"""معالجة البيانات (بديل مؤقت)"""
|
| 162 |
+
return {i: i**2 for i in range(size)}
|
| 163 |
+
|
| 164 |
# ─────────────── خادم Flask ───────────────
|
| 165 |
flask_app = Flask(__name__)
|
| 166 |
CORS(flask_app, resources={r"/*": {"origins": "*"}})
|
|
|
|
| 191 |
|
| 192 |
def start_flask_server():
|
| 193 |
ip_public = os.getenv("PUBLIC_IP", "127.0.0.1")
|
| 194 |
+
logging.info(f"Flask متوفر على: http://{ip_public}:{CPU_PORT}/run_task")
|
| 195 |
flask_app.run(host="0.0.0.0", port=CPU_PORT, debug=False)
|
| 196 |
|
| 197 |
+
# ─────────────── دوال النظام الأساسية ───────────────
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 198 |
def connect_until_success():
|
| 199 |
+
global CPU_PORT, current_server_index
|
| 200 |
+
|
| 201 |
+
peer_module = load_and_run_peer_discovery()
|
| 202 |
+
if peer_module is None:
|
| 203 |
+
logging.warning("سيستمر التشغيل بدون peer_discovery.py")
|
| 204 |
+
return None, []
|
| 205 |
+
|
| 206 |
+
CENTRAL_REGISTRY_SERVERS = getattr(peer_module, 'CENTRAL_REGISTRY_SERVERS', [])
|
| 207 |
+
if not CENTRAL_REGISTRY_SERVERS:
|
| 208 |
+
logging.error("قائمة السيرفرات المركزية فارغة")
|
| 209 |
+
return None, []
|
| 210 |
+
|
| 211 |
while True:
|
| 212 |
+
for port in [CPU_PORT, 5298, 5299]:
|
| 213 |
for idx, server in enumerate(CENTRAL_REGISTRY_SERVERS):
|
| 214 |
info = {
|
| 215 |
"node_id": os.getenv("NODE_ID", socket.gethostname()),
|
|
|
|
| 217 |
"port": port
|
| 218 |
}
|
| 219 |
try:
|
| 220 |
+
resp = requests.post(f"{server}/register", json=info, timeout=5)
|
| 221 |
+
resp.raise_for_status()
|
| 222 |
+
CPU_PORT = port
|
|
|
|
| 223 |
current_server_index = idx
|
| 224 |
+
logging.info(f"تم الاتصال بالسيرفر: {server} على المنفذ {CPU_PORT}")
|
| 225 |
+
|
| 226 |
+
# معالجة قائمة الأقران المستلمة
|
| 227 |
+
peers_list = resp.json()
|
| 228 |
+
peer_urls = []
|
| 229 |
+
for p in peers_list:
|
| 230 |
+
peer_url = add_peer(p)
|
| 231 |
+
peer_urls.append(peer_url)
|
| 232 |
+
return server, peer_urls
|
| 233 |
+
|
| 234 |
+
except Exception as e:
|
| 235 |
+
logging.warning(f"فشل الاتصال بـ {server}: {str(e)}")
|
| 236 |
+
time.sleep(5)
|
| 237 |
|
| 238 |
def main():
|
| 239 |
+
"""الدالة الرئيسية لتشغيل النظام"""
|
| 240 |
+
# تشغيل الخدمات الأساسية
|
| 241 |
+
try:
|
| 242 |
+
subprocess.Popen([PYTHON_EXE, "peer_server.py", "--port", str(CPU_PORT)])
|
| 243 |
+
subprocess.Popen([PYTHON_EXE, "load_balancer.py"])
|
| 244 |
+
logging.info("تم تشغيل الخدمات الخلفيّة")
|
| 245 |
+
except Exception as exc:
|
| 246 |
+
logging.error(f"خطأ بتشغيل الخدمات الخلفية: {exc}")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 247 |
|
| 248 |
+
# الاتصال بالسيرفر المركزي
|
| 249 |
+
server, initial_peers = connect_until_success()
|
| 250 |
+
|
| 251 |
+
# تشغيل خادم Flask
|
| 252 |
+
threading.Thread(target=start_flask_server, daemon=True).start()
|
| 253 |
|
| 254 |
+
# البقاء في حلقة رئيسية
|
| 255 |
try:
|
| 256 |
while True:
|
| 257 |
+
time.sleep(1)
|
| 258 |
except KeyboardInterrupt:
|
| 259 |
+
logging.info("تم إنهاء البرنامج.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 260 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 261 |
if __name__ == "__main__":
|
| 262 |
+
# إضافة القرين المحلي
|
| 263 |
+
add_peer({"ip": "127.0.0.1", "port": CPU_PORT})
|
| 264 |
+
|
| 265 |
+
# تشغيل خدمات اكتشاف الأقران
|
| 266 |
threading.Thread(target=register_service_lan, daemon=True).start()
|
| 267 |
threading.Thread(target=discover_lan_loop, daemon=True).start()
|
|
|
|
|
|
|
| 268 |
threading.Thread(target=fetch_central_loop, daemon=True).start()
|
| 269 |
|
| 270 |
+
# بدء النظام الرئيسي
|
| 271 |
+
main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
peer_discovery.py
CHANGED
|
@@ -8,168 +8,80 @@ import requests
|
|
| 8 |
from zeroconf import Zeroconf, ServiceInfo, ServiceBrowser
|
| 9 |
import random
|
| 10 |
|
| 11 |
-
#
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
CONNECTED = threading.Event()
|
| 15 |
-
PEERS = set()
|
| 16 |
|
|
|
|
|
|
|
| 17 |
SERVICE = "_tasknode._tcp.local."
|
| 18 |
-
|
|
|
|
| 19 |
|
| 20 |
-
#
|
| 21 |
-
|
| 22 |
"https://cv4790811.regru.cloud",
|
| 23 |
"https://amaloffload.onrender.com",
|
| 24 |
"https://osamabyc86-offload.hf.space",
|
| 25 |
-
"
|
| 26 |
-
"
|
|
|
|
| 27 |
]
|
| 28 |
|
| 29 |
-
RPORTS = [f"{i:04}" for i in range(1, 10000)]
|
| 30 |
-
CENTRAL_REGISTRY_SERVERS = [f"{base}:{port}" for base in BASES for port in RPORTS]
|
| 31 |
-
current_server_index = 0
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
# 🟢 الحصول على IP العام أو المحلي
|
| 35 |
def get_local_ip():
|
| 36 |
try:
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
|
|
|
|
|
|
| 40 |
except Exception:
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
# ❶ تسجيل الخدمة في شبكة LAN
|
| 68 |
-
def register_service_lan():
|
| 69 |
-
zc = Zeroconf()
|
| 70 |
-
local_ip = get_local_ip()
|
| 71 |
info = ServiceInfo(
|
| 72 |
SERVICE,
|
| 73 |
f"{socket.gethostname()}.{SERVICE}",
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
properties={b'
|
| 77 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
try:
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
ip = socket.inet_ntoa(info.addresses[0])
|
| 91 |
-
peer_url = f"http://{ip}:{info.port}/run"
|
| 92 |
-
if peer_url not in PEERS:
|
| 93 |
-
PEERS.add(peer_url)
|
| 94 |
-
print(f"🔗 LAN peer discovered: {peer_url}")
|
| 95 |
-
def update_service(self, zc, t, name):
|
| 96 |
-
self.add_service(zc, t, name)
|
| 97 |
-
def remove_service(self, zc, t, name):
|
| 98 |
-
print(f"❌ LAN peer removed: {name}")
|
| 99 |
-
|
| 100 |
-
def discover_lan_loop():
|
| 101 |
-
zc = Zeroconf()
|
| 102 |
-
ServiceBrowser(zc, SERVICE, Listener())
|
| 103 |
-
print(f"🔍 Started LAN discovery for {SERVICE}")
|
| 104 |
-
while True:
|
| 105 |
-
time.sleep(5)
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
# ❸ الاتصال بسيرفر مركزي (مع محاولات حتى النجاح)
|
| 109 |
-
def connect_until_success():
|
| 110 |
-
"""
|
| 111 |
-
يحاول الاتصال بكل سيرفر وبورت با��تسلسل، ويتوقف عند أول نجاح
|
| 112 |
-
ويضبط PORT وCONNECTED وCENTRAL_REGISTRY
|
| 113 |
-
"""
|
| 114 |
-
global PORT, current_server_index, CURRENT_SERVER
|
| 115 |
-
|
| 116 |
-
for port_int in range(1, 10000):
|
| 117 |
-
port = f"{port_int:04}"
|
| 118 |
-
for idx, server_base in enumerate(BASES):
|
| 119 |
-
server = f"{server_base}:{port}"
|
| 120 |
-
info = {
|
| 121 |
-
"node_id": os.getenv("NODE_ID", socket.gethostname()),
|
| 122 |
-
"ip": get_local_ip(),
|
| 123 |
-
"port": int(port)
|
| 124 |
-
}
|
| 125 |
-
try:
|
| 126 |
-
resp = requests.post(f"{server}/register", json=info, timeout=5)
|
| 127 |
-
resp.raise_for_status()
|
| 128 |
-
PORT = int(port)
|
| 129 |
-
CURRENT_SERVER = server
|
| 130 |
-
current_server_index = idx
|
| 131 |
-
CONNECTED.set()
|
| 132 |
-
print(f"✅ Connected: {server} on port {PORT}")
|
| 133 |
-
peers = resp.json()
|
| 134 |
-
for p in peers:
|
| 135 |
-
peer_url = f"http://{p['ip']}:{p['port']}/run"
|
| 136 |
-
if peer_url not in PEERS:
|
| 137 |
-
PEERS.add(peer_url)
|
| 138 |
-
print(f"🌐 Central peer: {peer_url}")
|
| 139 |
-
return
|
| 140 |
-
except Exception as e:
|
| 141 |
-
logging.info("❌ %s:%s -> %s", server_base, port, e)
|
| 142 |
-
time.sleep(0.1)
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
# ❹ مزامنة مستمرة مع السيرفر المركزي
|
| 146 |
-
def fetch_central_loop():
|
| 147 |
-
print("🔄 Central registry sync loop started")
|
| 148 |
-
while True:
|
| 149 |
-
if not CONNECTED.is_set():
|
| 150 |
-
time.sleep(5)
|
| 151 |
-
continue
|
| 152 |
-
try:
|
| 153 |
-
resp = requests.get(f"{CURRENT_SERVER}/peers", timeout=5)
|
| 154 |
-
resp.raise_for_status()
|
| 155 |
-
peers_list = resp.json()
|
| 156 |
-
for p in peers_list:
|
| 157 |
-
peer_url = f"http://{p['ip']}:{p['port']}/run"
|
| 158 |
-
if peer_url not in PEERS:
|
| 159 |
-
PEERS.add(peer_url)
|
| 160 |
-
print(f"🌐 Central peer discovered: {peer_url}")
|
| 161 |
-
except Exception as e:
|
| 162 |
-
print(f"⚠️ Fetch central peers failed: {e}")
|
| 163 |
-
time.sleep(300)
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
# 🚀 تشغيل تلقائي عند الاستيراد
|
| 167 |
-
def _start():
|
| 168 |
-
if not CONNECTED.is_set():
|
| 169 |
-
print("🚀 Starting peer discovery...")
|
| 170 |
-
connect_until_success()
|
| 171 |
-
threading.Thread(target=register_service_lan, daemon=True).start()
|
| 172 |
-
threading.Thread(target=discover_lan_loop, daemon=True).start()
|
| 173 |
-
threading.Thread(target=fetch_central_loop, daemon=True).start()
|
| 174 |
-
|
| 175 |
-
_start() # ← تشغيل تلقائي
|
|
|
|
| 8 |
from zeroconf import Zeroconf, ServiceInfo, ServiceBrowser
|
| 9 |
import random
|
| 10 |
|
| 11 |
+
# إعداد السجلات
|
| 12 |
+
logging.basicConfig(level=logging.INFO)
|
| 13 |
+
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
| 14 |
|
| 15 |
+
# منفذ الخدمة
|
| 16 |
+
PORT = int(os.getenv("CPU_PORT", random.randint(1000, 9999)))
|
| 17 |
SERVICE = "_tasknode._tcp.local."
|
| 18 |
+
PEERS = set() # مجموعة عناوين الأقران كسلاسل نصية
|
| 19 |
+
PEERS_INFO = {} # معلومات إضافية عن الأقران
|
| 20 |
|
| 21 |
+
# قائمة السيرفرات المركزية
|
| 22 |
+
CENTRAL_REGISTRY_SERVERS = [
|
| 23 |
"https://cv4790811.regru.cloud",
|
| 24 |
"https://amaloffload.onrender.com",
|
| 25 |
"https://osamabyc86-offload.hf.space",
|
| 26 |
+
"https://huggingface.co/spaces/osamabyc19866/omsd",
|
| 27 |
+
"https://huggingface.co/spaces/osamabyc86/offload",
|
| 28 |
+
"https://176.28.159.79"
|
| 29 |
]
|
| 30 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
def get_local_ip():
|
| 32 |
try:
|
| 33 |
+
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
| 34 |
+
s.connect(("8.8.8.8", 80))
|
| 35 |
+
ip = s.getsockname()[0]
|
| 36 |
+
s.close()
|
| 37 |
+
return ip
|
| 38 |
except Exception:
|
| 39 |
+
return "127.0.0.1"
|
| 40 |
+
|
| 41 |
+
def register_peer(ip, port):
|
| 42 |
+
peer_url = f"http://{ip}:{port}/run"
|
| 43 |
+
if peer_url not in PEERS:
|
| 44 |
+
PEERS.add(peer_url)
|
| 45 |
+
logger.info(f"تم تسجيل قرين جديد: {peer_url}")
|
| 46 |
+
|
| 47 |
+
def discover_lan_peers():
|
| 48 |
+
class Listener:
|
| 49 |
+
def add_service(self, zc, type_, name):
|
| 50 |
+
info = zc.get_service_info(type_, name)
|
| 51 |
+
if info:
|
| 52 |
+
ip = socket.inet_ntoa(info.addresses[0])
|
| 53 |
+
register_peer(ip, info.port)
|
| 54 |
+
|
| 55 |
+
zeroconf = Zeroconf()
|
| 56 |
+
ServiceBrowser(zeroconf, SERVICE, Listener())
|
| 57 |
+
return zeroconf
|
| 58 |
+
|
| 59 |
+
def main():
|
| 60 |
+
logger.info("🚀 بدء نظام اكتشاف الأقران...")
|
| 61 |
+
|
| 62 |
+
# تسجيل الخدمة المحلية
|
| 63 |
+
zeroconf = Zeroconf()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
info = ServiceInfo(
|
| 65 |
SERVICE,
|
| 66 |
f"{socket.gethostname()}.{SERVICE}",
|
| 67 |
+
socket.inet_aton(get_local_ip()),
|
| 68 |
+
PORT,
|
| 69 |
+
properties={b'version': b'1.0'}
|
| 70 |
)
|
| 71 |
+
zeroconf.register_service(info)
|
| 72 |
+
|
| 73 |
+
# بدء اكتشاف الأقران
|
| 74 |
+
discover_lan_peers()
|
| 75 |
+
|
| 76 |
try:
|
| 77 |
+
while True:
|
| 78 |
+
logger.info(f"عدد الأقران المكتشفين: {len(PEERS)}")
|
| 79 |
+
time.sleep(10)
|
| 80 |
+
except KeyboardInterrupt:
|
| 81 |
+
logger.info("🛑 إيقاف النظام...")
|
| 82 |
+
finally:
|
| 83 |
+
zeroconf.unregister_service(info)
|
| 84 |
+
zeroconf.close()
|
| 85 |
+
|
| 86 |
+
if __name__ == "__main__":
|
| 87 |
+
main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
peer_registry.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
import socket
|
| 2 |
import time
|
| 3 |
from zeroconf import Zeroconf, ServiceBrowser, ServiceInfo
|
| 4 |
-
from peer_discovery import PORT
|
| 5 |
|
| 6 |
class Listener:
|
| 7 |
def __init__(self):
|
|
|
|
| 1 |
import socket
|
| 2 |
import time
|
| 3 |
from zeroconf import Zeroconf, ServiceBrowser, ServiceInfo
|
| 4 |
+
from peer_discovery import PORT
|
| 5 |
|
| 6 |
class Listener:
|
| 7 |
def __init__(self):
|
peer_server.py
CHANGED
|
@@ -6,7 +6,7 @@ import smart_tasks
|
|
| 6 |
import time
|
| 7 |
import socket
|
| 8 |
import peer_discovery # إذا كان يستخدم لاحقًا
|
| 9 |
-
from peer_discovery import PORT
|
| 10 |
|
| 11 |
app = Flask(__name__) # إنشاء التطبيق
|
| 12 |
|
|
|
|
| 6 |
import time
|
| 7 |
import socket
|
| 8 |
import peer_discovery # إذا كان يستخدم لاحقًا
|
| 9 |
+
from peer_discovery import PORT
|
| 10 |
|
| 11 |
app = Flask(__name__) # إنشاء التطبيق
|
| 12 |
|
ram_manager.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
|
| 2 |
ram_manager.py – Distributed RAM Offload Agent
|
| 3 |
================================================
|
| 4 |
|
|
|
|
| 1 |
+
"""
|
| 2 |
ram_manager.py – Distributed RAM Offload Agent
|
| 3 |
================================================
|
| 4 |
|
remote_executor.py
CHANGED
|
@@ -12,7 +12,7 @@ from typing import Any
|
|
| 12 |
|
| 13 |
# قائمة الأقران (URLs) المستخرجة من peer_discovery
|
| 14 |
from peer_discovery import PEERS
|
| 15 |
-
from peer_discovery import PORT
|
| 16 |
|
| 17 |
# عنوان افتراضي احتياطي (يمكن تغييره بمتغير بيئي REMOTE_SERVER)
|
| 18 |
FALLBACK_SERVER = os.getenv(
|
|
|
|
| 12 |
|
| 13 |
# قائمة الأقران (URLs) المستخرجة من peer_discovery
|
| 14 |
from peer_discovery import PEERS
|
| 15 |
+
from peer_discovery import PORT
|
| 16 |
|
| 17 |
# عنوان افتراضي احتياطي (يمكن تغييره بمتغير بيئي REMOTE_SERVER)
|
| 18 |
FALLBACK_SERVER = os.getenv(
|
rpc_server.py
CHANGED
|
@@ -9,7 +9,7 @@ from flask import Flask, request, jsonify
|
|
| 9 |
import smart_tasks # «your_tasks» تمّ استيراده تحت هذا الاسم فى main.py
|
| 10 |
import logging, json
|
| 11 |
from security_layer import SecurityManager
|
| 12 |
-
from peer_discovery import PORT
|
| 13 |
|
| 14 |
SECURITY = SecurityManager("my_shared_secret_123")
|
| 15 |
|
|
|
|
| 9 |
import smart_tasks # «your_tasks» تمّ استيراده تحت هذا الاسم فى main.py
|
| 10 |
import logging, json
|
| 11 |
from security_layer import SecurityManager
|
| 12 |
+
from peer_discovery import PORT
|
| 13 |
|
| 14 |
SECURITY = SecurityManager("my_shared_secret_123")
|
| 15 |
|
security_layer.py
CHANGED
|
@@ -9,7 +9,7 @@ from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
|
| 9 |
from cryptography.fernet import Fernet
|
| 10 |
import os, base64, json
|
| 11 |
from typing import Dict
|
| 12 |
-
from peer_discovery import PORT
|
| 13 |
|
| 14 |
|
| 15 |
class SecurityManager:
|
|
|
|
| 9 |
from cryptography.fernet import Fernet
|
| 10 |
import os, base64, json
|
| 11 |
from typing import Dict
|
| 12 |
+
from peer_discovery import PORT
|
| 13 |
|
| 14 |
|
| 15 |
class SecurityManager:
|
server.py
CHANGED
|
@@ -4,7 +4,7 @@ import json
|
|
| 4 |
from your_tasks import *
|
| 5 |
from project_identifier import create_project_endpoint, get_project_info
|
| 6 |
import logging
|
| 7 |
-
from peer_discovery import PORT
|
| 8 |
|
| 9 |
app = Flask(__name__)
|
| 10 |
CORS(app)
|
|
|
|
| 4 |
from your_tasks import *
|
| 5 |
from project_identifier import create_project_endpoint, get_project_info
|
| 6 |
import logging
|
| 7 |
+
from peer_discovery import PORT
|
| 8 |
|
| 9 |
app = Flask(__name__)
|
| 10 |
CORS(app)
|
smart_tasks.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
import math
|
| 2 |
import numpy as np
|
| 3 |
import time
|
| 4 |
-
from peer_discovery import PORT
|
| 5 |
|
| 6 |
def prime_calculation(n: int):
|
| 7 |
"""ترجع قائمة الأعداد الأوليّة حتى n مع عددها"""
|
|
|
|
| 1 |
import math
|
| 2 |
import numpy as np
|
| 3 |
import time
|
| 4 |
+
from peer_discovery import PORT
|
| 5 |
|
| 6 |
def prime_calculation(n: int):
|
| 7 |
"""ترجع قائمة الأعداد الأوليّة حتى n مع عددها"""
|
system_check.py
CHANGED
|
@@ -7,7 +7,7 @@ import requests
|
|
| 7 |
import psutil
|
| 8 |
import threading
|
| 9 |
from offload_lib import discover_peers
|
| 10 |
-
from peer_discovery import PORT
|
| 11 |
|
| 12 |
def check_local_system():
|
| 13 |
"""فحص النظام المحلي"""
|
|
|
|
| 7 |
import psutil
|
| 8 |
import threading
|
| 9 |
from offload_lib import discover_peers
|
| 10 |
+
from peer_discovery import PORT
|
| 11 |
|
| 12 |
def check_local_system():
|
| 13 |
"""فحص النظام المحلي"""
|
system_tray.py
CHANGED
|
@@ -9,7 +9,7 @@ import threading
|
|
| 9 |
import requests
|
| 10 |
import webbrowser
|
| 11 |
from pathlib import Path
|
| 12 |
-
from peer_discovery import PORT
|
| 13 |
|
| 14 |
try:
|
| 15 |
import pystray
|
|
|
|
| 9 |
import requests
|
| 10 |
import webbrowser
|
| 11 |
from pathlib import Path
|
| 12 |
+
from peer_discovery import PORT
|
| 13 |
|
| 14 |
try:
|
| 15 |
import pystray
|
task_splitter.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
| 2 |
from typing import Dict, Any, List
|
| 3 |
import networkx as nx
|
| 4 |
import hashlib
|
| 5 |
-
from peer_discovery import PORT
|
| 6 |
|
| 7 |
class TaskSplitter:
|
| 8 |
def __init__(self):
|
|
|
|
| 2 |
from typing import Dict, Any, List
|
| 3 |
import networkx as nx
|
| 4 |
import hashlib
|
| 5 |
+
from peer_discovery import PORT
|
| 6 |
|
| 7 |
class TaskSplitter:
|
| 8 |
def __init__(self):
|
test_distributed_system.py
CHANGED
|
@@ -9,7 +9,7 @@ import psutil
|
|
| 9 |
import logging
|
| 10 |
from offload_lib import discover_peers, matrix_multiply, prime_calculation, data_processing
|
| 11 |
from your_tasks import complex_operation
|
| 12 |
-
from peer_discovery import PORT
|
| 13 |
|
| 14 |
# إعداد السجل
|
| 15 |
logging.basicConfig(
|
|
|
|
| 9 |
import logging
|
| 10 |
from offload_lib import discover_peers, matrix_multiply, prime_calculation, data_processing
|
| 11 |
from your_tasks import complex_operation
|
| 12 |
+
from peer_discovery import PORT
|
| 13 |
|
| 14 |
# إعداد السجل
|
| 15 |
logging.basicConfig(
|
test_monitor.py
CHANGED
|
@@ -7,7 +7,7 @@ import threading
|
|
| 7 |
import psutil
|
| 8 |
import signal
|
| 9 |
import sys
|
| 10 |
-
from peer_discovery import PORT
|
| 11 |
|
| 12 |
class TestMonitor:
|
| 13 |
def __init__(self):
|
|
|
|
| 7 |
import psutil
|
| 8 |
import signal
|
| 9 |
import sys
|
| 10 |
+
from peer_discovery import PORT
|
| 11 |
|
| 12 |
class TestMonitor:
|
| 13 |
def __init__(self):
|
video_processing.py
CHANGED
|
@@ -7,7 +7,7 @@ import logging
|
|
| 7 |
from functools import wraps
|
| 8 |
from processor_manager import should_offload
|
| 9 |
from remote_executor import execute_remotely
|
| 10 |
-
from peer_discovery import PORT
|
| 11 |
|
| 12 |
logging.basicConfig(level=logging.INFO)
|
| 13 |
|
|
|
|
| 7 |
from functools import wraps
|
| 8 |
from processor_manager import should_offload
|
| 9 |
from remote_executor import execute_remotely
|
| 10 |
+
from peer_discovery import PORT
|
| 11 |
|
| 12 |
logging.basicConfig(level=logging.INFO)
|
| 13 |
|
your_tasks.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
import math
|
| 2 |
import numpy as np
|
| 3 |
from offload_lib import offload
|
| 4 |
-
from peer_discovery import PORT
|
| 5 |
|
| 6 |
# الدوال الأساسية (محليّة)
|
| 7 |
def prime_calculation(n: int):
|
|
|
|
| 1 |
import math
|
| 2 |
import numpy as np
|
| 3 |
from offload_lib import offload
|
| 4 |
+
from peer_discovery import PORT
|
| 5 |
|
| 6 |
# الدوال الأساسية (محليّة)
|
| 7 |
def prime_calculation(n: int):
|