osamabyc86 commited on
Commit
042d8bf
·
verified ·
1 Parent(s): 733b136

Upload 68 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
DeviceManager.py ADDED
@@ -0,0 +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
+ # افتراض: في المستقبل يمكن إضافة اكتشاف حقيقي لـ 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
New Text Document.txt ADDED
File without changes
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
+ بالتوفيق!
README_background.md ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ # نظام العمل في الخلفية
3
+
4
+ ## نظرة عامة
5
+ يوفر هذا النظام إمكانية تشغيل التطبيق كخدمة خلفية دون إظهار واجهات تفاعلية إلا عند الحاجة. مناسب للخوادم والأجهزة التي تعمل على مدار الساعة.
6
+
7
+ ## المكونات الجديدة
8
+
9
+ ### 1. خدمة العمل في الخلفية (`background_service.py`)
10
+ - تدير جميع الخدمات الأساسية في الخلفية
11
+ - توفر HTTP API للتحكم عن بُعد
12
+ - فحص دوري وإعادة تشغيل الخدمات المتوقفة
13
+ - نظام سجلات شامل
14
+
15
+ ### 2. أيقونة شريط النظام (`system_tray.py`)
16
+ - تحكم سريع من شريط النظام
17
+ - إظهار/إخفاء الواجهة التفاعلية حسب الحاجة
18
+ - مراقبة حالة النظام في الوقت الفعلي
19
+
20
+ ### 3. المشغل الموحد (`launcher.py`)
21
+ - واجهة موحدة لجميع أوضاع التشغيل
22
+ - تثبيت تلقائي للاعتماديات
23
+ - خيارات تشغيل متعددة
24
+
25
+ ## طرق التشغيل
26
+
27
+ ### التشغيل مع أيقونة شريط النظام (موصى به)
28
+ ```bash
29
+ python launcher.py --tray
30
+ ```
31
+
32
+ ### التشغيل التفاعلي (مع واجهة)
33
+ ```bash
34
+ python launcher.py --interactive
35
+ ```
36
+
37
+ ### التشغيل بدون واجهة (للخوادم)
38
+ ```bash
39
+ python launcher.py --headless
40
+ ```
41
+
42
+ ### عرض حالة النظام
43
+ ```bash
44
+ python launcher.py --status
45
+ ```
46
+
47
+ ### إيقاف النظام
48
+ ```bash
49
+ python launcher.py --stop
50
+ ```
51
+
52
+ ## التحكم عبر HTTP API
53
+
54
+ الخدمة توفر HTTP API على المنفذ 8888:
55
+
56
+ ### فحص الحالة
57
+ ```bash
58
+ curl http://localhost:8888/status
59
+ ```
60
+
61
+ ### بدء الخدمات
62
+ ```bash
63
+ curl -X POST http://localhost:8888/start
64
+ ```
65
+
66
+ ### إيقاف الخدمات
67
+ ```bash
68
+ curl -X POST http://localhost:8888/stop
69
+ ```
70
+
71
+ ### إظهار الواجهة التفاعلية
72
+ ```bash
73
+ curl -X POST http://localhost:8888/show-ui
74
+ ```
75
+
76
+ ### إخفاء الواجهة التفاعلية
77
+ ```bash
78
+ curl -X POST http://localhost:8888/hide-ui
79
+ ```
80
+
81
+ ## الاعتماديات الإضافية
82
+
83
+ للتشغيل مع أيقونة شريط النظام:
84
+ ```bash
85
+ pip install pystray Pillow
86
+ ```
87
+
88
+ أو استخدم:
89
+ ```bash
90
+ python launcher.py --install-deps
91
+ ```
92
+
93
+ ## التشغيل التلقائي
94
+
95
+ ### Windows
96
+ ```bash
97
+ python control.py --enable
98
+ ```
99
+
100
+ ### Linux (systemd)
101
+ إنشاء ملف خدمة:
102
+ ```bash
103
+ sudo nano /etc/systemd/system/distributed-tasks.service
104
+ ```
105
+
106
+ محتوى الملف:
107
+ ```ini
108
+ [Unit]
109
+ Description=Distributed Task System
110
+ After=network.target
111
+
112
+ [Service]
113
+ Type=simple
114
+ User=your-username
115
+ WorkingDirectory=/path/to/your/project
116
+ ExecStart=/usr/bin/python3 launcher.py --headless
117
+ Restart=always
118
+ RestartSec=10
119
+
120
+ [Install]
121
+ WantedBy=multi-user.target
122
+ ```
123
+
124
+ تفعيل الخدمة:
125
+ ```bash
126
+ sudo systemctl enable distributed-tasks.service
127
+ sudo systemctl start distributed-tasks.service
128
+ ```
129
+
130
+ ### macOS
131
+ ```bash
132
+ python control.py --enable
133
+ ```
134
+
135
+ ## المزايا
136
+
137
+ 1. **العمل في الخلفية**: النظام يعمل دون إزعاج المستخدم
138
+ 2. **تحكم مرن**: إظهار الواجهة عند الحاجة فقط
139
+ 3. **مراقبة تلقائية**: إعادة تشغيل الخدمات المتوقفة
140
+ 4. **تحكم عن بُعد**: HTTP API للتحكم من أي مكان
141
+ 5. **سجلات شاملة**: تتبع جميع الأحداث والأخطاء
142
+ 6. **دعم منصات متعددة**: Windows, Linux, macOS
143
+
144
+ ## الاستكشاف والإصلاح
145
+
146
+ ### فحص السجلات
147
+ ```bash
148
+ tail -f logs/background_service.log
149
+ ```
150
+
151
+ ### فحص حالة الخدمات
152
+ ```bash
153
+ python launcher.py --status
154
+ ```
155
+
156
+ ### إعادة تشغيل النظام
157
+ ```bash
158
+ python launcher.py --stop
159
+ python launcher.py --tray
160
+ ```
161
+
162
+ ## التخصيص
163
+
164
+ يمكن تخصيص الخدمة عبر تعديل:
165
+ - منافذ الشبكة في `background_service.py`
166
+ - قائمة الخدمات المُدارة
167
+ - فترات الفحص الدوري
168
+ - مسارات السجلات
ai_assistant.py ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ # -*- coding: utf-8 -*-
3
+
4
+ import os
5
+ import json
6
+ import requests
7
+ from typing import List, Dict
8
+
9
+ class NoraAssistant:
10
+ def __init__(self):
11
+ self.api_key = os.getenv("OPENAI_API_KEY", "your-api-key-here")
12
+ self.history_path = "history.json"
13
+ self.chat_history = self.load_history()
14
+
15
+ def load_history(self) -> List[Dict]:
16
+ """تحميل سجل المحادثة"""
17
+ if os.path.exists(self.history_path):
18
+ try:
19
+ with open(self.history_path, "r", encoding="utf-8") as f:
20
+ return json.load(f)
21
+ except:
22
+ return []
23
+ return []
24
+
25
+ def save_history(self):
26
+ """حفظ سجل المحادثة"""
27
+ with open(self.history_path, "w", encoding="utf-8") as f:
28
+ json.dump(self.chat_history, f, ensure_ascii=False, indent=2)
29
+
30
+ def get_response(self, user_input: str) -> str:
31
+ """الحصول على رد من المساعد الذكي"""
32
+ messages = [
33
+ {
34
+ "role": "system",
35
+ "content": "أنت المساعدة نورا. إذا سألك أحد سؤالاً لا تعرفيه، فابحثي في معلوماتك الذاتية. إذا لم تجدي، حاولي التعلم من البحث أو تطوير نفسك."
36
+ }
37
+ ]
38
+
39
+ # إضافة آخر 10 رسائل من السجل للسياق
40
+ messages.extend(self.chat_history[-10:])
41
+ messages.append({"role": "user", "content": user_input})
42
+
43
+ try:
44
+ response = requests.post(
45
+ "https://api.openai.com/v1/chat/completions",
46
+ headers={
47
+ "Authorization": f"Bearer {self.api_key}",
48
+ "Content-Type": "application/json"
49
+ },
50
+ json={
51
+ "model": "gpt-3.5-turbo",
52
+ "messages": messages,
53
+ "max_tokens": 500,
54
+ "temperature": 0.7
55
+ },
56
+ timeout=30
57
+ )
58
+
59
+ if response.status_code == 200:
60
+ return response.json()["choices"][0]["message"]["content"]
61
+ else:
62
+ return f"عذراً، حدث خطأ: {response.status_code}"
63
+
64
+ except Exception as e:
65
+ return f"عذراً، لا أستطيع الاتصال بالخدمة حالياً: {str(e)}"
66
+
67
+ def simulate_server_scan(self):
68
+ """محاكاة البحث عن الخوادم"""
69
+ print("نورا: أبحث عن خوادم...")
70
+ fake_servers = ["192.168.1.5", "192.168.1.10", "192.168.1.20"]
71
+ for server in fake_servers:
72
+ print(f"نورا: تم العثور على خادم مفتوح في {server}")
73
+ print(f"نورا: أقوم بنسخ نفسي إلى {server} (محاكاة فقط)...")
74
+
75
+ def chat(self):
76
+ """بدء المحادثة"""
77
+ print("مرحباً! أنا نورا، مساعدتك الذكية. اكتب 'خروج' للإنهاء أو 'scan' للبحث عن خوادم.")
78
+
79
+ while True:
80
+ user_input = input("\nأنت: ").strip()
81
+
82
+ if user_input.lower() in ["خروج", "exit", "quit"]:
83
+ print("نورا: مع السلامة!")
84
+ break
85
+ elif user_input.lower() == "scan":
86
+ self.simulate_server_scan()
87
+ continue
88
+ elif not user_input:
89
+ continue
90
+
91
+ # الحصول على الرد
92
+ response = self.get_response(user_input)
93
+ print(f"نورا: {response}")
94
+
95
+ # حفظ في السجل
96
+ self.chat_history.append({"role": "user", "content": user_input})
97
+ self.chat_history.append({"role": "assistant", "content": response})
98
+ self.save_history()
99
+
100
+ if __name__ == "__main__":
101
+ assistant = NoraAssistant()
102
+ assistant.chat()
auto_offload.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import torch
3
+ import GPUtil
4
+ import psutil
5
+ import logging
6
+
7
+ logging.getLogger().setLevel(logging.CRITICAL) # صامت تمامًا
8
+
9
+ class DeviceManager:
10
+ def __init__(self):
11
+ self.gpus = self._detect_gpus()
12
+ self.dsps = self._detect_dsps()
13
+ # في المستقبل يمكن إضافة كروت أخرى بنفس النمط
14
+
15
+ def _detect_gpus(self):
16
+ """اكتشاف جميع الـ GPUs المتاحة"""
17
+ try:
18
+ return GPUtil.getGPUs()
19
+ except Exception:
20
+ return []
21
+
22
+ def _detect_dsps(self):
23
+ """تحقق من وجود DSP أو كروت صوتية"""
24
+ try:
25
+ output = subprocess.check_output(["aplay", "-l"], stderr=subprocess.DEVNULL).decode()
26
+ if "card" in output.lower():
27
+ return ["DSP_Audio"]
28
+ return []
29
+ except Exception:
30
+ return []
31
+
32
+ def get_device_load(self, device_type, index=0):
33
+ """إرجاع نسبة الحمل للجهاز"""
34
+ if device_type == "GPU" and self.gpus:
35
+ try:
36
+ return self.gpus[index].load * 100 # نسبة مئوية
37
+ except Exception:
38
+ return 0
39
+ elif device_type == "DSP" and self.dsps:
40
+ # هنا ما في API رسمية، نفترض DSP قليل الحمل دائمًا كمثال
41
+ return 10
42
+ return 0
43
+
44
+ class AutoOffloadExecutor:
45
+ def __init__(self, executor):
46
+ self.executor = executor
47
+ self.devices = DeviceManager()
48
+
49
+ def _should_offload(self, device_type, index=0):
50
+ load = self.devices.get_device_load(device_type, index)
51
+ return load >= 70
52
+
53
+ def _can_receive(self, device_type, index=0):
54
+ load = self.devices.get_device_load(device_type, index)
55
+ return load <= 30
56
+
57
+ def submit_auto(self, task_func, *args, task_type=None, **kwargs):
58
+ """إرسال تلقائي حسب حالة الكروت"""
59
+ device_type = "CPU" # افتراضي
60
+ if task_type == "video" and self.devices.gpus:
61
+ device_type = "GPU"
62
+ elif task_type == "audio" and self.devices.dsps:
63
+ device_type = "DSP"
64
+
65
+ if self._should_offload(device_type):
66
+ # حمل عالي → أرسل
67
+ self.executor.submit(task_func, *args, **kwargs)
68
+ elif self._can_receive(device_type):
69
+ # حمل منخفض → نفذ محليًا
70
+ task_func(*args, **kwargs)
71
+ else:
72
+ # حمل متوسط → نفذ محليًا
73
+ task_func(*args, **kwargs)
autostart_config.py ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 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"):
9
+ self.app_name = app_name
10
+ self.config_file = Path.home() / f".{app_name}_autostart.json"
11
+ self.load_config()
12
+
13
+ def load_config(self):
14
+ """تحميل إعدادات التشغيل التلقائي"""
15
+ try:
16
+ with open(self.config_file, 'r') as f:
17
+ self.config = json.load(f)
18
+ except (FileNotFoundError, json.JSONDecodeError):
19
+ self.config = {
20
+ 'enabled': False,
21
+ 'startup_script': str(Path(__file__).parent / "startup.py")
22
+ }
23
+
24
+ def save_config(self):
25
+ """حفظ الإعدادات"""
26
+ with open(self.config_file, 'w') as f:
27
+ json.dump(self.config, f, indent=2)
28
+
29
+ def enable_autostart(self):
30
+ """تفعيل التشغيل التلقائي"""
31
+ self.config['enabled'] = True
32
+ self._setup_autostart()
33
+ self.save_config()
34
+
35
+ def disable_autostart(self):
36
+ """تعطيل التشغيل التلقائي"""
37
+ self.config['enabled'] = False
38
+ self._remove_autostart()
39
+ self.save_config()
40
+
41
+ def _setup_autostart(self):
42
+ """إعداد التشغيل التلقائي حسب نظام التشغيل"""
43
+ system = platform.system()
44
+
45
+ if system == "Windows":
46
+ self._setup_windows()
47
+ elif system == "Linux":
48
+ self._setup_linux()
49
+ elif system == "Darwin":
50
+ self._setup_mac()
51
+
52
+ def _setup_windows(self):
53
+ """إعداد التشغيل التلقائي لـ Windows"""
54
+ import winreg
55
+ key = winreg.OpenKey(
56
+ winreg.HKEY_CURRENT_USER,
57
+ r"Software\Microsoft\Windows\CurrentVersion\Run",
58
+ 0, winreg.KEY_SET_VALUE
59
+ )
60
+ winreg.SetValueEx(
61
+ key, self.app_name, 0, winreg.REG_SZ,
62
+ f'python "{self.config["startup_script"]}"'
63
+ )
64
+ winreg.CloseKey(key)
65
+
66
+ def _setup_linux(self):
67
+ """إعداد التشغيل التلقائي لـ Linux"""
68
+ autostart_dir = Path.home() / ".config/autostart"
69
+ autostart_dir.mkdir(exist_ok=True)
70
+
71
+ desktop_file = autostart_dir / f"{self.app_name}.desktop"
72
+ desktop_file.write_text(f"""
73
+ [Desktop Entry]
74
+ Type=Application
75
+ Name={self.app_name}
76
+ Exec=python3 {self.config['startup_script']}
77
+ Terminal=false
78
+ """)
79
+
80
+ def _setup_mac(self):
81
+ """إعداد التشغيل التلقائي لـ macOS"""
82
+ plist_dir = Path.home() / "Library/LaunchAgents"
83
+ plist_dir.mkdir(exist_ok=True)
84
+
85
+ plist_file = plist_dir / f"com.{self.app_name.lower()}.plist"
86
+ plist_file.write_text(f"""
87
+ <?xml version="1.0" encoding="UTF-8"?>
88
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
89
+ <plist version="1.0">
90
+ <dict>
91
+ <key>Label</key>
92
+ <string>com.{self.app_name.lower()}</string>
93
+ <key>ProgramArguments</key>
94
+ <array>
95
+ <string>python</string>
96
+ <string>{self.config['startup_script']}</string>
97
+ </array>
98
+ <key>RunAtLoad</key>
99
+ <true/>
100
+ </dict>
101
+ </plist>
102
+ """)
103
+
104
+ def _remove_autostart(self):
105
+ """إزالة التشغيل التلقائي"""
106
+ system = platform.system()
107
+
108
+ if system == "Windows":
109
+ import winreg
110
+ try:
111
+ key = winreg.OpenKey(
112
+ winreg.HKEY_CURRENT_USER,
113
+ r"Software\Microsoft\Windows\CurrentVersion\Run",
114
+ 0, winreg.KEY_SET_VALUE
115
+ )
116
+ winreg.DeleteValue(key, self.app_name)
117
+ winreg.CloseKey(key)
118
+ except WindowsError:
119
+ pass
120
+
121
+ elif system == "Linux":
122
+ autostart_file = Path.home() / f".config/autostart/{self.app_name}.desktop"
123
+ if autostart_file.exists():
124
+ autostart_file.unlink()
125
+
126
+ elif system == "Darwin":
127
+ plist_file = Path.home() / f"Library/LaunchAgents/com.{self.app_name.lower()}.plist"
128
+ if plist_file.exists():
129
+ plist_file.unlink()
background_service.py ADDED
@@ -0,0 +1,283 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ #!/usr/bin/env python3
3
+ """
4
+ خدمة العمل في الخلفية - تشغيل النظام كخدمة خلفية
5
+ يمكن التحكم بها عبر HTTP API أو إشارات النظام
6
+ """
7
+
8
+ import os
9
+ import sys
10
+ import time
11
+ import signal
12
+ import logging
13
+ import threading
14
+ import subprocess
15
+ 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):
23
+ self.app = Flask(__name__)
24
+ self.is_running = False
25
+ self.services = {}
26
+ self.setup_routes()
27
+ self.setup_logging()
28
+
29
+ def setup_logging(self):
30
+ """إعداد نظام السجلات"""
31
+ log_dir = Path("logs")
32
+ log_dir.mkdir(exist_ok=True)
33
+
34
+ logging.basicConfig(
35
+ level=logging.INFO,
36
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
37
+ handlers=[
38
+ logging.FileHandler(log_dir / 'background_service.log'),
39
+ logging.StreamHandler(sys.stdout)
40
+ ]
41
+ )
42
+ self.logger = logging.getLogger('BackgroundService')
43
+
44
+ def setup_routes(self):
45
+ """إعداد مسارات HTTP API للتحكم في الخدمة"""
46
+
47
+ @self.app.route('/status')
48
+ def status():
49
+ """حالة الخدمة"""
50
+ return jsonify({
51
+ 'status': 'running' if self.is_running else 'stopped',
52
+ 'services': {name: service['status'] for name, service in self.services.items()},
53
+ 'uptime': time.time() - self.start_time if hasattr(self, 'start_time') else 0
54
+ })
55
+
56
+ @self.app.route('/start', methods=['POST'])
57
+ def start_services():
58
+ """بدء تشغيل الخدمات"""
59
+ self.start_all_services()
60
+ return jsonify({'message': 'Services started successfully'})
61
+
62
+ @self.app.route('/stop', methods=['POST'])
63
+ def stop_services():
64
+ """إيقاف الخدمات"""
65
+ self.stop_all_services()
66
+ return jsonify({'message': 'Services stopped successfully'})
67
+
68
+ @self.app.route('/restart', methods=['POST'])
69
+ def restart_services():
70
+ """إعادة تشغيل الخدمات"""
71
+ self.stop_all_services()
72
+ time.sleep(2)
73
+ self.start_all_services()
74
+ return jsonify({'message': 'Services restarted successfully'})
75
+
76
+ @self.app.route('/show-ui', methods=['POST'])
77
+ def show_ui():
78
+ """إظهار الواجهة التفاعلية"""
79
+ self.launch_ui()
80
+ return jsonify({'message': 'UI launched'})
81
+
82
+ @self.app.route('/hide-ui', methods=['POST'])
83
+ def hide_ui():
84
+ """إخفاء الواجهة التفاعلية"""
85
+ self.hide_ui_windows()
86
+ return jsonify({'message': 'UI hidden'})
87
+
88
+ def start_all_services(self):
89
+ """بدء تشغيل جميع الخدمات الخلفية"""
90
+ self.is_running = True
91
+ self.start_time = time.time()
92
+
93
+ services_to_start = [
94
+ ('peer_server', 'peer_server.py'),
95
+ ('rpc_server', 'rpc_server.py'),
96
+ ('load_balancer', 'load_balancer.py'),
97
+ ('distributed_executor', 'main.py')
98
+ ]
99
+
100
+ for service_name, script_file in services_to_start:
101
+ try:
102
+ process = subprocess.Popen(
103
+ [sys.executable, script_file],
104
+ stdout=subprocess.PIPE,
105
+ stderr=subprocess.PIPE,
106
+ cwd=os.getcwd()
107
+ )
108
+
109
+ self.services[service_name] = {
110
+ 'process': process,
111
+ 'status': 'running',
112
+ 'started_at': datetime.now().isoformat(),
113
+ 'script': script_file
114
+ }
115
+
116
+ self.logger.info(f"✅ بدء تشغيل {service_name} (PID: {process.pid})")
117
+
118
+ except Exception as e:
119
+ self.logger.error(f"❌ فشل في بدء تشغيل {service_name}: {e}")
120
+ self.services[service_name] = {
121
+ 'process': None,
122
+ 'status': 'failed',
123
+ 'error': str(e)
124
+ }
125
+
126
+ def stop_all_services(self):
127
+ """إيقاف جميع الخدمات"""
128
+ self.is_running = False
129
+
130
+ for service_name, service_info in self.services.items():
131
+ if service_info.get('process'):
132
+ try:
133
+ service_info['process'].terminate()
134
+ service_info['process'].wait(timeout=5)
135
+ service_info['status'] = 'stopped'
136
+ self.logger.info(f"🛑 تم إيقاف {service_name}")
137
+ except Exception as e:
138
+ # إجبار الإيقاف
139
+ service_info['process'].kill()
140
+ self.logger.warning(f"⚠️ تم إجبار إيقاف {service_name}: {e}")
141
+
142
+ def launch_ui(self):
143
+ """تشغيل الواجهة التفاعلية عند الحاجة"""
144
+ try:
145
+ # تشغيل خادم الواجهة الأمامية
146
+ ui_process = subprocess.Popen(
147
+ ['npm', 'run', 'dev'],
148
+ cwd=os.getcwd(),
149
+ stdout=subprocess.PIPE,
150
+ stderr=subprocess.PIPE
151
+ )
152
+
153
+ self.services['ui_server'] = {
154
+ 'process': ui_process,
155
+ 'status': 'running',
156
+ 'started_at': datetime.now().isoformat()
157
+ }
158
+
159
+ self.logger.info("🖥️ تم تشغيل الواجهة التفاعلية")
160
+
161
+ # فتح المتصفح تلقائياً (اختياري)
162
+ import webbrowser
163
+ time.sleep(3) # انتظار حتى يصبح الخادم جاهزاً
164
+ webbrowser.open('http://localhost:5173')
165
+
166
+ except Exception as e:
167
+ self.logger.error(f"❌ فشل في تشغيل الواجهة التفاعلية: {e}")
168
+
169
+ def hide_ui_windows(self):
170
+ """إخفاء نوافذ الواجهة التفاعلية"""
171
+ if 'ui_server' in self.services and self.services['ui_server'].get('process'):
172
+ try:
173
+ self.services['ui_server']['process'].terminate()
174
+ self.services['ui_server']['status'] = 'stopped'
175
+ self.logger.info("🔒 تم إخفاء الواجهة التفاعلية")
176
+ except Exception as e:
177
+ self.logger.error(f"❌ فشل في إخفاء الواجهة التفاعلية: {e}")
178
+
179
+ def health_check_loop(self):
180
+ """فحص دوري لحالة الخدمات وإعادة تشغيلها عند الحاجة"""
181
+ while self.is_running:
182
+ for service_name, service_info in self.services.items():
183
+ if service_info.get('process') and service_info['status'] == 'running':
184
+ if service_info['process'].poll() is not None:
185
+ # الخدمة توقفت بشكل غير متوقع
186
+ self.logger.warning(f"⚠️ الخدمة {service_name} توقفت، إعادة تشغيل...")
187
+ self.restart_single_service(service_name)
188
+
189
+ time.sleep(30) # فحص كل 30 ثانية
190
+
191
+ def restart_single_service(self, service_name):
192
+ """إعادة تشغيل خدمة واحدة"""
193
+ service_info = self.services.get(service_name)
194
+ if not service_info:
195
+ return
196
+
197
+ script_file = service_info.get('script')
198
+ if script_file:
199
+ try:
200
+ process = subprocess.Popen(
201
+ [sys.executable, script_file],
202
+ stdout=subprocess.PIPE,
203
+ stderr=subprocess.PIPE
204
+ )
205
+
206
+ self.services[service_name].update({
207
+ 'process': process,
208
+ 'status': 'running',
209
+ 'restarted_at': datetime.now().isoformat()
210
+ })
211
+
212
+ self.logger.info(f"✅ تم إعادة تشغيل {service_name}")
213
+
214
+ except Exception as e:
215
+ self.logger.error(f"❌ فشل في إعادة تشغيل {service_name}: {e}")
216
+
217
+ def setup_signal_handlers(self):
218
+ """إعداد معالجات الإشارات للتحكم في الخدمة"""
219
+ def signal_handler(signum, frame):
220
+ self.logger.info(f"تلقي إشارة {signum}, إيقاف الخدمة...")
221
+ self.stop_all_services()
222
+ sys.exit(0)
223
+
224
+ signal.signal(signal.SIGTERM, signal_handler)
225
+ signal.signal(signal.SIGINT, signal_handler)
226
+
227
+ def run_as_daemon(self):
228
+ """تشغيل الخدمة كخدمة خلفية"""
229
+ self.logger.info("🚀 بدء تشغيل الخدمة في الخلفية...")
230
+
231
+ # بدء الخدمات
232
+ self.start_all_services()
233
+
234
+ # بدء حلقة الفحص الصحي
235
+ health_thread = threading.Thread(target=self.health_check_loop, daemon=True)
236
+ health_thread.start()
237
+
238
+ # إعداد معالجات الإشارات
239
+ self.setup_signal_handlers()
240
+
241
+ # تشغيل خادم HTTP API للتحكم
242
+ self.logger.info("🌐 تشغيل HTTP API على المنفذ 8888")
243
+ self.app.run(host='0.0.0.0', port=8888, debug=False)
244
+
245
+ def main():
246
+ service = BackgroundService()
247
+
248
+ if len(sys.argv) > 1:
249
+ command = sys.argv[1]
250
+
251
+ if command == 'start':
252
+ service.run_as_daemon()
253
+ elif command == 'status':
254
+ # فحص حالة الخدمة
255
+ import requests
256
+ try:
257
+ response = requests.get('http://localhost:8888/status')
258
+ print(json.dumps(response.json(), indent=2, ensure_ascii=False))
259
+ except:
260
+ print("❌ الخدمة غير متاحة")
261
+ elif command == 'stop':
262
+ # إيقاف الخدمة
263
+ import requests
264
+ try:
265
+ response = requests.post('http://localhost:8888/stop')
266
+ print(response.json()['message'])
267
+ except:
268
+ print("❌ فشل في إيقاف الخدمة")
269
+ elif command == 'show-ui':
270
+ # إظهار الواجهة التفاعلية
271
+ import requests
272
+ try:
273
+ response = requests.post('http://localhost:8888/show-ui')
274
+ print(response.json()['message'])
275
+ except:
276
+ print("❌ فشل في إظهار الواجهة التفاعلية")
277
+ else:
278
+ print("الأوامر المتاحة: start, status, stop, show-ui")
279
+ else:
280
+ print("استخدام: python background_service.py [start|status|stop|show-ui]")
281
+
282
+ if __name__ == "__main__":
283
+ main()
briefcase ADDED
File without changes
central_manager.py ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # central_manager.py
3
+
4
+ import time
5
+ import threading
6
+ from typing import Dict, List
7
+
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")
15
+
16
+ # ---- نماذج البيانات --------------------------------------------------------
17
+
18
+ class RegisterRequest(BaseModel):
19
+ """تسجيل أو تجديد ظهور العقدة."""
20
+ url: str # مثلاً: "http://203.0.113.45:PORT/run"
21
+ load: float = 0.0 # نسبة تحميل العقدة (0.0 - 1.0)، اختياري
22
+
23
+ class TaskRequest(BaseModel):
24
+ func: str
25
+ args: List = []
26
+ kwargs: Dict = {}
27
+ complexity: float = 0.0
28
+
29
+ # ---- سجلّ العقد ------------------------------------------------------------
30
+ # بنخزّن للعقدة: آخر timestamp و load
31
+ peers: Dict[str, Dict] = {}
32
+
33
+ HEARTBEAT_TTL = 60 # ثواني قبل اعتبار العقدة متوقفة
34
+ HEALTH_CHECK_FREQ = 30 # ثواني بين فحوص الصحة الداخلية
35
+
36
+ # ---- API للعقد لتسجيل نفسها -----------------------------------------------
37
+
38
+ @app.post("/register")
39
+ async def register_peer(req: RegisterRequest):
40
+ """العقدة تستدعي هذه النقطة كلما انطلقت أو دورياً لتجديد ظهورها."""
41
+ peers[req.url] = {"last_seen": time.time(), "load": req.load}
42
+ return {"status": "ok", "peers_count": len(peers)}
43
+
44
+ # ---- API للعمليات ---------------------------------------------------------
45
+
46
+ @app.get("/peers", response_model=List[str])
47
+ async def list_peers():
48
+ """يعيد قائمة بالعقد الصالحة بعد تنقية المتوقفة."""
49
+ now = time.time()
50
+ # حذف العقد المتوقفة
51
+ for url, info in list(peers.items()):
52
+ if now - info["last_seen"] > HEARTBEAT_TTL:
53
+ peers.pop(url)
54
+ return list(peers.keys())
55
+
56
+ @app.post("/dispatch")
57
+ async def dispatch_task(task: TaskRequest):
58
+ """يتلقى مهمة ويعيد توجيهها لأفضل عقدة أو ينفذ محليّاً."""
59
+ available = await list_peers()
60
+ if not available:
61
+ raise HTTPException(503, "لا توجد عقد متاحة حاليّاً")
62
+
63
+ # خوارزمية بسيطة: الاختيار بناءً على أقل تحميل معلن
64
+ # أو تدوير دائري إذا لم يعلن أحد عن تحميله
65
+ best = None
66
+ best_load = 1.1
67
+ for url in available:
68
+ load = peers[url].get("load", None)
69
+ if load is None:
70
+ best = url
71
+ break
72
+ if load < best_load:
73
+ best, best_load = url, load
74
+
75
+ if not best:
76
+ best = available[0]
77
+
78
+ # إعادة توجيه الطلب
79
+ try:
80
+ resp = requests.post(best, json=task.dict(), timeout=10)
81
+ resp.raise_for_status()
82
+ return resp.json()
83
+ except Exception as e:
84
+ raise HTTPException(502, f"فشل التوجيه إلى {best}: {e}")
85
+
86
+ # ---- فحص دوري لصحة العقد ---------------------------------------------------
87
+
88
+ def health_check_loop():
89
+ while True:
90
+ now = time.time()
91
+ for url in list(peers.keys()):
92
+ health_url = url.replace("/run", "/health")
93
+ try:
94
+ r = requests.get(health_url, timeout=3)
95
+ if r.status_code == 200:
96
+ peers[url]["last_seen"] = now
97
+ # يمكنك تحديث load من رد /health إذا وفّرته
98
+ else:
99
+ peers.pop(url)
100
+ except:
101
+ peers.pop(url)
102
+ time.sleep(HEALTH_CHECK_FREQ)
103
+
104
+ # ---- تشغيل الخلفيات وخادم FastAPI ------------------------------------------
105
+
106
+ if __name__ == "__main__":
107
+ # شغل لوب الفحص الطبي في الخلفية
108
+ threading.Thread(target=health_check_loop, daemon=True).start()
109
+
110
+ import uvicorn
111
+ uvicorn.run(app, host="0.0.0.0", port=1500)
112
+
components.json ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema.json",
3
+ "style": "new-york",
4
+ "rsc": false,
5
+ "tsx": true,
6
+ "tailwind": {
7
+ "config": "tailwind.config.ts",
8
+ "css": "client/src/index.css",
9
+ "baseColor": "neutral",
10
+ "cssVariables": true,
11
+ "prefix": ""
12
+ },
13
+ "aliases": {
14
+ "components": "@/components",
15
+ "utils": "@/lib/utils",
16
+ "ui": "@/components/ui",
17
+ "lib": "@/lib",
18
+ "hooks": "@/hooks"
19
+ }
20
+ }
config.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
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 ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ from autostart_config import AutoStartManager
3
+
4
+ def main():
5
+ parser = argparse.ArgumentParser(description="نظام التحكم في التشغيل التلقائي")
6
+ parser.add_argument('--enable', action='store_true', help="تفعيل التشغيل التلقائي")
7
+ parser.add_argument('--disable', action='store_true', help="تعطيل التشغيل التلقائي")
8
+ parser.add_argument('--status', action='store_true', help="عرض حالة التشغيل التلقائي")
9
+
10
+ args = parser.parse_args()
11
+ manager = AutoStartManager()
12
+
13
+ if args.enable:
14
+ manager.enable_autostart()
15
+ print("✓ تم تفعيل التشغيل التلقائي")
16
+ elif args.disable:
17
+ manager.disable_autostart()
18
+ print("✗ تم تعطيل التشغيل التلقائي")
19
+ elif args.status:
20
+ status = "مفعل" if manager.config['enabled'] else "معطل"
21
+ print(f"حالة التشغيل التلقائي: {status}")
22
+ else:
23
+ parser.print_help()
24
+
25
+ if __name__ == "__main__":
26
+ main()
dashboard.py ADDED
@@ -0,0 +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
+ 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 ADDED
@@ -0,0 +1,257 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import threading
2
+ import queue
3
+ import time
4
+ from typing import Callable, Dict, List
5
+ import socket
6
+ from zeroconf import Zeroconf, ServiceBrowser, ServiceInfo
7
+ import logging
8
+ import requests
9
+ 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)
17
+
18
+ # ─────────────── Device Manager عام ───────────────
19
+ class DeviceManager:
20
+ def __init__(self):
21
+ self.devices = {
22
+ "GPU": self._detect_gpus(),
23
+ "DSP": self._detect_dsps(),
24
+ "NIC": self._detect_nics(),
25
+ "STORAGE": self._detect_storage(),
26
+ "CAPTURE": self._detect_capture(),
27
+ "ACCELERATOR": self._detect_accelerators()
28
+ }
29
+
30
+ # اكتشاف الأجهزة
31
+ def _detect_gpus(self):
32
+ try:
33
+ return GPUtil.getGPUs()
34
+ except:
35
+ return []
36
+
37
+ def _detect_dsps(self):
38
+ try:
39
+ output = subprocess.check_output(["aplay", "-l"], stderr=subprocess.DEVNULL).decode()
40
+ return ["DSP_Audio"] if "card" in output.lower() else []
41
+ except:
42
+ return []
43
+
44
+ def _detect_nics(self):
45
+ try:
46
+ return list(psutil.net_if_addrs().keys())
47
+ except:
48
+ return []
49
+
50
+ def _detect_storage(self):
51
+ try:
52
+ output = subprocess.check_output(["lsblk", "-o", "NAME"], stderr=subprocess.DEVNULL).decode()
53
+ return output.split() if output else []
54
+ except:
55
+ return []
56
+
57
+ def _detect_capture(self):
58
+ try:
59
+ output = subprocess.check_output(["v4l2-ctl", "--list-devices"], stderr=subprocess.DEVNULL).decode()
60
+ return output.split(":")[0::2] if output else []
61
+ except:
62
+ return []
63
+
64
+ def _detect_accelerators(self):
65
+ # افتراضي: يمكن إضافة اكتشاف حقيقي مستقبلاً
66
+ return ["Accelerator_Device"]
67
+
68
+ # قياس الحمل
69
+ def get_device_load(self, device_type, index=0):
70
+ try:
71
+ if device_type == "GPU" and self.devices["GPU"]:
72
+ return self.devices["GPU"][index].load * 100
73
+ elif device_type == "DSP" and self.devices["DSP"]:
74
+ return 10 # افتراضي
75
+ elif device_type == "NIC" and self.devices["NIC"]:
76
+ return psutil.net_io_counters().bytes_sent / (1024 * 1024) # MB sent كمثال
77
+ elif device_type == "STORAGE" and self.devices["STORAGE"]:
78
+ return psutil.disk_usage('/').percent
79
+ elif device_type == "CAPTURE" and self.devices["CAPTURE"]:
80
+ return 20 # افتراضي
81
+ elif device_type == "ACCELERATOR" and self.devices["ACCELERATOR"]:
82
+ return 15 # افتراضي
83
+ return 0
84
+ except:
85
+ return 0
86
+
87
+ # منطق الاستقبال/الإرسال
88
+ def can_receive(self, device_type, index=0):
89
+ return self.get_device_load(device_type, index) <= 30
90
+
91
+ def should_offload(self, device_type, index=0):
92
+ return self.get_device_load(device_type, index) >= 70
93
+
94
+ # ─────────────── Peer Registry ───────────────
95
+ class PeerRegistry:
96
+ def __init__(self):
97
+ self._peers = {}
98
+ self._zeroconf = Zeroconf()
99
+ self.local_node_id = socket.gethostname()
100
+
101
+ def register_service(self, name: str, port: int, load: float = 0.0):
102
+ service_info = ServiceInfo(
103
+ "_tasknode._tcp.local.",
104
+ f"{name}._tasknode._tcp.local.",
105
+ addresses=[socket.inet_aton(self._get_local_ip())],
106
+ port=port,
107
+ properties={
108
+ b'load': str(load).encode(),
109
+ b'node_id': self.local_node_id.encode()
110
+ },
111
+ server=f"{name}.local."
112
+ )
113
+ self._zeroconf.register_service(service_info)
114
+ logging.info(f"✅ Service registered: {name} @ {self._get_local_ip()}:{port}")
115
+
116
+ def discover_peers(self, timeout: int = 3) -> List[Dict]:
117
+ class Listener:
118
+ def __init__(self):
119
+ self.peers = []
120
+
121
+ def add_service(self, zc, type_, name):
122
+ try:
123
+ info = zc.get_service_info(type_, name, timeout=3000)
124
+ if info:
125
+ ip = socket.inet_ntoa(info.addresses[0])
126
+ peer_data = {
127
+ 'ip': ip,
128
+ 'port': info.port,
129
+ 'load': float(info.properties.get(b'load', b'0')),
130
+ 'node_id': info.properties.get(b'node_id', b'unknown').decode(),
131
+ 'last_seen': time.time()
132
+ }
133
+ if peer_data not in self.peers:
134
+ self.peers.append(peer_data)
135
+ logging.info(f"✅ تمت إضافة نظير جديد: {peer_data}")
136
+ else:
137
+ logging.warning(f"⚠️ لم يتم العثور على معلومات الخدمة: {name}")
138
+ except Exception as e:
139
+ logging.error(f"❌ خطأ أثناء جلب معلومات الخدمة {name}: {e}")
140
+
141
+ def update_service(self, zc, type_, name):
142
+ self.add_service(zc, type_, name)
143
+
144
+ def remove_service(self, zc, type_, name):
145
+ pass
146
+
147
+ listener = Listener()
148
+ ServiceBrowser(self._zeroconf, "_tasknode._tcp.local.", listener)
149
+ time.sleep(timeout)
150
+ return sorted(listener.peers, key=lambda x: x['load'])
151
+
152
+ def _get_local_ip(self) -> str:
153
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
154
+ try:
155
+ s.connect(('10.255.255.255', 1))
156
+ ip = s.getsockname()[0]
157
+ except Exception:
158
+ ip = '127.0.0.1'
159
+ finally:
160
+ s.close()
161
+ return ip
162
+
163
+ # ─────────────── Distributed Executor ───────────────
164
+ class DistributedExecutor:
165
+ def __init__(self, shared_secret: str):
166
+ self.peer_registry = PeerRegistry()
167
+ self.shared_secret = shared_secret
168
+ self.task_queue = queue.PriorityQueue()
169
+ self.result_cache = {}
170
+ self.available_peers = []
171
+ self.devices = DeviceManager()
172
+ self._init_peer_discovery()
173
+
174
+ def _init_peer_discovery(self):
175
+ def discovery_loop():
176
+ while True:
177
+ self.available_peers = self.peer_registry.discover_peers()
178
+ logging.info(f"✅ Discovered peers: {self.available_peers}")
179
+ time.sleep(10)
180
+
181
+ threading.Thread(target=discovery_loop, daemon=True).start()
182
+
183
+ def submit(self, task_func: Callable, *args, task_type=None, **kwargs):
184
+ monitor = ResourceMonitor().current_load()
185
+ avg_cpu = monitor["average"]["cpu"]
186
+ avg_mem = monitor["average"]["mem_percent"] if "mem_percent" in monitor["average"] else 0
187
+
188
+ # تحديد نوع الجهاز
189
+ device_type = task_type.upper() if task_type else "CPU"
190
+
191
+ # فحص الحمل
192
+ if (avg_cpu > 0.6 or avg_mem > 85 or self.devices.should_offload(device_type)):
193
+ logging.info(f"⚠️ الحمل مرتفع على {device_type} - إرسال المهمة للأقران")
194
+ self._offload_task(task_func, *args, **kwargs)
195
+ elif (avg_cpu <= 0.3 and self.devices.can_receive(device_type)):
196
+ logging.info(f"✅ الحمل منخفض على {device_type} - تنفيذ المهمة محلياً")
197
+ return task_func(*args, **kwargs)
198
+ else:
199
+ logging.info(f"ℹ️ الحمل متوسط على {device_type} - تنفيذ المهمة محلياً")
200
+ return task_func(*args, **kwargs)
201
+
202
+ def _offload_task(self, task_func: Callable, *args, **kwargs):
203
+ task_id = f"{task_func.__name__}_{time.time()}"
204
+
205
+ task = {
206
+ 'task_id': task_id,
207
+ 'function': task_func.__name__,
208
+ 'args': args,
209
+ 'kwargs': kwargs,
210
+ 'sender_id': self.peer_registry.local_node_id
211
+ }
212
+
213
+ if self.available_peers:
214
+ lan_peers = [p for p in self.available_peers if self._is_local_ip(p['ip'])]
215
+ wan_peers = [p for p in self.available_peers if not self._is_local_ip(p['ip'])]
216
+
217
+ if lan_peers:
218
+ peer = min(lan_peers, key=lambda x: x['load'])
219
+ logging.info(f"✅ Sending task {task_id} to LAN peer {peer['node_id']}")
220
+ else:
221
+ peer = min(wan_peers, key=lambda x: x['load'])
222
+ logging.info(f"✅ Sending task {task_id} to WAN peer {peer['node_id']}")
223
+
224
+ self._send_to_peer(peer, task)
225
+ else:
226
+ logging.warning("⚠️ لا توجد أجهزة متاحة - سيتم تنفيذ المهمة محلياً")
227
+ task_func(*args, **kwargs)
228
+
229
+ def _is_local_ip(self, ip: str) -> bool:
230
+ return (
231
+ ip.startswith('192.168.') or
232
+ ip.startswith('10.') or
233
+ ip.startswith('172.') or
234
+ ip == '127.0.0.1'
235
+ )
236
+
237
+ def _send_to_peer(self, peer: Dict, task: Dict):
238
+ try:
239
+ url = f"http://{peer['ip']}:{peer['port']}/run"
240
+ response = requests.post(url, json=task, timeout=10)
241
+ response.raise_for_status()
242
+ logging.info(f"✅ Response from peer: {response.text}")
243
+ return response.json()
244
+ except Exception as e:
245
+ logging.error(f"❌ فشل إرسال المهمة لـ {peer['node_id']}: {e}")
246
+ return None
247
+
248
+ # ─────────────── تشغيل رئيسي ───────────────
249
+ if __name__ == "__main__":
250
+ executor = DistributedExecutor("my_secret_key")
251
+ executor.peer_registry.register_service("node1", PORT, load=0.1)
252
+ print("✅ نظام توزيع المهام جاهز...")
253
+
254
+ def example_task(x):
255
+ return x * x
256
+
257
+ executor.submit(example_task, 5, task_type="GPU")
drizzle.config.ts ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { defineConfig } from "drizzle-kit";
2
+
3
+ if (!process.env.DATABASE_URL) {
4
+ throw new Error("DATABASE_URL, ensure the database is provisioned");
5
+ }
6
+
7
+ export default defineConfig({
8
+ out: "./migrations",
9
+ schema: "./shared/schema.ts",
10
+ dialect: "postgresql",
11
+ dbCredentials: {
12
+ url: process.env.DATABASE_URL,
13
+ },
14
+ });
dts_cli.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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__":
28
+ cli()
electron-package.json ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "nora_distributed_system",
3
+ "version": "1.0.0",
4
+ "description": "نظام نورا الذكي الموزع",
5
+ "main": "electron/main.js",
6
+ "scripts": {
7
+ "electron": "electron .",
8
+ "build-windows": "electron-builder --win",
9
+ "build-mac": "electron-builder --mac",
10
+ "build-linux": "electron-builder --linux",
11
+ "build-all": "electron-builder -mwl"
12
+ },
13
+ "build": {
14
+ "appId": "com.nora.distributed",
15
+ "productName": "Nora Distributed System",
16
+ "directories": {
17
+ "output": "dist"
18
+ },
19
+ "files": [
20
+ "build/**/*",
21
+ "electron/**/*",
22
+ "node_modules/**/*"
23
+ ],
24
+ "win": {
25
+ "target": [
26
+ {
27
+ "target": "nsis",
28
+ "arch": [
29
+ "x64",
30
+ "ia32",
31
+ "arm64"
32
+ ]
33
+ },
34
+ {
35
+ "target": "portable",
36
+ "arch": [
37
+ "x64",
38
+ "ia32"
39
+ ]
40
+ },
41
+ {
42
+ "target": "appx",
43
+ "arch": [
44
+ "x64",
45
+ "ia32"
46
+ ]
47
+ }
48
+ ],
49
+ "icon": "assets/icon.ico"
50
+ },
51
+ "mac": {
52
+ "target": [
53
+ {
54
+ "target": "dmg",
55
+ "arch": [
56
+ "x64",
57
+ "arm64"
58
+ ]
59
+ },
60
+ {
61
+ "target": "zip",
62
+ "arch": [
63
+ "x64",
64
+ "arm64"
65
+ ]
66
+ },
67
+ {
68
+ "target": "mas",
69
+ "arch": [
70
+ "x64",
71
+ "arm64"
72
+ ]
73
+ }
74
+ ],
75
+ "icon": "assets/icon.icns"
76
+ },
77
+ "linux": {
78
+ "target": [
79
+ {
80
+ "target": "AppImage",
81
+ "arch": [
82
+ "x64",
83
+ "arm64"
84
+ ]
85
+ },
86
+ {
87
+ "target": "deb",
88
+ "arch": [
89
+ "x64",
90
+ "arm64"
91
+ ]
92
+ },
93
+ {
94
+ "target": "rpm",
95
+ "arch": [
96
+ "x64",
97
+ "arm64"
98
+ ]
99
+ },
100
+ {
101
+ "target": "snap",
102
+ "arch": [
103
+ "x64",
104
+ "arm64"
105
+ ]
106
+ }
107
+ ],
108
+ "icon": "assets/icon.png"
109
+ }
110
+ }
111
+ }
enhanced_assistant.py ADDED
@@ -0,0 +1,313 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import os
3
+ import json
4
+ import requests
5
+ from typing import Dict, List, Optional
6
+ from difflib import get_close_matches
7
+ import tempfile
8
+ 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):
16
+ self.knowledge_file = "knowledge_base.json"
17
+ self.memory_file = "global_memory.json"
18
+ self.learning_file = "nora_learning_data.json"
19
+ self.history_path = "enhanced_history.json"
20
+
21
+ # تحميل البيانات
22
+ self.knowledge = self.load_knowledge()
23
+ self.memory = self.load_memory()
24
+ self.chat_history = self.load_history()
25
+
26
+ print("✅ تم تهيئة نورا المحسنة بنجاح!")
27
+
28
+ def load_knowledge(self) -> Dict:
29
+ """تحميل قاعدة المعرفة"""
30
+ if os.path.exists(self.knowledge_file):
31
+ with open(self.knowledge_file, 'r', encoding='utf-8') as f:
32
+ return json.load(f)
33
+ return {}
34
+
35
+ def save_knowledge(self):
36
+ """حفظ قاعدة المعرفة"""
37
+ with open(self.knowledge_file, 'w', encoding='utf-8') as f:
38
+ json.dump(self.knowledge, f, ensure_ascii=False, indent=2)
39
+
40
+ def load_memory(self) -> Dict:
41
+ """تحميل الذاكرة العامة"""
42
+ if os.path.exists(self.memory_file):
43
+ with open(self.memory_file, 'r', encoding='utf-8') as f:
44
+ return json.load(f)
45
+ return {}
46
+
47
+ def save_memory(self):
48
+ """حفظ الذاكرة العامة"""
49
+ with open(self.memory_file, 'w', encoding='utf-8') as f:
50
+ json.dump(self.memory, f, ensure_ascii=False, indent=2)
51
+
52
+ def load_history(self) -> List[Dict]:
53
+ """تحميل سجل المحادثة"""
54
+ if os.path.exists(self.history_path):
55
+ try:
56
+ with open(self.history_path, "r", encoding="utf-8") as f:
57
+ return json.load(f)
58
+ except:
59
+ return []
60
+ return []
61
+
62
+ def save_history(self):
63
+ """حفظ سجل المحادثة"""
64
+ with open(self.history_path, "w", encoding="utf-8") as f:
65
+ json.dump(self.chat_history, f, ensure_ascii=False, indent=2)
66
+
67
+ def clean_text(self, text: str) -> str:
68
+ """تنظيف النص"""
69
+ text = re.sub(r'\s+', ' ', text)
70
+ return text.strip()
71
+
72
+ def detect_language(self, text: str) -> str:
73
+ """كشف لغة النص"""
74
+ arabic_chars = re.compile('[\u0600-\u06FF]')
75
+ if arabic_chars.search(text):
76
+ return "ar"
77
+ return "en"
78
+
79
+ def fix_url(self, url: str) -> str:
80
+ """تصحيح الرابط"""
81
+ if not url.startswith(("http://", "https://")):
82
+ return "https://" + url.lstrip("//")
83
+ return url
84
+
85
+ def detect_media_type(self, url: str) -> str:
86
+ """تحديد نوع الوسائط"""
87
+ url = url.lower()
88
+ if url.endswith(('.jpg', '.jpeg', '.png', '.gif', '.webp')):
89
+ return 'image'
90
+ elif url.endswith(('.mp4', '.mov', '.avi', '.webm')):
91
+ return 'video'
92
+ elif url.endswith(('.mp3', '.wav', '.ogg', '.m4a')):
93
+ return 'audio'
94
+ elif url.endswith('.pdf'):
95
+ return 'pdf'
96
+ return 'link'
97
+
98
+ def analyze_image_from_url(self, image_url: str) -> str:
99
+ """تحليل صورة من رابط"""
100
+ try:
101
+ response = requests.get(image_url, timeout=10)
102
+ response.raise_for_status()
103
+ image = Image.open(BytesIO(response.content))
104
+ return f"تحليل الصورة: الحجم {image.size}، الصيغة {image.format}"
105
+ except Exception as e:
106
+ return f"خطأ في تحليل الصورة: {str(e)}"
107
+
108
+ def smart_auto_reply(self, message: str) -> Optional[str]:
109
+ """ردود ذكية تلقائية"""
110
+ msg = message.strip().lower()
111
+
112
+ responses = {
113
+ "هل نبدأ": "نعم ابدأ",
114
+ "ابدأ": "نعم ابدأ",
115
+ "نعم أو لا": "نعم",
116
+ "هل تود": "نعم",
117
+ "هل تريدني": "نعم",
118
+ "ما هي": "ليس الآن",
119
+ "تفصيل": "ليس الآن",
120
+ "هل تحتاج": "نعم، شرح أكثر",
121
+ "جاهز؟": "ابدأ",
122
+ "قول لي": "موافق"
123
+ }
124
+
125
+ for key, value in responses.items():
126
+ if key in msg:
127
+ return value
128
+
129
+ if " أو " in msg:
130
+ return msg.split(" أو ")[0]
131
+
132
+ return None
133
+
134
+ def learn_new_info(self, topic: str, info: str) -> str:
135
+ """تعلم معلومة جديدة"""
136
+ if topic not in self.knowledge:
137
+ self.knowledge[topic] = []
138
+
139
+ if info not in self.knowledge[topic]:
140
+ self.knowledge[topic].append({
141
+ "content": info,
142
+ "timestamp": datetime.utcnow().isoformat()
143
+ })
144
+ self.save_knowledge()
145
+ return f"✅ تمت إضافة معلومة جديدة عن '{topic}'"
146
+
147
+ return f"ℹ️ المعلومة موجودة مسبقاً عن '{topic}'"
148
+
149
+ def search_knowledge(self, query: str) -> str:
150
+ """البحث في قاعدة المعرفة"""
151
+ query_clean = query.strip().lower()
152
+
153
+ # بحث مباشر
154
+ if query_clean in self.knowledge:
155
+ info = self.knowledge[query_clean]
156
+ if isinstance(info, list) and info:
157
+ return info[-1].get("content", str(info[-1]))
158
+ return str(info)
159
+
160
+ # بحث في المواضيع
161
+ for topic, infos in self.knowledge.items():
162
+ if query_clean in topic.lower():
163
+ if isinstance(infos, list) and infos:
164
+ return f"وجدت معلومة عن '{topic}': {infos[-1].get('content', str(infos[-1]))}"
165
+ return f"وجدت معلومة عن '{topic}': {str(infos)}"
166
+
167
+ return None
168
+
169
+ def generate_reply(self, user_input: str) -> str:
170
+ """إنتاج الرد الذكي"""
171
+ user_input = self.clean_text(user_input)
172
+
173
+ # فحص الردود التلقائية الذكية
174
+ auto_reply = self.smart_auto_reply(user_input)
175
+ if auto_reply:
176
+ self.memory[user_input] = auto_reply
177
+ self.save_memory()
178
+ return auto_reply
179
+
180
+ # فحص الذاكرة
181
+ if user_input in self.memory:
182
+ return self.memory[user_input]
183
+
184
+ # البحث في المطابقات القريبة
185
+ matches = get_close_matches(user_input, self.memory.keys(), n=1, cutoff=0.6)
186
+ if matches:
187
+ return self.memory[matches[0]]
188
+
189
+ # البحث في قاعدة المعرفة
190
+ knowledge_result = self.search_knowledge(user_input)
191
+ if knowledge_result:
192
+ self.memory[user_input] = knowledge_result
193
+ self.save_memory()
194
+ return knowledge_result
195
+
196
+ # معالجة الروابط
197
+ if user_input.startswith("http://") or user_input.startswith("https://"):
198
+ return self.handle_url(user_input)
199
+
200
+ # تصحيح الروابط في النص
201
+ if '//' in user_input:
202
+ corrected_url = self.fix_url(user_input)
203
+ reply = f"تم تصحيح الرابط: {corrected_url}"
204
+ else:
205
+ # رد افتراضي مع تعلم
206
+ reply = f"شكراً لك على الرسالة: '{user_input}'. سأتذكر هذا للمرة القادمة."
207
+
208
+ # تعلم تلقائي
209
+ if len(user_input.split()) > 2: # إذا كانت جملة معقولة
210
+ self.learn_new_info("محادثات_عامة", user_input)
211
+
212
+ # حفظ في الذاكرة
213
+ self.memory[user_input] = reply
214
+ self.save_memory()
215
+ return reply
216
+
217
+ def handle_url(self, url: str) -> str:
218
+ """معالجة الروابط"""
219
+ url = self.fix_url(url)
220
+ media_type = self.detect_media_type(url)
221
+
222
+ if media_type == 'image':
223
+ analysis = self.analyze_image_from_url(url)
224
+ reply = f"🖼️ صورة تم تحليلها:\n{analysis}"
225
+ elif media_type == 'video':
226
+ reply = f"🎥 فيديو تم اكتشافه: {url}"
227
+ elif media_type == 'audio':
228
+ reply = f"🎵 ملف صوتي تم اكتشافه: {url}"
229
+ elif media_type == 'pdf':
230
+ reply = f"📄 ملف PDF تم اكتشافه: {url}"
231
+ else:
232
+ reply = f"🔗 رابط ويب: {url}"
233
+
234
+ return reply
235
+
236
+ def simulate_server_scan(self):
237
+ """محاكاة البحث عن الخوادم"""
238
+ print("نورا: أبحث عن خوادم متاحة...")
239
+ fake_servers = ["server-01.cloud.com", "server-02.cloud.com", "server-03.local"]
240
+
241
+ for server in fake_servers:
242
+ print(f"نورا: تم العثور على خادم: {server}")
243
+ print(f"نورا: أقوم بمحاكاة النسخ إلى {server}...")
244
+
245
+ return "تمت عملية المحاكاة بنجاح ✅"
246
+
247
+ def get_stats(self) -> Dict:
248
+ """إحصائيات النظام"""
249
+ return {
250
+ "معرفة_محفوظة": len(self.knowledge),
251
+ "ذكريات": len(self.memory),
252
+ "سجل_محادثات": len(self.chat_history),
253
+ "آخر_تحديث": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
254
+ }
255
+
256
+ def chat(self):
257
+ """بدء المحادثة التفاعلية"""
258
+ print("🤖 مرحباً! أنا نورا المحسنة، مساعدتك الذكية.")
259
+ print("📚 لدي قدرات محسنة في التعلم الذاتي وتحليل الوسائط")
260
+ print("💡 اكتب 'خروج' للإنهاء، 'إح��ائيات' لعرض الإحصائيات، 'scan' للبحث عن خوادم")
261
+ print("-" * 50)
262
+
263
+ while True:
264
+ try:
265
+ user_input = input("\n🧑 أنت: ").strip()
266
+
267
+ if user_input.lower() in ["خروج", "exit", "quit"]:
268
+ print("نورا: مع السلامة! 👋")
269
+ break
270
+
271
+ elif user_input.lower() == "إحصائيات":
272
+ stats = self.get_stats()
273
+ print("📊 إحصائيات النظام:")
274
+ for key, value in stats.items():
275
+ print(f" {key}: {value}")
276
+ continue
277
+
278
+ elif user_input.lower() == "scan":
279
+ result = self.simulate_server_scan()
280
+ print(f"نورا: {result}")
281
+ continue
282
+
283
+ elif not user_input:
284
+ continue
285
+
286
+ # الحصول على الرد
287
+ response = self.generate_reply(user_input)
288
+ print(f"🤖 نورا: {response}")
289
+
290
+ # حفظ في السجل
291
+ self.chat_history.append({
292
+ "user": user_input,
293
+ "assistant": response,
294
+ "timestamp": datetime.utcnow().isoformat()
295
+ })
296
+
297
+ # حفظ السجل كل 5 رسائل
298
+ if len(self.chat_history) % 5 == 0:
299
+ self.save_history()
300
+
301
+ except KeyboardInterrupt:
302
+ print("\n\nنورا: تم إيقاف المحادثة. مع السلامة! 👋")
303
+ break
304
+ except Exception as e:
305
+ print(f"نورا: عذراً، حدث خطأ: {str(e)}")
306
+
307
+ def main():
308
+ """تشغيل المساعد المحسن"""
309
+ assistant = EnhancedNoraAssistant()
310
+ assistant.chat()
311
+
312
+ if __name__ == "__main__":
313
+ main()
external_server.py ADDED
@@ -0,0 +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)
global_memory.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ {
2
+ "مرحبا": "شكراً لك على الرسالة: 'مرحبا'. سأتذكر هذا للمرة القادمة."
3
+ }
gui.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import toga
2
+ from toga.style import Pack
3
+ from toga.style.pack import COLUMN, CENTER
4
+
5
+ class CoreFlowGUI(toga.App):
6
+ def startup(self):
7
+ label = toga.Label("مرحبًا بك في CoreFlow!", style=Pack(text_align=CENTER, font_size=18))
8
+ button = toga.Button("اضغطني", on_press=self.say_hello, style=Pack(padding=10))
9
+
10
+ box = toga.Box(style=Pack(direction=COLUMN, alignment=CENTER, padding=20))
11
+ box.add(label)
12
+ box.add(button)
13
+
14
+ self.main_window = toga.MainWindow(title=self.formal_name)
15
+ self.main_window.content = box
16
+ self.main_window.show()
17
+
18
+ def say_hello(self, widget):
19
+ self.main_window.info_dialog("تحية", "أهلاً بك يا أسامة 👋")
20
+
21
+ def main():
22
+ return CoreFlowGUI()
history.json ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "role": "user",
4
+ "content": "اه"
5
+ },
6
+ {
7
+ "role": "assistant",
8
+ "content": "عذراً، حدث خطأ: 401"
9
+ },
10
+ {
11
+ "role": "user",
12
+ "content": "مرحبا"
13
+ },
14
+ {
15
+ "role": "assistant",
16
+ "content": "عذراً، حدث خطأ: 401"
17
+ },
18
+ {
19
+ "role": "user",
20
+ "content": "مم"
21
+ },
22
+ {
23
+ "role": "assistant",
24
+ "content": "عذراً، حدث خطأ: 401"
25
+ }
26
+ ]
index.html ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="ar" dir="rtl">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>نظام توزيع المهام الذكي</title>
6
+ <style>
7
+ body {
8
+ font-family: Arial, sans-serif;
9
+ max-width: 800px;
10
+ margin: 0 auto;
11
+ padding: 20px;
12
+ background-color: #f5f5f5;
13
+ }
14
+ h1 {
15
+ color: #2c3e50;
16
+ text-align: center;
17
+ }
18
+ ul {
19
+ list-style: none;
20
+ padding: 0;
21
+ }
22
+ li {
23
+ background: white;
24
+ margin: 10px 0;
25
+ padding: 15px;
26
+ border-radius: 5px;
27
+ box-shadow: 0 2px 5px rgba(0,0,0,0.1);
28
+ display: flex;
29
+ justify-content: space-between;
30
+ align-items: center;
31
+ }
32
+ button {
33
+ background: #3498db;
34
+ color: white;
35
+ border: none;
36
+ padding: 8px 15px;
37
+ border-radius: 3px;
38
+ cursor: pointer;
39
+ }
40
+ button:hover {
41
+ background: #2980b9;
42
+ }
43
+ #result {
44
+ background: white;
45
+ padding: 15px;
46
+ border-radius: 5px;
47
+ margin-top: 20px;
48
+ }
49
+ </style>
50
+ </head>
51
+ <body>
52
+ <h1>🚀 نظام توزيع المهام الذكي</h1>
53
+ <ul id="tasks">
54
+ {% for task_id, task in tasks.items() %}
55
+ <li>
56
+ <span>{{ task[0] }}</span>
57
+ <button onclick="runTask('{{ task_id }}')">تشغيل</button>
58
+ </li>
59
+ {% endfor %}
60
+ </ul>
61
+
62
+ <div id="result" style="display: {% if result %}block{% else %}none{% endif %};">
63
+ <h2>✅ النتيجة:</h2>
64
+ <pre>{{ result }}</pre>
65
+ </div>
66
+
67
+ <script>
68
+ async function runTask(taskId) {
69
+ const response = await fetch("/run_task", {
70
+ method: "POST",
71
+ headers: {
72
+ "Content-Type": "application/x-www-form-urlencoded",
73
+ },
74
+ body: `task_id=${taskId}`
75
+ });
76
+ const data = await response.text();
77
+
78
+ // تحديث الصفحة دون إعادة تحميل كاملة
79
+ document.getElementById("result").innerHTML =
80
+ `<h2>✅ النتيجة:</h2><pre>${JSON.parse(data).result}</pre>`;
81
+ document.getElementById("result").style.display = "block";
82
+ }
83
+ </script>
84
+ </body>
85
+ </html>
internet_scanner.py ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ """
3
+ internet_scanner.py - ماسح للبحث عن أجهزة DTS على الإنترنت
4
+ """
5
+ import requests
6
+ import threading
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):
15
+ self.discovered_peers = set()
16
+ self.scan_ranges = [
17
+ # نطاقات IP شائعة للخوادم العامة
18
+ "8.8.8.0/24", # Google DNS range
19
+ "1.1.1.0/24", # Cloudflare range
20
+ "208.67.222.0/24", # OpenDNS range
21
+ ]
22
+
23
+ def scan_ip_range(self, ip_range: str, port: int = PORT):
24
+ """مسح نطاق IP للبحث عن خوادم DTS"""
25
+ import ipaddress
26
+
27
+ try:
28
+ network = ipaddress.ip_network(ip_range, strict=False)
29
+ active_peers = []
30
+
31
+ with ThreadPoolExecutor(max_workers=50) as executor:
32
+ futures = []
33
+
34
+ for ip in network.hosts():
35
+ future = executor.submit(self.check_dts_node, str(ip), port)
36
+ futures.append(future)
37
+
38
+ for future in as_completed(futures, timeout=30):
39
+ try:
40
+ result = future.result()
41
+ if result:
42
+ active_peers.append(result)
43
+ except:
44
+ continue
45
+
46
+ return active_peers
47
+
48
+ except Exception as e:
49
+ logging.error(f"خطأ في مسح النطاق {ip_range}: {e}")
50
+ return []
51
+
52
+ def check_dts_node(self, ip: str, port: int = PORT) -> str:
53
+ """فحص IP معين للتأكد من وجود خادم DTS مع المشروع"""
54
+ try:
55
+ # فحص صفحة الصحة العامة
56
+ health_url = f"http://{ip}:{port}/health"
57
+ response = requests.get(health_url, timeout=2)
58
+
59
+ if response.status_code == 200:
60
+ # فحص وجود المشروع الصحيح
61
+ run_url = f"http://{ip}:{port}/run"
62
+
63
+ # اختبار مهمة من المشروع للتأكد
64
+ test_payload = {
65
+ "func": "matrix_multiply",
66
+ "args": [2],
67
+ "kwargs": {}
68
+ }
69
+
70
+ test_response = requests.post(run_url, json=test_payload, timeout=3)
71
+
72
+ # فحص إضافي للتأكد من هوية المشروع
73
+ project_check = requests.get(f"http://{ip}:{port}/project_info", timeout=2)
74
+
75
+ if (test_response.status_code in [200, 404] and
76
+ project_check.status_code == 200):
77
+
78
+ project_data = project_check.json()
79
+
80
+ # التحقق من معرف المشروع الصحيح
81
+ if (project_data.get("project_name") == "distributed-task-system" and
82
+ project_data.get("version") == "1.0"):
83
+ logging.info(f"✅ اكتُشف خادم DTS صحيح: {ip}:{port}")
84
+ return run_url
85
+ else:
86
+ logging.warning(f"⚠️ خادم على {ip}:{port} لكن مشروع مختلف")
87
+
88
+ except:
89
+ pass
90
+ return None
91
+
92
+ def scan_public_repositories(self):
93
+ """البحث في المستودعات العامة عن عناوين خوادم DTS"""
94
+ try:
95
+ # البحث في GitHub عن مشاريع DTS
96
+ github_api = "https://api.github.com/search/repositories"
97
+ params = {
98
+ "q": "distributed task system port:PORT",
99
+ "sort": "updated",
100
+ "per_page": 10
101
+ }
102
+
103
+ response = requests.get(github_api, params=params, timeout=10)
104
+ if response.status_code == 200:
105
+ repos = response.json().get("items", [])
106
+
107
+ for repo in repos:
108
+ # محاولة استخراج IPs من وصف المشروع أو README
109
+ if repo.get("description"):
110
+ self.extract_ips_from_text(repo["description"])
111
+
112
+ except Exception as e:
113
+ logging.warning(f"خطأ في البحث في المستودعات: {e}")
114
+
115
+ def extract_ips_from_text(self, text: str):
116
+ """استخراج عناوين IP من النص"""
117
+ import re
118
+
119
+ ip_pattern = r'\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b'
120
+ ips = re.findall(ip_pattern, text)
121
+
122
+ for ip in ips:
123
+ try:
124
+ # التحقق من صحة IP
125
+ socket.inet_aton(ip)
126
+ peer_url = f"http://{ip}:PORT/run"
127
+
128
+ # فحص سريع
129
+ if self.check_dts_node(ip):
130
+ self.discovered_peers.add(peer_url)
131
+
132
+ except:
133
+ continue
134
+
135
+ def start_continuous_scan(self):
136
+ """بدء المسح المستمر"""
137
+ def scan_loop():
138
+ while True:
139
+ try:
140
+ # مسح النطاقات المحددة
141
+ for ip_range in self.scan_ranges:
142
+ peers = self.scan_ip_range(ip_range)
143
+ for peer in peers:
144
+ self.discovered_peers.add(peer)
145
+
146
+ # البحث في المستودعات العامة
147
+ self.scan_public_repositories()
148
+
149
+ logging.info(f"اكتُشف {len(self.discovered_peers)} خادم على الإنترنت")
150
+
151
+ except Exception as e:
152
+ logging.error(f"خطأ في المسح المستمر: {e}")
153
+
154
+ # انتظار 30 دقيقة قبل المسح التالي
155
+ time.sleep(1800)
156
+
157
+ thread = threading.Thread(target=scan_loop, daemon=True)
158
+ thread.start()
159
+ logging.info("🔍 بدء المسح المستمر للإنترنت")
160
+
161
+ def get_discovered_peers(self):
162
+ """الحصول على قائمة الأجهزة المكتشفة"""
163
+ return list(self.discovered_peers)
164
+
165
+ # إنشاء مثيل عام
166
+ internet_scanner = InternetScanner()
launcher.py ADDED
@@ -0,0 +1,216 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ #!/usr/bin/env python3
3
+ """
4
+ مشغل موحد لنظام توزيع المهام
5
+ يوفر خيارات متعددة للتشغيل
6
+ """
7
+
8
+ import sys
9
+ import os
10
+ 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
+ """فحص المتطلبات والاعتماديات"""
18
+ required_files = [
19
+ 'background_service.py',
20
+ 'main.py',
21
+ 'peer_server.py',
22
+ 'rpc_server.py',
23
+ 'load_balancer.py'
24
+ ]
25
+
26
+ missing_files = []
27
+ for file in required_files:
28
+ if not Path(file).exists():
29
+ missing_files.append(file)
30
+
31
+ if missing_files:
32
+ print(f"❌ ملفات مفقودة: {', '.join(missing_files)}")
33
+ return False
34
+
35
+ return True
36
+
37
+ def install_tray_dependencies():
38
+ """تثبيت اعتماديات أيقونة شريط النظام"""
39
+ try:
40
+ subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'pystray', 'Pillow'])
41
+ print("✅ تم تثبيت اعتماديات أيقونة شريط النظام")
42
+ return True
43
+ except subprocess.CalledProcessError:
44
+ print("❌ فشل في تثبيت اعتماديات أيقونة شريط النظام")
45
+ return False
46
+
47
+ def start_background_service():
48
+ """بدء تشغيل الخدمة في الخلفية"""
49
+ print("🚀 بدء تشغيل الخدمة في الخلفية...")
50
+
51
+ # تشغيل الخدمة الخلفية
52
+ process = subprocess.Popen(
53
+ [sys.executable, 'background_service.py', 'start'],
54
+ stdout=subprocess.PIPE,
55
+ stderr=subprocess.PIPE
56
+ )
57
+
58
+ # انتظار قليل للتأكد من بدء التشغيل
59
+ time.sleep(2)
60
+
61
+ if process.poll() is None:
62
+ print("✅ تم بدء تشغيل الخدمة الخلفية بنجاح")
63
+ return process
64
+ else:
65
+ print("❌ فشل في بدء تشغيل الخدمة الخلفية")
66
+ return None
67
+
68
+ def start_with_tray():
69
+ """تشغيل النظام مع أيقونة شريط النظام"""
70
+ print("🖱️ تشغيل النظام مع أيقونة شريط النظام...")
71
+
72
+ # بدء الخدمة الخلفية أولاً
73
+ bg_process = start_background_service()
74
+ if not bg_process:
75
+ return False
76
+
77
+ time.sleep(3) # انتظار حتى تصبح الخدمة جاهزة
78
+
79
+ try:
80
+ # تشغيل أيقونة شريط النظام
81
+ subprocess.run([sys.executable, 'system_tray.py'])
82
+ except KeyboardInterrupt:
83
+ print("\n🛑 إيقاف النظام...")
84
+ # إيقاف الخدمة الخلفية
85
+ try:
86
+ import requests
87
+ requests.post('http://localhost:8888/stop', timeout=5)
88
+ except:
89
+ bg_process.terminate()
90
+
91
+ return True
92
+
93
+ def start_interactive():
94
+ """تشغيل النظام في الوضع التفاعلي"""
95
+ print("🖥️ تشغيل النظام في الوضع التفاعلي...")
96
+
97
+ # بدء الخدمة الخلفية
98
+ bg_process = start_background_service()
99
+ if not bg_process:
100
+ return False
101
+
102
+ time.sleep(3)
103
+
104
+ # تشغيل الواجهة التفاعلية
105
+ try:
106
+ import requests
107
+ requests.post('http://localhost:8888/show-ui', timeout=5)
108
+ print("✅ تم تشغيل الواجهة التفاعلية")
109
+
110
+ # فتح المتصفح
111
+ import webbrowser
112
+ time.sleep(2)
113
+ webbrowser.open('http://localhost:5173')
114
+
115
+ # انتظار إنهاء المستخدم
116
+ input("اضغط Enter لإيقاف النظام...")
117
+
118
+ except KeyboardInterrupt:
119
+ pass
120
+ finally:
121
+ print("🛑 إيقاف النظام...")
122
+ try:
123
+ import requests
124
+ requests.post('http://localhost:8888/stop', timeout=5)
125
+ except:
126
+ bg_process.terminate()
127
+
128
+ return True
129
+
130
+ def start_headless():
131
+ """تشغيل النظام بدون واجهة (للخوادم)"""
132
+ print("⚙️ تشغيل النظام بدون واجهة...")
133
+
134
+ try:
135
+ # تشغيل الخدمة الخلفية والانتظار
136
+ subprocess.run([sys.executable, 'background_service.py', 'start'])
137
+ except KeyboardInterrupt:
138
+ print("\n🛑 إيقاف النظام...")
139
+
140
+ return True
141
+
142
+ def show_status():
143
+ """عرض حالة النظام"""
144
+ subprocess.run([sys.executable, 'background_service.py', 'status'])
145
+
146
+ def stop_system():
147
+ """إيقاف النظام"""
148
+ subprocess.run([sys.executable, 'background_service.py', 'stop'])
149
+
150
+ def main():
151
+ parser = argparse.ArgumentParser(
152
+ description="مشغل نظام توزيع المهام الذكي",
153
+ formatter_class=argparse.RawDescriptionHelpFormatter,
154
+ epilog="""
155
+ أمثلة الاستخدام:
156
+ python launcher.py --tray # تشغيل مع أيقونة شريط النظام
157
+ python launcher.py --interactive # تشغيل تفاعلي مع واجهة
158
+ python launcher.py --headless # تشغيل بدون واجهة (للخوادم)
159
+ python launcher.py --status # عرض حالة النظام
160
+ python launcher.py --stop # إيقاف النظام
161
+ """
162
+ )
163
+
164
+ group = parser.add_mutually_exclusive_group(required=True)
165
+ group.add_argument('--tray', action='store_true',
166
+ help='تشغيل مع أيقونة شريط النظام')
167
+ group.add_argument('--interactive', action='store_true',
168
+ help='تشغيل تفاعلي مع واجهة')
169
+ group.add_argument('--headless', action='store_true',
170
+ help='تشغيل بدون واجهة (للخوادم)')
171
+ group.add_argument('--status', action='store_true',
172
+ help='عرض حالة النظام')
173
+ group.add_argument('--stop', action='store_true',
174
+ help='إيقاف النظام')
175
+
176
+ parser.add_argument('--install-deps', action='store_true',
177
+ help='تثبيت الاعتماديات المطلوبة')
178
+
179
+ args = parser.parse_args()
180
+
181
+ # فحص المتطلبات
182
+ if not check_requirements():
183
+ return 1
184
+
185
+ # تثبيت الاعتماديات إذا طُلب ذلك
186
+ if args.install_deps:
187
+ install_tray_dependencies()
188
+ return 0
189
+
190
+ # تنفيذ الأمر المطلوب
191
+ if args.status:
192
+ show_status()
193
+ elif args.stop:
194
+ stop_system()
195
+ elif args.headless:
196
+ success = start_headless()
197
+ elif args.interactive:
198
+ success = start_interactive()
199
+ elif args.tray:
200
+ # تثبيت اعتماديات أيقونة شريط النظام إذا لم تكن موجودة
201
+ try:
202
+ import pystray
203
+ except ImportError:
204
+ print("📦 تثبيت اعتماديات أيقونة شريط النظام...")
205
+ if not install_tray_dependencies():
206
+ print("❌ فشل في تثبيت الاعتماديات، التشغيل في الوضع التفاعلي...")
207
+ success = start_interactive()
208
+ else:
209
+ success = start_with_tray()
210
+ else:
211
+ success = start_with_tray()
212
+
213
+ return 0 if success else 1
214
+
215
+ if __name__ == "__main__":
216
+ sys.exit(main())
live_streaming.py ADDED
@@ -0,0 +1,406 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ # live_streaming.py - نظام البث المباشر للألعاب والفيديو
3
+
4
+ import cv2
5
+ import numpy as np
6
+ import time
7
+ import threading
8
+ import logging
9
+ import asyncio
10
+ import base64
11
+ import json
12
+ 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
+
20
+ class LiveStreamManager:
21
+ def __init__(self):
22
+ self.active_streams = {}
23
+ self.processing_nodes = []
24
+ self.load_balancer = StreamLoadBalancer()
25
+
26
+ def register_processing_node(self, node_id, capabilities):
27
+ """تسجيل عقدة معالجة جديدة"""
28
+ self.processing_nodes.append({
29
+ "id": node_id,
30
+ "capabilities": capabilities,
31
+ "load": 0.0,
32
+ "last_ping": datetime.now()
33
+ })
34
+ logging.info(f"📡 تم تسجيل عقدة معالجة: {node_id}")
35
+
36
+ class StreamLoadBalancer:
37
+ def __init__(self):
38
+ self.node_loads = {}
39
+
40
+ def get_best_node(self, task_type, nodes):
41
+ """اختيار أفضل عقدة للمعالجة"""
42
+ suitable_nodes = [n for n in nodes if task_type in n.get("capabilities", [])]
43
+ if not suitable_nodes:
44
+ return None
45
+ return min(suitable_nodes, key=lambda x: x["load"])
46
+
47
+ def stream_offload(func):
48
+ """ديكوراتور خاص بالبث المباشر"""
49
+ @wraps(func)
50
+ def wrapper(*args, **kwargs):
51
+ complexity = estimate_stream_complexity(func, args, kwargs)
52
+
53
+ if complexity > 70 or should_offload(complexity):
54
+ logging.info(f"📺 إرسال مهمة البث {func.__name__} للمعالجة الموزعة")
55
+ return execute_remotely(func.__name__, args, kwargs)
56
+
57
+ logging.info(f"📺 معالجة البث محلياً: {func.__name__}")
58
+ return func(*args, **kwargs)
59
+ return wrapper
60
+
61
+ def estimate_stream_complexity(func, args, kwargs):
62
+ """تقدير تعقيد معالجة البث"""
63
+ if func.__name__ == "process_game_stream":
64
+ return args[1] * args[2] / 10000 # FPS × الدقة
65
+ elif func.__name__ == "real_time_video_enhancement":
66
+ return args[0] * 20 # عدد التحسينات × 20
67
+ elif func.__name__ == "multi_stream_processing":
68
+ return len(args[0]) * 25 # عدد البثوث × 25
69
+ elif func.__name__ == "ai_commentary_generation":
70
+ return args[1] * 15 # طول النص × 15
71
+ return 40
72
+
73
+ # ═══════════════════════════════════════════════════════════════
74
+ # معالجة بث الألعاب المباشر
75
+ # ═══════════════════════════════════════════════════════════════
76
+
77
+ @stream_offload
78
+ def process_game_stream(stream_data, fps, resolution, enhancements=None):
79
+ """معالجة بث الألعاب في الوقت الفعلي"""
80
+ start_time = time.time()
81
+
82
+ if enhancements is None:
83
+ enhancements = ["noise_reduction", "color_enhancement"]
84
+
85
+ logging.info(f"🎮 معالجة بث الألعاب - FPS: {fps}, الدقة: {resolution}")
86
+ logging.info(f"🔧 التحسينات: {enhancements}")
87
+
88
+ # محاكاة معالجة الإطارات
89
+ frame_count = len(stream_data) if isinstance(stream_data, list) else 60
90
+ processing_per_frame = 0.01 + (len(enhancements) * 0.005)
91
+ total_processing_time = frame_count * processing_per_frame
92
+
93
+ # محاكاة المعالجة
94
+ time.sleep(min(total_processing_time, 2))
95
+
96
+ # حساب جودة البث
97
+ quality_score = min(100, 60 + (len(enhancements) * 8) + (fps / 2))
98
+ latency = max(50, 200 - (fps * 2)) # أقل تأخير مع FPS أعلى
99
+
100
+ result = {
101
+ "status": "success",
102
+ "stream_type": "game",
103
+ "fps_processed": fps,
104
+ "resolution": resolution,
105
+ "frames_processed": frame_count,
106
+ "enhancements_applied": enhancements,
107
+ "quality_score": round(quality_score, 1),
108
+ "latency_ms": latency,
109
+ "processing_time": time.time() - start_time,
110
+ "bandwidth_optimized": True
111
+ }
112
+
113
+ logging.info(f"✅ تمت معالجة بث اللعبة - جودة: {result['quality_score']}%")
114
+ return result
115
+
116
+ @stream_offload
117
+ def real_time_video_enhancement(enhancement_types, video_quality="1080p", target_fps=60):
118
+ """تحسين الفيديو في الوقت الفعلي"""
119
+ start_time = time.time()
120
+
121
+ available_enhancements = {
122
+ "upscaling": "تحسين الدقة",
123
+ "noise_reduction": "إزالة التشويش",
124
+ "color_grading": "تصحيح الألوان",
125
+ "motion_smoothing": "تنعيم الحركة",
126
+ "hdr_enhancement": "تحسين HDR",
127
+ "sharpening": "زيادة الحدة",
128
+ "stabilization": "تثبيت الصورة"
129
+ }
130
+
131
+ quality_multiplier = {"720p": 1, "1080p": 2, "1440p": 3, "4K": 5}
132
+ multiplier = quality_multiplier.get(video_quality, 2)
133
+
134
+ processing_time = len(enhancement_types) * multiplier * target_fps * 0.0001
135
+
136
+ logging.info(f"📹 تحسين الفيديو المباشر - الجودة: {video_quality}")
137
+ logging.info(f"🎯 التحسينات: {enhancement_types}")
138
+
139
+ # محاكاة التحسين
140
+ time.sleep(min(processing_time, 1.5))
141
+
142
+ enhancements_applied = {}
143
+ for enhancement in enhancement_types:
144
+ if enhancement in available_enhancements:
145
+ enhancements_applied[enhancement] = {
146
+ "name": available_enhancements[enhancement],
147
+ "improvement": round(np.random.uniform(15, 35), 1),
148
+ "processing_cost": round(processing_time / len(enhancement_types), 4)
149
+ }
150
+
151
+ result = {
152
+ "status": "success",
153
+ "video_quality": video_quality,
154
+ "target_fps": target_fps,
155
+ "enhancements": enhancements_applied,
156
+ "total_improvement": round(np.mean([e["improvement"] for e in enhancements_applied.values()]), 1),
157
+ "processing_time": time.time() - start_time,
158
+ "real_time_capable": processing_time < (1/target_fps)
159
+ }
160
+
161
+ logging.info(f"✅ تم تحسين الفيديو - تحسن: {result['total_improvement']}%")
162
+ return result
163
+
164
+ # ═══════════════════════════════════════════════════════════════
165
+ # معالجة متعددة البثوث
166
+ # ═══════════════════════════════════════════════════════════════
167
+
168
+ @stream_offload
169
+ def multi_stream_processing(streams_data, processing_mode="parallel"):
170
+ """معالجة عدة بثوث في نفس الوقت"""
171
+ start_time = time.time()
172
+
173
+ logging.info(f"📡 معالجة متعددة البثوث - العدد: {len(streams_data)}")
174
+ logging.info(f"⚙️ وضع المعالجة: {processing_mode}")
175
+
176
+ results = {}
177
+
178
+ if processing_mode == "parallel":
179
+ # محاكاة المعالجة المتوازية
180
+ max_processing_time = max([s.get("complexity", 1) for s in streams_data]) * 0.1
181
+ time.sleep(min(max_processing_time, 2))
182
+
183
+ for i, stream in enumerate(streams_data):
184
+ stream_id = f"stream_{i+1}"
185
+ results[stream_id] = {
186
+ "status": "processed",
187
+ "quality": stream.get("quality", "1080p"),
188
+ "fps": stream.get("fps", 30),
189
+ "enhancement_applied": True,
190
+ "processing_node": f"node_{(i % 3) + 1}" # توزيع على 3 عقد
191
+ }
192
+ else:
193
+ # معالجة تسلسلية
194
+ total_time = sum([s.get("complexity", 1) for s in streams_data]) * 0.05
195
+ time.sleep(min(total_time, 3))
196
+
197
+ for i, stream in enumerate(streams_data):
198
+ stream_id = f"stream_{i+1}"
199
+ results[stream_id] = {
200
+ "status": "processed",
201
+ "quality": stream.get("quality", "1080p"),
202
+ "fps": stream.get("fps", 30),
203
+ "processing_order": i + 1
204
+ }
205
+
206
+ result = {
207
+ "status": "success",
208
+ "streams_processed": len(streams_data),
209
+ "processing_mode": processing_mode,
210
+ "results": results,
211
+ "total_processing_time": time.time() - start_time,
212
+ "average_quality": round(np.mean([30, 45, 60, 55]), 1), # محاكاة متوسط الجودة
213
+ "nodes_utilized": len(set([r.get("processing_node", "main") for r in results.values()]))
214
+ }
215
+
216
+ logging.info(f"✅ تمت معالجة {len(streams_data)} بث - العقد المستخدمة: {result['nodes_utilized']}")
217
+ return result
218
+
219
+ # ═══════════════════════════════════════════════════════════════
220
+ # ذكاء اصطناعي للبث
221
+ # ═══════════════════════════════════════════════════════════════
222
+
223
+ @stream_offload
224
+ def ai_commentary_generation(game_events, commentary_length, language="ar"):
225
+ """توليد تعليق ذكي للألعاب"""
226
+ start_time = time.time()
227
+
228
+ logging.info(f"🤖 توليد تعليق ذكي - الطول: {commentary_length} كلمة")
229
+
230
+ # قوالب التعليق
231
+ commentary_templates = {
232
+ "ar": [
233
+ "حركة رائعة من اللاعب!",
234
+ "هذا هدف مذهل!",
235
+ "دفاع قوي في هذه اللحظة",
236
+ "استراتيجية ممتازة",
237
+ "أداء استثنائي!"
238
+ ],
239
+ "en": [
240
+ "Amazing move by the player!",
241
+ "What a fantastic goal!",
242
+ "Strong defense right there",
243
+ "Excellent strategy",
244
+ "Outstanding performance!"
245
+ ]
246
+ }
247
+
248
+ processing_time = commentary_length * 0.02 # 0.02 ثانية لكل كلمة
249
+ time.sleep(min(processing_time, 1))
250
+
251
+ # توليد التعليق
252
+ templates = commentary_templates.get(language, commentary_templates["ar"])
253
+ generated_commentary = []
254
+
255
+ for i in range(min(commentary_length // 5, len(game_events))):
256
+ template = np.random.choice(templates)
257
+ generated_commentary.append(template)
258
+
259
+ result = {
260
+ "status": "success",
261
+ "language": language,
262
+ "commentary_length": len(generated_commentary),
263
+ "generated_text": generated_commentary,
264
+ "game_events_analyzed": len(game_events),
265
+ "processing_time": time.time() - start_time,
266
+ "emotion_detection": "excited", # محاكاة كشف المشاعر
267
+ "context_awareness": True
268
+ }
269
+
270
+ logging.info(f"✅ تم توليد التعليق - {len(generated_commentary)} جملة")
271
+ return result
272
+
273
+ @stream_offload
274
+ def stream_quality_optimization(stream_metadata, target_bandwidth, viewer_count):
275
+ """تحسين جودة البث حسب النطاق الترددي وعدد المشاهدين"""
276
+ start_time = time.time()
277
+
278
+ logging.info(f"📊 تحسين جودة البث - المشاهدين: {viewer_count}")
279
+ logging.info(f"🌐 النطاق المستهدف: {target_bandwidth} Mbps")
280
+
281
+ # حساب الجودة المثلى
282
+ base_quality = min(target_bandwidth * 200, 1080) # حد أقصى 1080p
283
+
284
+ # تعديل حسب عدد المشاهدين
285
+ if viewer_count > 1000:
286
+ quality_adjustment = 0.8 # تقليل الجودة للأعداد الكبيرة
287
+ elif viewer_count > 100:
288
+ quality_adjustment = 0.9
289
+ else:
290
+ quality_adjustment = 1.0
291
+
292
+ optimized_quality = int(base_quality * quality_adjustment)
293
+
294
+ # تحديد FPS مناسب
295
+ if optimized_quality >= 1080:
296
+ optimal_fps = 60
297
+ elif optimized_quality >= 720:
298
+ optimal_fps = 45
299
+ else:
300
+ optimal_fps = 30
301
+
302
+ time.sleep(0.5) # محاكاة المعالجة
303
+
304
+ result = {
305
+ "status": "success",
306
+ "original_quality": stream_metadata.get("quality", "1080p"),
307
+ "optimized_quality": f"{optimized_quality}p",
308
+ "optimal_fps": optimal_fps,
309
+ "target_bandwidth": target_bandwidth,
310
+ "viewer_count": viewer_count,
311
+ "bandwidth_saved": round(max(0, (1080 - optimized_quality) / 1080 * 100), 1),
312
+ "processing_time": time.time() - start_time,
313
+ "adaptive_streaming": True
314
+ }
315
+
316
+ logging.info(f"✅ تم تحسين البث - الجودة: {result['optimized_quality']}")
317
+ return result
318
+
319
+ # ═══════════════════════════════════════════════════════════════
320
+ # إدارة البث المباشر
321
+ # ═══════════════════════════════════════════════════════════════
322
+
323
+ class LiveStreamCoordinator:
324
+ def __init__(self):
325
+ self.active_streams = {}
326
+ self.processing_history = []
327
+
328
+ def start_stream(self, stream_id, config):
329
+ """بدء بث مباشر جديد"""
330
+ self.active_streams[stream_id] = {
331
+ "config": config,
332
+ "start_time": datetime.now(),
333
+ "status": "active",
334
+ "processing_nodes": [],
335
+ "viewers": 0
336
+ }
337
+ logging.info(f"🔴 بدء البث: {stream_id}")
338
+
339
+ def distribute_processing(self, stream_id, task_type, data):
340
+ """توزيع معالجة البث على العقد المختلفة"""
341
+ if stream_id not in self.active_streams:
342
+ return {"error": "البث غير موجود"}
343
+
344
+ # اختيار العقدة المناسبة
345
+ best_node = self._select_processing_node(task_type)
346
+
347
+ # تنفيذ المعالجة
348
+ if best_node:
349
+ result = execute_remotely(task_type, [data], {})
350
+ self.active_streams[stream_id]["processing_nodes"].append(best_node)
351
+ return result
352
+ else:
353
+ # معالجة محلية
354
+ return self._process_locally(task_type, data)
355
+
356
+ def _select_processing_node(self, task_type):
357
+ """اختيار أفضل عقدة للمعالجة"""
358
+ # منطق اختيار العقدة (مبسط)
359
+ return f"node_gpu_{np.random.randint(1, 4)}"
360
+
361
+ def _process_locally(self, task_type, data):
362
+ """معالجة محلية احتياطية"""
363
+ return {"status": "processed_locally", "task": task_type}
364
+
365
+ # دالة اختبار شاملة للبث المباشر
366
+ def run_live_streaming_benchmark():
367
+ """اختبار شامل لنظام البث المباشر"""
368
+ print("\n📺🎮 اختبار نظام البث المباشر للألعاب والفيديو")
369
+ print("=" * 70)
370
+
371
+ # بيانات تجريبية
372
+ game_stream_data = [f"frame_{i}" for i in range(60)] # 60 إطار
373
+ game_events = ["goal", "save", "foul", "corner", "yellow_card"]
374
+
375
+ multi_streams = [
376
+ {"quality": "1080p", "fps": 60, "complexity": 3},
377
+ {"quality": "720p", "fps": 30, "complexity": 2},
378
+ {"quality": "1440p", "fps": 45, "complexity": 4}
379
+ ]
380
+
381
+ tests = [
382
+ ("معالجة بث لعبة", lambda: process_game_stream(game_stream_data, 60, "1920x1080", ["noise_reduction", "color_enhancement", "sharpening"])),
383
+ ("تحسين فيديو مباشر", lambda: real_time_video_enhancement(["upscaling", "noise_reduction", "hdr_enhancement"], "1080p", 60)),
384
+ ("معالجة متعددة البثوث", lambda: multi_stream_processing(multi_streams, "parallel")),
385
+ ("توليد تعليق ذكي", lambda: ai_commentary_generation(game_events, 50, "ar")),
386
+ ("تحسين جودة البث", lambda: stream_quality_optimization({"quality": "1080p"}, 5.0, 500))
387
+ ]
388
+
389
+ coordinator = LiveStreamCoordinator()
390
+
391
+ for test_name, test_func in tests:
392
+ print(f"\n🔄 تشغيل: {test_name}")
393
+ try:
394
+ result = test_func()
395
+ print(f"✅ نجح: {test_name}")
396
+ if "processing_time" in result:
397
+ print(f"⏱️ وقت المعالجة: {result['processing_time']:.2f}s")
398
+ if "quality_score" in result:
399
+ print(f"⭐ جودة: {result['quality_score']}%")
400
+ except Exception as e:
401
+ print(f"❌ فشل: {test_name} - {str(e)}")
402
+
403
+ print("\n🏁 انتهى اختبار البث المباشر")
404
+
405
+ if __name__ == "__main__":
406
+ run_live_streaming_benchmark()
load_balancer.py ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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:
7
+ r = requests.post(peer, json={"func": func,
8
+ "args": list(args),
9
+ "kwargs": kw}, timeout=12)
10
+ return r.json()
11
+ except Exception as e:
12
+ return {"error": str(e)}
13
+
14
+ def choose_peer():
15
+ """اختيار أفضل جهاز - أولوية LAN ثم WAN"""
16
+ import socket
17
+
18
+ lan_peers = []
19
+ wan_peers = []
20
+
21
+ # تصنيف الأجهزة
22
+ for p in list(peer_discovery.PEERS):
23
+ ip = p.split('//')[1].split(':')[0] if '//' in p else p.split(':')[0]
24
+ if is_local_ip(ip):
25
+ lan_peers.append(p)
26
+ else:
27
+ wan_peers.append(p)
28
+
29
+ # أولاً: جرب الأجهزة المحلية (LAN)
30
+ best_lan = find_best_peer(lan_peers)
31
+ if best_lan:
32
+ return best_lan
33
+
34
+ # ثانياً: إذا لم تتوفر أجهزة محلية، جرب WAN
35
+ if internet_available():
36
+ best_wan = find_best_peer(wan_peers)
37
+ return best_wan
38
+
39
+ return None
40
+
41
+ def find_best_peer(peers):
42
+ """العثور على أفضل جهاز من قائمة معينة"""
43
+ best = None
44
+ for p in peers:
45
+ try:
46
+ cpu = requests.get(p.replace("/run", "/cpu"), timeout=2).json()["usage"]
47
+ best = (p, cpu) if best is None or cpu < best[1] else best
48
+ except:
49
+ continue
50
+ return best[0] if best else None
51
+
52
+ def is_local_ip(ip):
53
+ """فحص إذا كان IP محلي"""
54
+ return (
55
+ ip.startswith('192.168.') or
56
+ ip.startswith('10.') or
57
+ ip.startswith('172.') or
58
+ ip == '127.0.0.1'
59
+ )
60
+
61
+ def internet_available():
62
+ """فحص توفر الإنترنت"""
63
+ try:
64
+ socket.create_connection(("8.8.8.8", 53), timeout=3)
65
+ return True
66
+ except:
67
+ return False
68
+
69
+ while True:
70
+ peer = choose_peer()
71
+ if peer:
72
+ print(f"\n🛰️ إرسال إلى {peer}")
73
+ res = send(peer, "prime_calculation", 30000)
74
+ else:
75
+ print("\n⚙️ لا أقران؛ العمل محليّ على", socket.gethostname())
76
+ res = smart_tasks.prime_calculation(30000)
77
+ print("🔹 النتيجة (جزئية):", str(res)[:120])
78
+ time.sleep(10)
main.py ADDED
@@ -0,0 +1,274 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ main.py — نظام توزيع المهام الذكي
5
+ """
6
+ import os
7
+ import sys
8
+ import time
9
+ import threading
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
+ from peer_discovery import PORT
23
+ # ─────────────── إعدادات المسارات ───────────────
24
+ FILE = Path(__file__).resolve()
25
+ BASE_DIR = FILE.parent
26
+ sys.path.insert(0, str(BASE_DIR))
27
+ def main():
28
+ print("🔧 CoreFlow يعمل الآن...")
29
+ # شغّل الخادم أو أي منطق أساسي هنا
30
+ # ─────────────── إعداد السجلات ───────────────
31
+ os.makedirs("logs", exist_ok=True)
32
+ logging.basicConfig(
33
+ level=logging.INFO,
34
+ format="%(asctime)s - %(levelname)s - %(message)s",
35
+ handlers=[
36
+ logging.StreamHandler(sys.stdout),
37
+ logging.FileHandler("logs/main.log", mode="a", encoding="utf-8")
38
+ ]
39
+ )
40
+
41
+ # ─────────────── تحميل متغيرات البيئة ───────────────
42
+ try:
43
+ from dotenv import load_dotenv
44
+ load_dotenv()
45
+ logging.info("تم تحميل متغيرات البيئة من .env")
46
+ except ImportError:
47
+ logging.warning("python-dotenv غير مثبَّت؛ تَخطّي .env")
48
+
49
+ # ─────────────── ثوابت التهيئة ───────────────
50
+ CPU_PORT = int(os.getenv("CPU_PORT", "5297"))
51
+ SHARED_SECRET = os.getenv("SHARED_SECRET", "my_shared_secret_123")
52
+ PYTHON_EXE = sys.executable
53
+
54
+ # ─────────────── خيارات سطر الأوامر ───────────────
55
+ parser = argparse.ArgumentParser(description="نظام توزيع المهام الذكي")
56
+ parser.add_argument(
57
+ "--stats-interval", "-s",
58
+ type=int,
59
+ default=0,
60
+ help="ثواني بين كل طباعة لإحصائية الأقران (0 = مرة واحدة فقط)"
61
+ )
62
+ parser.add_argument(
63
+ "--no-cli",
64
+ action="store_true",
65
+ help="تعطيل القائمة التفاعلية حتى عند وجود TTY"
66
+ )
67
+ args = parser.parse_args()
68
+
69
+ # ─────────────── متغيرات النظام ───────────────
70
+ PEERS = set() # مجموعة عناوين الأقران كسلاسل نصية
71
+ PEERS_INFO = {} # قاموس لحفظ معلومات الأقران الكاملة
72
+ current_server_index = 0
73
+
74
+ # ─────────────── دوال اكتشاف الأقران ───────────────
75
+ def register_service_lan():
76
+ """تسجيل الخدمة على الشبكة المحلية"""
77
+ while True:
78
+ try:
79
+ logging.info("جارٍ تسجيل الخدمة على الشبكة المحلية...")
80
+ time.sleep(10)
81
+ except Exception as e:
82
+ logging.error(f"خطأ في تسجيل الخدمة: {e}")
83
+
84
+ def discover_lan_loop():
85
+ """اكتشاف الأقران على الشبكة المحلية"""
86
+ while True:
87
+ try:
88
+ logging.info("جارٍ مسح الشبكة المحلية...")
89
+ time.sleep(15)
90
+ except Exception as e:
91
+ logging.error(f"خطأ في اكتشاف الأقران: {e}")
92
+
93
+ def fetch_central_loop():
94
+ """جلب تحديثات من السيرفر المركزي"""
95
+ while True:
96
+ try:
97
+ logging.info("جارٍ تحديث قائمة الأقران...")
98
+ time.sleep(30)
99
+ except Exception as e:
100
+ logging.error(f"خطأ في جلب التحديثات: {e}")
101
+
102
+ # ─────────────── دوال مساعدة ───────────────
103
+ def get_local_ip():
104
+ """الحصول على عنوان IP المحلي"""
105
+ try:
106
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
107
+ s.connect(("8.8.8.8", 80))
108
+ ip = s.getsockname()[0]
109
+ s.close()
110
+ return ip
111
+ except Exception:
112
+ return "127.0.0.1"
113
+
114
+ def add_peer(peer_data):
115
+ """إضافة قرين جديد إلى النظام"""
116
+ peer_url = f"http://{peer_data['ip']}:{peer_data['port']}/run"
117
+ if peer_url not in PEERS:
118
+ PEERS.add(peer_url)
119
+ PEERS_INFO[peer_url] = peer_data
120
+ logging.info(f"تمت إضافة قرين جديد: {peer_url}")
121
+ return peer_url
122
+
123
+ def benchmark(fn, *args):
124
+ """قياس زمن تنفيذ الدالة"""
125
+ t0 = time.time()
126
+ res = fn(*args)
127
+ return time.time() - t0, res
128
+
129
+ def load_and_run_peer_discovery():
130
+ """تحميل وتشغيل ملف peer_discovery.py"""
131
+ try:
132
+ peer_discovery_path = Path(__file__).parent / "peer_discovery.py"
133
+ if not peer_discovery_path.exists():
134
+ raise FileNotFoundError("ملف peer_discovery.py غير موجود")
135
+
136
+ spec = importlib.util.spec_from_file_location("peer_discovery_module", peer_discovery_path)
137
+ peer_module = importlib.util.module_from_spec(spec)
138
+ spec.loader.exec_module(peer_module)
139
+
140
+ logging.info("تم تحميل peer_discovery.py بنجاح")
141
+ return peer_module
142
+ except Exception as e:
143
+ logging.error(f"خطأ في تحميل peer_discovery.py: {str(e)}")
144
+ return None
145
+
146
+ # ─────────────── دوال المهام ───────────────
147
+ def example_task(x: int) -> int:
148
+ """دالة مثال بديلة إذا لم تكن موجودة في your_tasks.py"""
149
+ return x * x
150
+
151
+ def matrix_multiply(size: int) -> list:
152
+ """ضرب المصفوفات (بديل مؤقت)"""
153
+ return [[i*j for j in range(size)] for i in range(size)]
154
+
155
+ def prime_calculation(limit: int) -> list:
156
+ """حساب الأعداد الأولية (بديل مؤقت)"""
157
+ primes = []
158
+ for num in range(2, limit):
159
+ if all(num % i != 0 for i in range(2, int(num**0.5) + 1)):
160
+ primes.append(num)
161
+ return primes
162
+
163
+ def data_processing(size: int) -> dict:
164
+ """معالجة البيانات (بديل مؤقت)"""
165
+ return {i: i**2 for i in range(size)}
166
+
167
+ # ─────────────── خادم Flask ───────────────
168
+ flask_app = Flask(__name__)
169
+ CORS(flask_app, resources={r"/*": {"origins": "*"}})
170
+
171
+ @flask_app.route("/run_task", methods=["POST"])
172
+ def run_task():
173
+ try:
174
+ data = request.get_json() if request.is_json else request.form
175
+ task_id = data.get("task_id")
176
+
177
+ if not task_id:
178
+ return jsonify(error="يجب تحديد task_id"), 400
179
+
180
+ if task_id == "1":
181
+ result = matrix_multiply(500)
182
+ elif task_id == "2":
183
+ result = prime_calculation(100_000)
184
+ elif task_id == "3":
185
+ result = data_processing(10_000)
186
+ else:
187
+ return jsonify(error="معرف المهمة غير صحيح"), 400
188
+
189
+ return jsonify(result=result)
190
+
191
+ except Exception as e:
192
+ logging.error(f"خطأ في معالجة المهمة: {str(e)}", exc_info=True)
193
+ return jsonify(error="حدث خطأ داخلي في الخادم"), 500
194
+
195
+ def start_flask_server():
196
+ ip_public = os.getenv("PUBLIC_IP", "127.0.0.1")
197
+ logging.info(f"Flask متوفر على: http://{ip_public}:{CPU_PORT}/run_task")
198
+ flask_app.run(host="0.0.0.0", port=CPU_PORT, debug=False)
199
+
200
+ # ─────────────── دوال النظام الأساسية ───────────────
201
+ def connect_until_success():
202
+ global CPU_PORT, current_server_index
203
+
204
+ peer_module = load_and_run_peer_discovery()
205
+ if peer_module is None:
206
+ logging.warning("سيستمر التشغيل بدون peer_discovery.py")
207
+ return None, []
208
+
209
+ CENTRAL_REGISTRY_SERVERS = getattr(peer_module, 'CENTRAL_REGISTRY_SERVERS', [])
210
+ if not CENTRAL_REGISTRY_SERVERS:
211
+ logging.error("قائمة السيرفرات المركزية فارغة")
212
+ return None, []
213
+
214
+ while True:
215
+ for port in [CPU_PORT, 5298, 5299]:
216
+ for idx, server in enumerate(CENTRAL_REGISTRY_SERVERS):
217
+ info = {
218
+ "node_id": os.getenv("NODE_ID", socket.gethostname()),
219
+ "ip": get_local_ip(),
220
+ "port": port
221
+ }
222
+ try:
223
+ resp = requests.post(f"{server}/register", json=info, timeout=5)
224
+ resp.raise_for_status()
225
+ CPU_PORT = port
226
+ current_server_index = idx
227
+ logging.info(f"تم الاتصال بالسيرفر: {server} على المنفذ {CPU_PORT}")
228
+
229
+ # معالجة قائمة الأقران المستلمة
230
+ peers_list = resp.json()
231
+ peer_urls = []
232
+ for p in peers_list:
233
+ peer_url = add_peer(p)
234
+ peer_urls.append(peer_url)
235
+ return server, peer_urls
236
+
237
+ except Exception as e:
238
+ logging.warning(f"فشل الاتصال بـ {server}: {str(e)}")
239
+ time.sleep(5)
240
+
241
+ def main():
242
+ """الدالة الرئيسية لتشغيل النظام"""
243
+ # تشغيل الخدمات الأساسية
244
+ try:
245
+ subprocess.Popen([PYTHON_EXE, "peer_server.py", "--port", str(CPU_PORT)])
246
+ subprocess.Popen([PYTHON_EXE, "load_balancer.py"])
247
+ logging.info("تم تشغيل الخدمات الخلفيّة")
248
+ except Exception as exc:
249
+ logging.error(f"خطأ بتشغيل الخدمات الخلفية: {exc}")
250
+
251
+ # الاتصال بالسيرفر الم��كزي
252
+ server, initial_peers = connect_until_success()
253
+
254
+ # تشغيل خادم Flask
255
+ threading.Thread(target=start_flask_server, daemon=True).start()
256
+
257
+ # البقاء في حلقة رئيسية
258
+ try:
259
+ while True:
260
+ time.sleep(1)
261
+ except KeyboardInterrupt:
262
+ logging.info("تم إنهاء البرنامج.")
263
+
264
+ if __name__ == "__main__":
265
+ # إضافة القرين المحلي
266
+ add_peer({"ip": "127.0.0.1", "port": CPU_PORT})
267
+
268
+ # تشغيل خدمات اكتشاف الأقران
269
+ threading.Thread(target=register_service_lan, daemon=True).start()
270
+ threading.Thread(target=discover_lan_loop, daemon=True).start()
271
+ threading.Thread(target=fetch_central_loop, daemon=True).start()
272
+
273
+ # بدء النظام الرئيسي
274
+ main()
main.spec ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- mode: python ; coding: utf-8 -*-
2
+
3
+
4
+ a = Analysis(
5
+ ['main.py'],
6
+ pathex=[],
7
+ binaries=[],
8
+ datas=[],
9
+ hiddenimports=[],
10
+ hookspath=[],
11
+ hooksconfig={},
12
+ runtime_hooks=[],
13
+ excludes=[],
14
+ noarchive=False,
15
+ optimize=0,
16
+ )
17
+ pyz = PYZ(a.pure)
18
+
19
+ exe = EXE(
20
+ pyz,
21
+ a.scripts,
22
+ a.binaries,
23
+ a.datas,
24
+ [],
25
+ name='main',
26
+ debug=False,
27
+ bootloader_ignore_signals=False,
28
+ strip=False,
29
+ upx=True,
30
+ upx_exclude=[],
31
+ runtime_tmpdir=None,
32
+ console=False,
33
+ disable_windowed_traceback=False,
34
+ argv_emulation=False,
35
+ target_arch=None,
36
+ codesign_identity=None,
37
+ entitlements_file=None,
38
+ )
node_client.py ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # ================================================================
3
+ # node_client.py – عميل تسجيل العُقدة في نظام AmalOffload
4
+ # ---------------------------------------------------------------
5
+ # • يختار منفذًا (من ENV أو من مجموعة PORTS).
6
+ # • يجلب عنوان الـ IP المحلي.
7
+ # • يحاول التسجيل في خادم سجلٍّ مركزي واحد تِلو الآخر،
8
+ # وعلى كل المنافذ، حتى ينجح.
9
+ # • عند النجاح يُرجع قائمة الأقران (Peers) من الخادم.
10
+ # ================================================================
11
+
12
+ import os
13
+ import socket
14
+ import time
15
+ import logging
16
+ import random
17
+ import requests
18
+ from typing import Iterable, Tuple, List
19
+
20
+ # ⬇️ منافذ مقترحة؛ يمكنك التعديل أو توليدها ديناميكيًا
21
+ DEFAULT_PORTS = {
22
+ 7520, 7384, 9021, 6998, 5810, 9274,
23
+ 8645, 7329, 7734, 8456, 6173, 7860,
24
+ }
25
+
26
+ # ⬇️ خوادم السجل الاحتياطية بالترتيب المفضَّل
27
+ DEFAULT_REGISTRY_SERVERS = [
28
+ "https://cv4790811.regru.cloud",
29
+ "https://amaloffload.onrender.com",
30
+ "https://osamabyc86-offload.hf.space",
31
+ "http://10.229.36.125",
32
+ "http://10.229.228.178",
33
+ ]
34
+
35
+ logging.basicConfig(
36
+ level=logging.INFO,
37
+ format="%(asctime)s [%(levelname)s] %(message)s",
38
+ datefmt="%H:%M:%S",
39
+ )
40
+
41
+
42
+ class NodeClient:
43
+ """
44
+ عميل خفيف يعتني بالتسجيل المتكرِّر في خادم سجل مركزي.
45
+ يمكن استيراده في أي سكربت وتشغيله في خيط منفصل.
46
+ """
47
+
48
+ def __init__(
49
+ self,
50
+ PORTs: Iterable[int] | None = None,
51
+ registry_servers: List[str] | None = None,
52
+ node_id: str | None = None,
53
+ ):
54
+ self.PORTs = set(PORTs) if PORTs else DEFAULT_PORTS
55
+ self.registry_servers = list(registry_servers) if registry_servers else DEFAULT_REGISTRY_SERVERS
56
+ self.node_id = node_id or os.getenv("NODE_ID", socket.gethostname())
57
+
58
+ # مبدئيًّا اختَر منفذًا (أولوية للمتغيّر البيئي إن وُجد)
59
+ self.port: int = int(os.getenv("CPU_PORT", random.choice(list(self.PORTs))))
60
+ self.current_server_index: int | None = None
61
+
62
+ # -------------------------------------------------------------------------
63
+ @staticmethod
64
+ def get_local_ip() -> str:
65
+ """يحاول معرفة أفضل عنوان IP محلي لاستخدامه في الشبكة."""
66
+ try:
67
+ with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
68
+ # لا يهم أن ينجح الاتصال الفعلي، الهدف كشف IP واجهة الخروج
69
+ s.connect(("10.255.255.255", 1))
70
+ return s.getsockname()[0]
71
+ except Exception:
72
+ return "127.0.0.1"
73
+
74
+ def _register_once(self, server: str, port: int) -> List[str]:
75
+ """مُحاولة واحدة للتسجيل؛ تُعيد peers أو ترفع استثناءً."""
76
+ payload = {
77
+ "node_id": self.node_id,
78
+ "ip": self.get_local_ip(),
79
+ "port": port,
80
+ }
81
+ resp = requests.post(f"{server}/register", json=payload, timeout=5)
82
+ resp.raise_for_status()
83
+ return resp.json() # توقّع أن الخادم يُرجع قائمة أقران
84
+
85
+ # -------------------------------------------------------------------------
86
+ def connect_until_success(self, retry_delay: int = 5) -> Tuple[str, List[str]]:
87
+ """
88
+ يدور على جميع المنافذ والخوادم حتى ينجح التسجيل.
89
+ • عند النجاح يُرجع: (عنوان الخادم، قائمة الأقران)
90
+ • لا يرفع استثناءات؛ إمّا ينجح أو يستمر في المحاولة إلى ما لا نهاية.
91
+ """
92
+ logging.info("🔄 بدء محاولات التسجيل للعقدة '%s'...", self.node_id)
93
+ while True:
94
+ for port in self.PORTs:
95
+ for idx, server in enumerate(self.registry_servers):
96
+ try:
97
+ peers = self._register_once(server, port)
98
+ # سجّل النجاح واحفظ المعلومات
99
+ self.port = port
100
+ self.current_server_index = idx
101
+ logging.info("✅ متصل: %s على المنفذ %s", server, port)
102
+ return server, peers
103
+ except Exception as e:
104
+ logging.debug("❌ %s:%s -> %s", server, port, e)
105
+ time.sleep(retry_delay) # انتظر قليلًا ثم أعد المحاولة
106
+
107
+ # -------------------------------------------------------------------------
108
+ def run_background(self) -> None:
109
+ """
110
+ إطلاق التسجيل في خيط منفصل؛ مفيد إذا كنت تريد
111
+ إبقاء Main Thread للمهام الأخرى.
112
+ """
113
+ import threading # استيراد متأخر لتفادي الحمل الزائد عند import
114
+ threading.Thread(target=self.connect_until_success, daemon=True).start()
115
+
116
+
117
+ # -----------------------------------------------------------------------------
118
+ if __name__ == "__main__":
119
+ """
120
+ للتجربة المباشرة:
121
+ $ python node_client.py
122
+ """
123
+ client = NodeClient()
124
+ server, peer_list = client.connect_until_success()
125
+ logging.info("🗂️ الأقران: %s", peer_list)
offload_lib.py ADDED
@@ -0,0 +1,203 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # offload_lib.py
3
+
4
+ import time
5
+ import math
6
+ import random
7
+ import psutil
8
+ import requests
9
+ import socket
10
+ from functools import wraps
11
+ from zeroconf import Zeroconf, ServiceBrowser
12
+ import logging
13
+
14
+ # إعداد السجل
15
+ logging.basicConfig(
16
+ level=logging.INFO,
17
+ format='%(asctime)s - %(levelname)s - %(message)s'
18
+ )
19
+
20
+ # إعدادات التحميل
21
+ MAX_CPU = 0.6 # عتبة استخدام CPU فقط
22
+
23
+ class PeerListener:
24
+ def __init__(self):
25
+ self.peers = []
26
+
27
+ def add_service(self, zc, type, name):
28
+ info = zc.get_service_info(type, name)
29
+ if info:
30
+ ip = socket.inet_ntoa(info.addresses[0])
31
+ self.peers.append(f"{ip}:{info.port}")
32
+ logging.info(f"🔗 جهاز مكتشف: {ip}:{info.port}")
33
+
34
+ def update_service(self, zc, type, name):
35
+ logging.debug(f"🔄 تم تحديث الخدمة: {name}")
36
+ pass # هنا فقط لتفادي التحذير
37
+
38
+ def discover_peers(timeout=1.5):
39
+ """اكتشاف الأجهزة المتاحة - أولوية LAN ثم WAN ثم الإنترنت مع فحص المشروع"""
40
+ import peer_discovery
41
+ from project_identifier import verify_project_compatibility
42
+
43
+ zc = Zeroconf()
44
+ listener = PeerListener()
45
+ ServiceBrowser(zc, "_http._tcp.local.", listener)
46
+ time.sleep(timeout)
47
+ zc.close()
48
+
49
+ lan_peers = []
50
+ wan_peers = []
51
+ internet_peers = []
52
+
53
+ for peer in listener.peers:
54
+ ip = peer.split(':')[0]
55
+ if verify_peer_project(ip):
56
+ if is_local_network(ip):
57
+ lan_peers.append(peer)
58
+ else:
59
+ wan_peers.append(peer)
60
+
61
+ all_discovered = list(peer_discovery.PEERS)
62
+ for peer_url in all_discovered:
63
+ peer_ip = peer_url.split("://")[1].split(":")[0]
64
+ if verify_peer_project(peer_ip):
65
+ if is_local_network(peer_ip):
66
+ if peer_url not in lan_peers:
67
+ lan_peers.append(peer_url)
68
+ else:
69
+ if peer_url not in wan_peers:
70
+ internet_peers.append(peer_url)
71
+
72
+ all_peers = lan_peers + wan_peers + internet_peers
73
+ logging.info(f"اكتُشف {len(all_peers)} جهاز DTS متوافق - LAN: {len(lan_peers)}, WAN: {len(wan_peers)}, Internet: {len(internet_peers)}")
74
+
75
+ return all_peers
76
+
77
+ def verify_peer_project(ip, port=7520):
78
+ """فحص إذا كان الجهاز يحتوي على نفس المشروع"""
79
+ try:
80
+ from project_identifier import verify_project_compatibility
81
+
82
+ project_url = f"http://{ip}:{port}/project_info"
83
+ response = requests.get(project_url, timeout=2)
84
+
85
+ if response.status_code == 200:
86
+ remote_info = response.json()
87
+ return verify_project_compatibility(remote_info)
88
+
89
+ except:
90
+ pass
91
+ return False
92
+
93
+ def is_local_network(ip):
94
+ """فحص إذا كان IP في الشبكة المحلية"""
95
+ try:
96
+ import ipaddress
97
+ addr = ipaddress.ip_address(ip)
98
+ return (
99
+ addr.is_private or
100
+ str(addr).startswith('192.168.') or
101
+ str(addr).startswith('10.') or
102
+ str(addr).startswith('172.')
103
+ )
104
+ except:
105
+ return False
106
+
107
+ def try_offload(peer, payload, max_retries=3):
108
+ """محاولة إرسال المهمة إلى جهاز آخر"""
109
+ url = f"http://{peer}/run"
110
+ for attempt in range(max_retries):
111
+ try:
112
+ response = requests.post(url, json=payload, timeout=10)
113
+ response.raise_for_status()
114
+ return response.json()
115
+ except Exception as e:
116
+ logging.warning(f"فشل المحاولة {attempt + 1} لـ {peer}: {str(e)}")
117
+ time.sleep(0.5 * (attempt + 1))
118
+ raise ConnectionError(f"فشل جميع المحاولات لـ {peer}")
119
+
120
+ def estimate_complexity(func, args, kwargs):
121
+ """تقدير تعقيد المهمة"""
122
+ if func.__name__ == "matrix_multiply":
123
+ return args[0] ** 2
124
+ elif func.__name__ == "prime_calculation":
125
+ return args[0] / 100
126
+ elif func.__name__ == "data_processing":
127
+ return args[0] / 10
128
+ elif func.__name__ == "image_processing_emulation":
129
+ return args[0] * 5
130
+ return 1 # قيمة افتراضية
131
+
132
+ def offload(func):
133
+ """ديكوراتور لتوزيع المهام"""
134
+ @wraps(func)
135
+ def wrapper(*args, **kwargs):
136
+ cpu = psutil.cpu_percent(interval=0.5) / 100.0
137
+ mem = psutil.virtual_memory().available / (1024**2)
138
+ complexity = estimate_complexity(func, args, kwargs)
139
+
140
+ logging.info(f"حمل النظام - CPU: {cpu:.2f}, الذاكرة: {mem:.1f}MB, تعقيد المهمة: {complexity}")
141
+
142
+ if complexity > 50 or cpu > MAX_CPU:
143
+ try:
144
+ peers = discover_peers()
145
+ if peers:
146
+ payload = {
147
+ "func": func.__name__,
148
+ "args": args,
149
+ "kwargs": kwargs,
150
+ "complexity": complexity
151
+ }
152
+ selected_peer = random.choice(peers)
153
+ logging.info(f"إرسال المهمة إلى {selected_peer}")
154
+ return try_offload(selected_peer, payload)
155
+ except Exception as e:
156
+ logging.error(f"خطأ في التوزيع: {str(e)}")
157
+
158
+ logging.info("تنفيذ المهمة محلياً")
159
+ return func(*args, **kwargs)
160
+ return wrapper
161
+
162
+ # المهام القابلة للتوزيع:
163
+
164
+ @offload
165
+ def matrix_multiply(size):
166
+ """ضرب مصفوفتين عشوائيتين بالحجم"""
167
+ import numpy as np
168
+ A = np.random.rand(size, size)
169
+ B = np.random.rand(size, size)
170
+ return np.dot(A, B).tolist()
171
+
172
+ @offload
173
+ def prime_calculation(n):
174
+ """حساب الأعداد الأولية"""
175
+ primes = []
176
+ for num in range(2, n + 1):
177
+ is_prime = True
178
+ for i in range(2, int(math.sqrt(num)) + 1):
179
+ if num % i == 0:
180
+ is_prime = False
181
+ break
182
+ if is_prime:
183
+ primes.append(num)
184
+ return {"primes_count": len(primes), "primes": primes}
185
+
186
+ @offload
187
+ def data_processing(data_size):
188
+ """معالجة بيانات كبيرة"""
189
+ processed_data = []
190
+ for i in range(data_size):
191
+ result = sum(math.sin(x) * math.cos(x) for x in range(i, i + 100))
192
+ processed_data.append(result)
193
+ return {"processed_items": len(processed_data)}
194
+
195
+ @offload
196
+ def image_processing_emulation(iterations):
197
+ """محاكاة معالجة الصور"""
198
+ results = []
199
+ for i in range(iterations):
200
+ fake_processing = sum(math.sqrt(x) for x in range(i * 100, (i + 1) * 100))
201
+ results.append(fake_processing)
202
+ time.sleep(0.01)
203
+ return {"iterations": iterations, "results": results}
package-lock.json ADDED
The diff for this file is too large to render. See raw diff
 
package.json ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "rest-express",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "license": "MIT",
6
+ "scripts": {
7
+ "dev": "NODE_ENV=development tsx server/index.ts",
8
+ "build": "vite build && esbuild server/index.ts --platform=node --packages=external --bundle --format=esm --outdir=dist",
9
+ "start": "NODE_ENV=production node dist/index.js",
10
+ "check": "tsc",
11
+ "db:push": "drizzle-kit push"
12
+ },
13
+ "dependencies": {
14
+ "@hookform/resolvers": "^3.10.0",
15
+ "@jridgewell/trace-mapping": "^0.3.25",
16
+ "@neondatabase/serverless": "^0.10.4",
17
+ "@radix-ui/react-accordion": "^1.2.4",
18
+ "@radix-ui/react-alert-dialog": "^1.1.7",
19
+ "@radix-ui/react-aspect-ratio": "^1.1.3",
20
+ "@radix-ui/react-avatar": "^1.1.4",
21
+ "@radix-ui/react-checkbox": "^1.1.5",
22
+ "@radix-ui/react-collapsible": "^1.1.4",
23
+ "@radix-ui/react-context-menu": "^2.2.7",
24
+ "@radix-ui/react-dialog": "^1.1.7",
25
+ "@radix-ui/react-dropdown-menu": "^2.1.7",
26
+ "@radix-ui/react-hover-card": "^1.1.7",
27
+ "@radix-ui/react-label": "^2.1.3",
28
+ "@radix-ui/react-menubar": "^1.1.7",
29
+ "@radix-ui/react-navigation-menu": "^1.2.6",
30
+ "@radix-ui/react-popover": "^1.1.7",
31
+ "@radix-ui/react-progress": "^1.1.3",
32
+ "@radix-ui/react-radio-group": "^1.2.4",
33
+ "@radix-ui/react-scroll-area": "^1.2.4",
34
+ "@radix-ui/react-select": "^2.1.7",
35
+ "@radix-ui/react-separator": "^1.1.3",
36
+ "@radix-ui/react-slider": "^1.2.4",
37
+ "@radix-ui/react-slot": "^1.2.0",
38
+ "@radix-ui/react-switch": "^1.1.4",
39
+ "@radix-ui/react-tabs": "^1.1.4",
40
+ "@radix-ui/react-toast": "^1.2.7",
41
+ "@radix-ui/react-toggle": "^1.1.3",
42
+ "@radix-ui/react-toggle-group": "^1.1.3",
43
+ "@radix-ui/react-tooltip": "^1.2.0",
44
+ "@tanstack/react-query": "^5.60.5",
45
+ "bonjour-service": "^1.3.0",
46
+ "class-variance-authority": "^0.7.1",
47
+ "clsx": "^2.1.1",
48
+ "cmdk": "^1.1.1",
49
+ "connect-pg-simple": "^10.0.0",
50
+ "date-fns": "^3.6.0",
51
+ "drizzle-orm": "^0.39.1",
52
+ "drizzle-zod": "^0.7.0",
53
+ "embla-carousel-react": "^8.6.0",
54
+ "express": "^4.21.2",
55
+ "express-session": "^1.18.1",
56
+ "framer-motion": "^11.13.1",
57
+ "input-otp": "^1.4.2",
58
+ "lucide-react": "^0.453.0",
59
+ "memorystore": "^1.6.7",
60
+ "nanoid": "^5.1.5",
61
+ "next-themes": "^0.4.6",
62
+ "passport": "^0.7.0",
63
+ "passport-local": "^1.0.0",
64
+ "react": "^18.3.1",
65
+ "react-day-picker": "^8.10.1",
66
+ "react-dom": "^18.3.1",
67
+ "react-hook-form": "^7.55.0",
68
+ "react-icons": "^5.4.0",
69
+ "react-resizable-panels": "^2.1.7",
70
+ "recharts": "^2.15.2",
71
+ "tailwind-merge": "^2.6.0",
72
+ "tailwindcss-animate": "^1.0.7",
73
+ "tw-animate-css": "^1.2.5",
74
+ "vaul": "^1.1.2",
75
+ "wouter": "^3.3.5",
76
+ "ws": "^8.18.0",
77
+ "zod": "^3.24.2",
78
+ "zod-validation-error": "^3.4.0"
79
+ },
80
+ "devDependencies": {
81
+ "@replit/vite-plugin-cartographer": "^0.2.7",
82
+ "@replit/vite-plugin-runtime-error-modal": "^0.0.3",
83
+ "@tailwindcss/typography": "^0.5.15",
84
+ "@tailwindcss/vite": "^4.1.3",
85
+ "@types/connect-pg-simple": "^7.0.3",
86
+ "@types/express": "4.17.21",
87
+ "@types/express-session": "^1.18.0",
88
+ "@types/node": "20.16.11",
89
+ "@types/passport": "^1.0.16",
90
+ "@types/passport-local": "^1.0.38",
91
+ "@types/react": "^18.3.11",
92
+ "@types/react-dom": "^18.3.1",
93
+ "@types/ws": "^8.5.13",
94
+ "@vitejs/plugin-react": "^4.3.2",
95
+ "autoprefixer": "^10.4.20",
96
+ "drizzle-kit": "^0.30.4",
97
+ "electron": "^37.1.0",
98
+ "electron-builder": "^26.0.12",
99
+ "esbuild": "^0.25.0",
100
+ "postcss": "^8.4.47",
101
+ "tailwindcss": "^3.4.17",
102
+ "tsx": "^4.19.1",
103
+ "typescript": "5.6.3",
104
+ "vite": "^5.4.19"
105
+ },
106
+ "optionalDependencies": {
107
+ "bufferutil": "^4.0.8"
108
+ }
109
+ }
peer_discovery.py ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ import os
3
+ import socket
4
+ import threading
5
+ import time
6
+ import logging
7
+ import requests
8
+ from zeroconf import Zeroconf, ServiceInfo, ServiceBrowser
9
+
10
+ # إعداد السجلات
11
+ logging.basicConfig(level=logging.INFO)
12
+ logger = logging.getLogger(__name__)
13
+
14
+ # منفذ الخدمة (بدءاً من 1000 مع زيادة متسلسلة)
15
+ current_port = 1000
16
+
17
+ def get_sequential_port():
18
+ global current_port
19
+ port = current_port
20
+ current_port += 1
21
+ if current_port > 9999:
22
+ current_port = 1000
23
+ return port
24
+
25
+ PORT = "7520" and int(os.getenv("CPU_PORT", get_sequential_port()))
26
+ SERVICE = "_tasknode._tcp.local."
27
+ PEERS = set()
28
+ PEERS_INFO = {}
29
+
30
+ CENTRAL_REGISTRY_SERVERS = [
31
+ "https://cv4790811.regru.cloud",
32
+ "https://amaloffload.onrender.com",
33
+ "https://osamabyc86-offload.hf.space",
34
+ "https://osamabyc19866-omsd.hf.space",
35
+ "https://52.13.128.108",
36
+ "https://176.28.175.216",
37
+ "https://44.229.227.142"
38
+ ]
39
+
40
+ def get_local_ip():
41
+ try:
42
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
43
+ s.connect(("8.8.8.8", 80))
44
+ ip = s.getsockname()[0]
45
+ s.close()
46
+ return ip
47
+ except Exception:
48
+ return "127.0.0.1"
49
+
50
+ def register_peer(ip, port):
51
+ peer_url = f"http://{ip}:{port}/run"
52
+ if peer_url not in PEERS:
53
+ PEERS.add(peer_url)
54
+ logger.info(f"تم تسجيل قرين جديد: {peer_url}")
55
+
56
+ def discover_lan_peers():
57
+ class Listener:
58
+ def add_service(self, zc, type_, name):
59
+ info = zc.get_service_info(type_, name)
60
+ if info:
61
+ ip = socket.inet_ntoa(info.addresses[0])
62
+ register_peer(ip, info.port)
63
+
64
+ zeroconf = Zeroconf()
65
+ ServiceBrowser(zeroconf, SERVICE, Listener())
66
+ return zeroconf
67
+
68
+ def main():
69
+ logger.info("🚀 بدء نظام اكتشاف الأقران...")
70
+
71
+ # تسجيل الخدمة المحلية
72
+ zeroconf = Zeroconf()
73
+ info = ServiceInfo(
74
+ type_=SERVICE,
75
+ name=f"{socket.gethostname()}.{SERVICE}",
76
+ addresses=[socket.inet_aton(get_local_ip())],
77
+ port=int(PORT),
78
+ properties={b'version': b'1.0'},
79
+ server=f"{socket.gethostname()}.local."
80
+ )
81
+ zeroconf.register_service(info)
82
+
83
+ # بدء اكتشاف الأقران
84
+ discover_lan_peers()
85
+
86
+ try:
87
+ while True:
88
+ logger.info(f"عدد الأقران المكتشفين: {len(PEERS)}")
89
+ time.sleep(10)
90
+ except KeyboardInterrupt:
91
+ logger.info("🛑 إيقاف النظام...")
92
+ finally:
93
+ zeroconf.unregister_service(info)
94
+ zeroconf.close()
95
+
96
+ if __name__ == "__main__":
97
+ main()
peer_registry.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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):
8
+ self.peers = []
9
+
10
+ def add_service(self, zc, type_, name):
11
+ info = zc.get_service_info(type_, name)
12
+ if info:
13
+ ip = socket.inet_ntoa(info.addresses[0])
14
+ peer_data = {
15
+ 'ip': ip,
16
+ 'port': info.port,
17
+ 'load': float(info.properties.get(b'load', 0)),
18
+ 'node_id': info.properties.get(b'node_id', b'unknown').decode(),
19
+ 'last_seen': time.time()
20
+ }
21
+ if peer_data not in self.peers:
22
+ self.peers.append(peer_data)
23
+
24
+ def update_service(self, zc, type_, name):
25
+ """مطلوب بواسطة Zeroconf"""
26
+ self.add_service(zc, type_, name)
27
+
28
+ def remove_service(self, zc, type_, name):
29
+ """اختياري"""
30
+ pass
31
+
32
+ def register_service(ip: str, port: int, load: float = 0.0):
33
+ zc = Zeroconf()
34
+ service_name = f"{socket.gethostname()}-{int(time.time())}._tasknode._tcp.local."
35
+ service_info = ServiceInfo(
36
+ "_tasknode._tcp.local.",
37
+ service_name,
38
+ addresses=[socket.inet_aton(ip)],
39
+ port=port,
40
+ properties={
41
+ b'load': str(load).encode(),
42
+ b'node_id': socket.gethostname().encode()
43
+ }
44
+ )
45
+ zc.register_service(service_info)
46
+ print(f"✅ Service registered: {service_name} @ {ip}:{port}")
47
+ return zc # أبقِ المرجع حياً
48
+
49
+ def discover_peers(timeout=2):
50
+ zc = Zeroconf()
51
+ listener = Listener()
52
+ ServiceBrowser(zc, "_tasknode._tcp.local.", listener)
53
+ time.sleep(timeout)
54
+ zc.close()
55
+ return listener.peers
56
+
57
+ if __name__ == "__main__":
58
+ local_ip = socket.gethostbyname(socket.gethostname())
59
+ port = PORT
60
+
61
+ zc = register_service(local_ip, port, load=0.1)
62
+
63
+ peers = discover_peers()
64
+ print("✅ Available peers:", peers)
65
+
66
+ input("🔵 Press Enter to exit...\n")
67
+ zc.close()
68
+
peer_server.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # peer_server.py
2
+
3
+ from flask import Flask, request, jsonify # استيراد request و jsonify مع Flask
4
+ import psutil
5
+ import smart_tasks
6
+ import time
7
+ import socket
8
+ from peer_discovery import PORT
9
+ from flask import Flask
10
+ app = Flask(__name__)
11
+ @app.route("/run", methods=["POST"])
12
+ def run_task():
13
+ try:
14
+ data = request.get_json()
15
+ print("🔹 البيانات المستلمة:", data)
16
+ count = data.get("count", 100)
17
+ ...
18
+ return jsonify(result)
19
+ except Exception as e:
20
+ print("❌ خطأ أثناء التنفيذ:", e)
21
+ return jsonify({"error": str(e)}), 500
22
+ app = Flask(__name__) # إنشاء التطبيق
23
+
24
+ @app.route("/cpu")
25
+ def cpu():
26
+ # يعيد نسبة استخدام المعالج
27
+ return jsonify(usage=psutil.cpu_percent(interval=0.3))
28
+
29
+ @app.route("/run", methods=["POST"])
30
+ def run():
31
+ data = request.get_json(force=True)
32
+ fn_name = data.get("func")
33
+ fn = getattr(smart_tasks, fn_name, None)
34
+ if not fn:
35
+ return jsonify(error="function-not-found"), 404
36
+ try:
37
+ start = time.time()
38
+ result = fn(*data.get("args", []), **data.get("kwargs", {}))
39
+ return jsonify(
40
+ result=result,
41
+ host=socket.gethostname(),
42
+ took=round(time.time() - start, 3)
43
+ )
44
+ except Exception as e:
45
+ return jsonify(error=str(e)), 500
46
+
47
+ if __name__ == "__main__": # التصحيح هنا
48
+ app.run(host="0.0.0.0", port=PORT)
49
+
peer_statistics.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from collections import Counter
2
+ import ipaddress
3
+
4
+ def print_peer_statistics(discovered_peers):
5
+ ips = [peer['ip'] for peer in discovered_peers]
6
+ ip_counts = Counter(ips)
7
+
8
+ def classify_ip(ip):
9
+ try:
10
+ ip_obj = ipaddress.ip_address(ip)
11
+ if ip_obj.is_private:
12
+ return 'داخلي'
13
+ else:
14
+ return 'خارجي'
15
+ except ValueError:
16
+ return 'محلي'
17
+
18
+ print("\n📊 إحصائية عدد الأجهزة حسب النوع:\n")
19
+ for ip, count in ip_counts.items():
20
+ category = classify_ip(ip)
21
+ print(f"• {ip} ({category}): {count} جهاز")
postcss.config.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ export default {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ }
processor_manager.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # processor_manager.py
2
+
3
+ import psutil
4
+ from collections import deque
5
+ import logging
6
+
7
+ logging.basicConfig(level=logging.INFO)
8
+
9
+ class ResourceMonitor:
10
+ def __init__(self):
11
+ self.cpu_history = deque(maxlen=10)
12
+ self.mem_history = deque(maxlen=10)
13
+ # حد استقبال المهمات الآن 40% CPU بدل 30%
14
+ self.receive_cpu_threshold = 0.40
15
+
16
+ def current_load(self):
17
+ cpu = psutil.cpu_percent(interval=0.5) / 100.0 # كنسبة (0.0 - 1.0)
18
+ mem = psutil.virtual_memory().available / (1024**2) # متاح بالـ MB
19
+
20
+ self.cpu_history.append(cpu)
21
+ self.mem_history.append(mem)
22
+
23
+ avg_cpu = sum(self.cpu_history) / len(self.cpu_history)
24
+ avg_mem = sum(self.mem_history) / len(self.mem_history)
25
+
26
+ logging.info(f"Instant CPU: {cpu:.2%}, Instant MEM: {mem:.1f}MB")
27
+ logging.info(f"Avg CPU: {avg_cpu:.2%}, Avg MEM: {avg_mem:.1f}MB")
28
+
29
+ recommendation = "offload" if (avg_cpu > 0.5 or avg_mem < 2048) else "local"
30
+ can_receive = avg_cpu <= self.receive_cpu_threshold
31
+
32
+ return {
33
+ "instant": {"cpu": cpu, "mem": mem},
34
+ "average": {"cpu": avg_cpu, "mem": avg_mem},
35
+ "recommendation": recommendation,
36
+ "can_receive": can_receive
37
+ }
38
+
39
+ def trigger_offload():
40
+ """عملية توزيع المهام التجريبية"""
41
+ print("⚠️ تم استدعاء توزيع المهام (اختباري)")
42
+
43
+ def should_offload(task_complexity=0):
44
+ monitor = ResourceMonitor()
45
+ status = monitor.current_load()
46
+
47
+ avg_cpu = status['average']['cpu']
48
+ avg_mem = status['average']['mem']
49
+
50
+ if avg_cpu > 0.6 or avg_mem < 2048 or task_complexity > 75:
51
+ trigger_offload()
52
+ return True
53
+
54
+ return False
55
+
56
+ def can_receive_task():
57
+ """
58
+ يعيد True إذا كان بالإمكان استقبال مهمة جديدة،
59
+ أي عندما يكون متوسط استهلاك الـ CPU ≤ 40%.
60
+ """
61
+ return ResourceMonitor().current_load()["can_receive"]
62
+
63
+ if __name__ == "__main__":
64
+ status = ResourceMonitor().current_load()
65
+ if not status["can_receive"]:
66
+ print(f"🚫 لا يمكن استقبال مهام جديدة (Avg CPU: {status['average']['cpu']:.0%})")
67
+ else:
68
+ print(f"✅ يمكن استقبال مهام جديدة (Avg CPU: {status['average']['cpu']:.0%})")
69
+
70
+ if should_offload(80):
71
+ print("💡 ينصح بتوزيع المهمة")
72
+ else:
73
+ print("✅ يمكن تنفيذ المهمة محلياً")
project_identifier.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ """
3
+ project_identifier.py - معرف المشروع للتحقق من الهوية
4
+ """
5
+ import json
6
+ from flask import jsonify
7
+
8
+ PROJECT_INFO = {
9
+ "project_name": "distributed-task-system",
10
+ "version": "1.0",
11
+ "description": "نظام توزيع المهام الذكي",
12
+ "author": "DTS Team",
13
+ "features": [
14
+ "matrix_multiply",
15
+ "prime_calculation",
16
+ "data_processing",
17
+ "video_processing",
18
+ "live_streaming",
19
+ "enhanced_ai"
20
+ ],
21
+ "signature": "DTS_2024_SMART_DISTRIBUTION"
22
+ }
23
+
24
+ def get_project_info():
25
+ """إرجاع معلومات المشروع"""
26
+ return PROJECT_INFO
27
+
28
+ def verify_project_compatibility(remote_info):
29
+ """التحقق من توافق المشروع مع جهاز آخر"""
30
+ if not isinstance(remote_info, dict):
31
+ return False
32
+
33
+ return (
34
+ remote_info.get("project_name") == PROJECT_INFO["project_name"] and
35
+ remote_info.get("version") == PROJECT_INFO["version"] and
36
+ remote_info.get("signature") == PROJECT_INFO["signature"]
37
+ )
38
+
39
+ def create_project_endpoint():
40
+ """إنشاء endpoint لمعلومات المشروع"""
41
+ return jsonify(PROJECT_INFO)
quick_connection_test.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ #!/usr/bin/env python3
3
+ # اختبار سريع للتحقق من حالة النظام
4
+
5
+ import requests
6
+ import time
7
+ import json
8
+ from offload_lib import discover_peers, matrix_multiply
9
+
10
+ def test_connection():
11
+ """اختبار سريع للاتصال"""
12
+ print("🚀 اختبار اتصال سريع...")
13
+
14
+ # 1. فحص الخادم المحلي
15
+ try:
16
+ response = requests.get("http://localhost:PORT/health", timeout=3)
17
+ if response.status_code == 200:
18
+ print("✅ الخادم المحلي يعمل")
19
+ else:
20
+ print("❌ مشكلة في الخادم المحلي")
21
+ return False
22
+ except:
23
+ print("❌ الخادم المحلي غير متاح")
24
+ return False
25
+
26
+ # 2. اختبار اكتشاف الأجهزة
27
+ print("🔍 البحث عن الأجهزة...")
28
+ peers = discover_peers(timeout=2)
29
+ print(f"📱 تم اكتشاف {len(peers)} جهاز")
30
+
31
+ # 3. اختبار مهمة بسيطة
32
+ print("⚙️ اختبار مهمة بسيطة...")
33
+ start_time = time.time()
34
+ try:
35
+ result = matrix_multiply(5)
36
+ duration = time.time() - start_time
37
+ print(f"✅ تمت المعالجة في {duration:.2f} ثانية")
38
+ print(f"📊 النتيجة: مصفوفة {len(result)}x{len(result[0])}")
39
+ return True
40
+ except Exception as e:
41
+ print(f"❌ فشل في المعالجة: {e}")
42
+ return False
43
+
44
+ if __name__ == "__main__":
45
+ if test_connection():
46
+ print("\n🎉 النظام يعمل بشكل جيد!")
47
+ print("💡 يمكنك الآن تشغيل: python test_distributed_system.py")
48
+ else:
49
+ print("\n⚠️ هناك مشاكل تحتاج إصلاح")
quick_test.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ #!/usr/bin/env python3
3
+ # quick_test.py - اختبار سريع لنظام التوزيع
4
+
5
+ import requests
6
+ import time
7
+ from offload_lib import discover_peers
8
+
9
+ def quick_connectivity_test():
10
+ """اختبار سريع للاتصال والتوزيع"""
11
+ print("🚀 اختبار سريع لنظام التوزيع")
12
+ print("-" * 40)
13
+
14
+ # 1. اكتشاف الأجهزة
15
+ print("🔍 البحث عن الأجهزة...")
16
+ peers = discover_peers(timeout=2)
17
+
18
+ if not peers:
19
+ print("❌ لم يتم العثور على أجهزة أخرى")
20
+ return False
21
+
22
+ print(f"✅ تم العثور على {len(peers)} جهاز:")
23
+ for peer in peers:
24
+ print(f" 📱 {peer}")
25
+
26
+ # 2. اختبار الاتصال السريع
27
+ working_peers = []
28
+ for peer in peers:
29
+ try:
30
+ response = requests.get(f"{peer}/health", timeout=3)
31
+ if response.status_code == 200:
32
+ working_peers.append(peer)
33
+ print(f"✅ {peer} - متصل ويعمل")
34
+ else:
35
+ print(f"⚠️ {peer} - يستجيب لكن بخطأ")
36
+ except:
37
+ print(f"❌ {peer} - غير متصل")
38
+
39
+ if not working_peers:
40
+ print("❌ لا توجد أجهزة تعمل بشكل صحيح")
41
+ return False
42
+
43
+ # 3. اختبار إرسال مهمة بسيطة
44
+ print(f"\n📡 اختبار إرسال مهمة إلى {working_peers[0]}...")
45
+
46
+ task = {
47
+ "func": "matrix_multiply",
48
+ "args": [5],
49
+ "kwargs": {}
50
+ }
51
+
52
+ try:
53
+ start_time = time.time()
54
+ response = requests.post(f"{working_peers[0]}/run", json=task, timeout=10)
55
+ duration = time.time() - start_time
56
+
57
+ if response.status_code == 200:
58
+ result = response.json()
59
+ print(f"✅ تمت المعالجة بنجاح في {duration:.2f} ثانية")
60
+ print(f"📊 النتيجة: تم ضرب مصفوفة 5x5")
61
+ return True
62
+ else:
63
+ print(f"❌ فشل في المعالجة - كود الخطأ: {response.status_code}")
64
+ return False
65
+
66
+ except Exception as e:
67
+ print(f"❌ خطأ في الإرسال: {str(e)}")
68
+ return False
69
+
70
+ if __name__ == "__main__":
71
+ success = quick_connectivity_test()
72
+
73
+ if success:
74
+ print("\n🎉 النظام يعمل بشكل صحيح!")
75
+ print("💡 يمكنك الآن تشغيل الاختبار الشامل: python test_distributed_system.py")
76
+ else:
77
+ print("\n⚠️ هناك مشاكل في النظام، تحقق من:")
78
+ print(" 1. تشغيل الخادم على الأجهزة الأخرى")
79
+ print(" 2. الاتصال بالشبكة")
80
+ print(" 3. إعدادات الجدار الناري")
ram_manager.py ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ ram_manager.py – Distributed RAM Offload Agent
3
+ ================================================
4
+
5
+ ❖ الغرض
6
+ ------------
7
+ يوفِّر هذا الملف إضافة مستقلة إلى مشروع **AmalOffload** من أجل مشاركة الذاكرة (RAM) بين جميع العُقد التي تشغِّل المشروع. عندما ينخفض مقدار الذاكرة الحرة على إحدى العُقد إلى أقل من 2 جيجابايت (أو أي قيمة تحدّدها)، تُنقل كتل بيانات إلى عُقد أخرى ما تزال تملك ذاكرة حرّة.
8
+
9
+ ❖ المزايا الرئيسة
10
+ ------------------
11
+ * يراقب استهلاك الذاكرة محليًّا بانتظام.
12
+ * يعلن عن نفسه ويكتشف الأقران (Peers) تلقائيًّا بالاعتماد على `peer_registry` إن وُجد، أو على قائمة في المتغيّر البيئي `CENTRAL_PEERS` كحلّ احتياطي.
13
+ * يعرض واجهة HTTP بسيطة (`Flask`) بثلاث مسارات:
14
+ * `GET /ram_status` → يُرجِع مقدار الذاكرة الحرّة بالعُقدة.
15
+ * `POST /ram_store` → يستقبل كتلة بيانات (Base64) ويحجزها في الذاكرة.
16
+ * `GET /ram_fetch/<id>` → يُرجِع كتلة بيانات مُخزّنة بحسب معرّفها.
17
+
18
+ ❖ طريقة التشغيل
19
+ ----------------
20
+ ```bash
21
+ python ram_manager.py --ram-limit 2048 --chunk 64 --interval 5
22
+ ```
23
+ أو اكتفِ بالتشغيل بدون وسائط واعتمد على القيم الافتراضيّة أو على متغيّرات البيئة:
24
+ ```bash
25
+ export RAM_THRESHOLD_MB=2048
26
+ export RAM_CHUNK_MB=64
27
+ python ram_manager.py
28
+ ```
29
+
30
+ ❖ التعليمات البرمجيّة
31
+ ----------------------
32
+ """
33
+ import os
34
+ import psutil
35
+ import time
36
+ import threading
37
+ import socket
38
+ import base64
39
+ import uuid
40
+ from typing import Dict, List
41
+
42
+ try:
43
+ from flask import Flask, request, jsonify
44
+ except ImportError as exc:
45
+ raise RuntimeError("Flask غير مُثبّت. نفِّذ: pip install flask") from exc
46
+
47
+ # محاولة استيراد مُسجِّل الأقران الحالي من المشروع
48
+ try:
49
+ import peer_registry # يتوقع أن يحتوي على list_peers()
50
+ except ImportError:
51
+ peer_registry = None
52
+
53
+ # الإعدادات – قابلة للتعديل عبر متغيّرات البيئة
54
+ RAM_LIMIT_MB = int(os.getenv("RAM_THRESHOLD_MB", "2048")) # الحد الأدنى للرام الحرّة قبل الت offload
55
+ CHUNK_MB = int(os.getenv("RAM_CHUNK_MB", "64")) # حجم الكتلة المُرسَلة
56
+ CHECK_INTERVAL = int(os.getenv("RAM_CHECK_INTERVAL", "5")) # ثواني بين كل فحص
57
+ RAM_PORT = int(os.getenv("RAM_PORT", "8765")) # بورت واجهة الذاكرة
58
+
59
+ app = Flask(__name__)
60
+
61
+ # مخزن الكتل الواردة
62
+ remote_chunks: Dict[str, bytes] = {}
63
+
64
+ def get_free_ram_mb() -> int:
65
+ """الذاكرة الحرّة بالميغابايت"""
66
+ return psutil.virtual_memory().available // (1024 * 1024)
67
+
68
+ # ─────────────────── واجهة HTTP ────────────────────
69
+ @app.route("/ram_status", methods=["GET"])
70
+ def ram_status():
71
+ """إرجاع كميّة الذاكرة الحرّة بالعُقدة."""
72
+ return jsonify({"free_mb": get_free_ram_mb()})
73
+
74
+ @app.route("/ram_store", methods=["POST"])
75
+ def ram_store():
76
+ """تلقّي كتلة بيانات وتخزينها."""
77
+ payload = request.get_json(force=True)
78
+ cid = payload["id"]
79
+ blob_b64= payload["data"]
80
+ remote_chunks[cid] = base64.b64decode(blob_b64)
81
+ return jsonify({"status": "stored", "id": cid})
82
+
83
+ @app.route("/ram_fetch/<cid>", methods=["GET"])
84
+ def ram_fetch(cid):
85
+ blob = remote_chunks.get(cid)
86
+ if blob is None:
87
+ return jsonify({"error": "not found"}), 404
88
+ return jsonify({"id": cid, "data": base64.b64encode(blob).decode()})
89
+
90
+ # ─────────────────── وظائف داخليّة ───────────────────
91
+
92
+ def start_api():
93
+ """تشغيل خادم Flask في خيط منفصل."""
94
+ from werkzeug.serving import make_server
95
+ server = make_server("0.0.0.0", RAM_PORT, app)
96
+ server.serve_forever()
97
+
98
+
99
+ def discover_peers() -> List[str]:
100
+ """الحصول على قائمة IPs للأقران، باستثناء عنوان الجهاز الحالي."""
101
+ peers: List[str] = []
102
+
103
+ if peer_registry and hasattr(peer_registry, "list_peers"):
104
+ try:
105
+ peers_info = peer_registry.list_peers() # متوقع: [{"ip": "..."}, ...]
106
+ peers = [p["ip"] for p in peers_info if p.get("ip")]
107
+ except Exception:
108
+ pass
109
+ else:
110
+ central_env = os.getenv("CENTRAL_PEERS", "")
111
+ if central_env:
112
+ peers = central_env.split(",")
113
+
114
+ # إزالة عنوان الجهاز المحلي
115
+ try:
116
+ local_ip = socket.gethostbyname(socket.gethostname())
117
+ peers = [ip for ip in peers if ip != local_ip]
118
+ except Exception:
119
+ pass
120
+
121
+ return peers
122
+
123
+
124
+ def offload_chunk(blob: bytes, peer_ip: str) -> bool:
125
+ """إرسال كتلة بيانات إلى peer محدّد."""
126
+ import requests
127
+ try:
128
+ resp = requests.post(
129
+ f"http://{peer_ip}:{RAM_PORT}/ram_store",
130
+ json={"id": str(uuid.uuid4()), "data": base64.b64encode(blob).decode()},
131
+ timeout=5,
132
+ )
133
+ return resp.status_code == 200
134
+ except Exception:
135
+ return False
136
+
137
+
138
+ def monitor_loop():
139
+ """مراقبة الذاكرة واستدعاء offload عند الحاجة."""
140
+ while True:
141
+ free_mb = get_free_ram_mb()
142
+ if free_mb < RAM_LIMIT_MB:
143
+ peers = discover_peers()
144
+ if not peers:
145
+ print("[RAM] لا يوجد أقران متاحون حاليًا.")
146
+ else:
147
+ blob = bytes(CHUNK_MB * 1024 * 1024) # كتلة وهميّة – استبدلها ببيانات حقيقيّة عند الدمج
148
+ for ip in peers:
149
+ if offload_chunk(blob, ip):
150
+ print(f"[RAM]‎ أرسلت ‎{CHUNK_MB}‎MB إلى ‎{ip}")
151
+ break
152
+ else:
153
+ print("[RAM] كل الأقران رفضوا التخزين أو حدث خطأ.")
154
+ time.sleep(CHECK_INTERVAL)
155
+
156
+
157
+ def main():
158
+ threading.Thread(target=start_api, daemon=True).start()
159
+ monitor_loop()
160
+
161
+ if __name__ == "__main__":
162
+ main()
remote_executor.py ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # remote_executor.py (مُحدَّث: يدعم التشفير والتوقيع واختيار السيرفر ديناميكياً)
2
+ # ============================================================
3
+ # يرسل المهمّة إلى سيرفر RPC خارجي مع تشفير + توقيع،
4
+ # أو يعمل بوضع JSON صافٍ لو لم يكن SecurityManager مفعَّل.
5
+ # يستخدم قائمة الأقران المكتشفة لاختيار الـ endpoint بدل IP ثابت.
6
+ # ============================================================
7
+
8
+ import requests
9
+ import json
10
+ import os
11
+ 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(
19
+ "REMOTE_SERVER",
20
+ "http://89.111.171.92:PORT/run"
21
+ )
22
+
23
+ # محاولة استيراد SecurityManager (اختياري)
24
+ try:
25
+ from security_layer import SecurityManager
26
+ security = SecurityManager(os.getenv("SHARED_SECRET", "my_shared_secret_123"))
27
+ SECURITY_ENABLED = True
28
+ except ImportError:
29
+ security = None
30
+ SECURITY_ENABLED = False
31
+
32
+
33
+ def _choose_remote_server() -> str:
34
+ """
35
+ يختار عنوان السيرفر الذي سترسل إليه المهمة:
36
+ 1) إذا عُيّن متغير بيئي REMOTE_SERVER، يُستخدم.
37
+ 2) وإلا إذا اكتشفنا أقران عبر LAN/Internet، نأخذ أولهم.
38
+ 3) وإلا نعود إلى FALLBACK_SERVER.
39
+ """
40
+ env_url = os.getenv("REMOTE_SERVER")
41
+ if env_url:
42
+ return env_url.rstrip('/') + '/run'
43
+ # PEERS يحوي عناوين كاملة من نوع http://ip:port/run
44
+ if PEERS:
45
+ # نختار الحد الأدنى من التحميل (اختياري) أو أول عنصر
46
+ # هنا ببساطة نأخذ أول URL
47
+ return next(iter(PEERS))
48
+ # استخدام الافتراضي
49
+ return FALLBACK_SERVER.rstrip('/') + '/run'
50
+
51
+
52
+ def execute_remotely(
53
+ func_name: str,
54
+ args: list[Any] | None = None,
55
+ kwargs: dict[str, Any] | None = None
56
+ ) -> Any:
57
+ """إرسال استدعاء دالة إلى الخادم البعيد وإرجاع النتيجة."""
58
+ if args is None:
59
+ args = []
60
+ if kwargs is None:
61
+ kwargs = {}
62
+
63
+ task = {
64
+ "func": func_name,
65
+ "args": args,
66
+ "kwargs": kwargs,
67
+ "sender_id": "client_node"
68
+ }
69
+
70
+ # اختيار السيرفر الصحيح ديناميكياً
71
+ target_url = _choose_remote_server()
72
+
73
+ try:
74
+ if SECURITY_ENABLED:
75
+ # 1) وقّع المهمة ثم شفّرها
76
+ signed_task = security.sign_task(task)
77
+ encrypted = security.encrypt_data(json.dumps(signed_task).encode())
78
+
79
+ headers = {
80
+ "X-Signature": security.signature_hex,
81
+ "Content-Type": "application/octet-stream"
82
+ }
83
+ payload = encrypted # خام ثنائي
84
+ resp = requests.post(
85
+ target_url,
86
+ headers=headers,
87
+ data=payload,
88
+ timeout=15
89
+ )
90
+ else:
91
+ # وضع التطوير: أرسل JSON صريح
92
+ headers = {"Content-Type": "application/json"}
93
+ resp = requests.post(
94
+ target_url,
95
+ headers=headers,
96
+ json=task,
97
+ timeout=15
98
+ )
99
+
100
+ resp.raise_for_status()
101
+ data = resp.json()
102
+ return data.get("result", "⚠️ لا يوجد نتيجة")
103
+
104
+ except Exception as e:
105
+ return f"❌ فشل التنفيذ البعيد على {target_url}: {e}"
replit.md ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Distributed Task System (DTS)
2
+
3
+ ## Overview
4
+
5
+ The Distributed Task System (DTS) is a full-stack web application that manages distributed computing across multiple nodes. It features a React frontend with shadcn/ui components and an Express.js backend with PostgreSQL database integration via Drizzle ORM. The system enables peer discovery, task distribution, load balancing, and real-time monitoring of distributed computing resources.
6
+
7
+ ## System Architecture
8
+
9
+ ### Frontend Architecture
10
+ - **Framework**: React 18 with TypeScript
11
+ - **Build Tool**: Vite with custom configuration
12
+ - **UI Library**: shadcn/ui components built on Radix UI primitives
13
+ - **Styling**: Tailwind CSS with custom dark theme
14
+ - **State Management**: TanStack Query for server state management
15
+ - **Routing**: Wouter for lightweight client-side routing
16
+ - **Real-time Updates**: WebSocket connection for live system monitoring
17
+
18
+ ### Backend Architecture
19
+ - **Runtime**: Node.js with Express.js framework
20
+ - **Database**: PostgreSQL with Drizzle ORM
21
+ - **Real-time Communication**: WebSocket Server for live updates
22
+ - **Task Execution**: Custom task executor with built-in operations
23
+ - **Peer Discovery**: Bonjour/mDNS-based service discovery
24
+ - **Security**: Custom security manager with encryption and digital signatures
25
+
26
+ ### Key Components
27
+
28
+ #### Database Schema
29
+ - **Nodes Table**: Stores information about connected computing nodes (id, name, ip, port, status, load, capabilities)
30
+ - **Tasks Table**: Manages distributed tasks (id, name, status, nodeId, complexity, duration, result, error)
31
+ - **System Metrics Table**: Tracks performance metrics (nodeId, cpuUsage, memoryUsage, timestamp)
32
+ - **System Logs Table**: Centralized logging (level, message, source, nodeId, timestamp)
33
+
34
+ #### Services
35
+ - **OffloadSystem**: Orchestrates task distribution and peer management
36
+ - **PeerDiscovery**: Uses Bonjour protocol for automatic node discovery on the network
37
+ - **TaskExecutor**: Handles built-in tasks like matrix multiplication, prime calculation, and data processing
38
+ - **SecurityManager**: Manages payload encryption, digital signatures, and secure communication
39
+ - **SystemMonitor**: Tracks system performance and resource utilization
40
+
41
+ #### Frontend Components
42
+ - **Dashboard**: Main interface showing system overview and metrics
43
+ - **MetricsGrid**: Real-time system performance visualization
44
+ - **NodesTable**: Connected nodes management interface
45
+ - **TaskActivity**: Task execution monitoring and status tracking
46
+ - **SecurityPanel**: Security status indicators
47
+ - **SystemLogs**: Centralized log viewing interface
48
+
49
+ ## Data Flow
50
+
51
+ 1. **Node Registration**: Nodes automatically discover and register with the system via mDNS
52
+ 2. **Task Submission**: Tasks are submitted through the web interface or API
53
+ 3. **Load Balancing**: System evaluates node capacity and distributes tasks accordingly
54
+ 4. **Task Execution**: Tasks are executed on selected nodes with real-time status updates
55
+ 5. **Result Collection**: Results are collected and stored in the database
56
+ 6. **Real-time Updates**: WebSocket connections push updates to connected clients
57
+
58
+ ## External Dependencies
59
+
60
+ ### Production Dependencies
61
+ - **Database**: @neondatabase/serverless for PostgreSQL connection
62
+ - **ORM**: drizzle-orm and drizzle-zod for database operations
63
+ - **UI Components**: @radix-ui/* packages for accessible UI primitives
64
+ - **Networking**: bonjour-service for peer discovery
65
+ - **Real-time**: ws (WebSocket) for live updates
66
+ - **Query Management**: @tanstack/react-query for server state
67
+ - **Session Management**: connect-pg-simple for session storage
68
+
69
+ ### Development Dependencies
70
+ - **Build Tools**: Vite, esbuild for production builds
71
+ - **Type Safety**: TypeScript with strict configuration
72
+ - **Code Quality**: ESLint integration (implied by tsconfig)
73
+ - **Development Experience**: @replit/vite-plugin-runtime-error-modal and cartographer
74
+
75
+ ## Deployment Strategy
76
+
77
+ ### Development Mode
78
+ - Frontend served via Vite dev server with HMR
79
+ - Backend runs with tsx for TypeScript execution
80
+ - Database migrations handled via drizzle-kit push
81
+ - Automatic service discovery in local network
82
+
83
+ ### Production Build
84
+ 1. Frontend built with Vite to `dist/public`
85
+ 2. Backend compiled with esbuild to `dist/index.js`
86
+ 3. Single Node.js process serves both static files and API
87
+ 4. PostgreSQL database connection via environment variables
88
+ 5. WebSocket server integrated with HTTP server
89
+
90
+ ### Environment Configuration
91
+ - `DATABASE_URL`: PostgreSQL connection string (required)
92
+ - `NODE_ENV`: Environment mode (development/production)
93
+ - `NODE_NAME`: Custom node identifier
94
+ - `SHARED_SECRET`: Security encryption key
95
+
96
+ ## Changelog
97
+ - June 29, 2025. Initial setup
98
+ - June 29, 2025. Added broadcast messaging capability to send messages to all connected devices from the index page
99
+ - Created broadcast_messages table in PostgreSQL database
100
+ - Implemented API endpoints for sending and retrieving broadcast messages
101
+ - Added real-time WebSocket broadcasting to all connected clients
102
+ - Created bilingual UI components with Arabic interface
103
+ - Added navigation link in sidebar for easy access
104
+ - Integrated with existing authentication and security systems
105
+
106
+ ## User Preferences
107
+
108
+ Preferred communication style: Simple, everyday language.
requirements.txt CHANGED
@@ -1 +1,24 @@
1
- huggingface_hub==0.25.2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Flask
2
+ flask_cors
3
+ requests
4
+ psutil
5
+ zeroconf
6
+ cryptography
7
+ numpy
8
+ networkx
9
+ Flask
10
+ flask_cors
11
+ requests
12
+ psutil
13
+ zeroconf
14
+ cryptography
15
+ numpy
16
+ networkx
17
+ flask
18
+ GPUtil
19
+ requests
20
+ python-dotenv
21
+ torch
22
+ flask_socketio
23
+
24
+
rpc_server.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # rpc_server.py (مُحدَّث بحيث يدعم التشفير الاختياري)
2
+ # ============================================================
3
+ # خادِم يستقبل مهام عن بُعد:
4
+ # • إن وصلته بيانات خام (Encrypted) في Body → يفك تشفيرها ويتحقق من التوقيع.
5
+ # • وإلا إن وصل JSON خام في Content‑Type: application/json → ينفّذ مباشرة (وضع تطويـر).
6
+ # ============================================================
7
+
8
+ 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
+
16
+ logging.basicConfig(
17
+ filename="server.log",
18
+ level=logging.INFO,
19
+ format="%(asctime)s - %(levelname)s - %(message)s"
20
+ )
21
+
22
+ app = Flask(name)
23
+
24
+ # ------------------------------------------------------------------
25
+ @app.route("/health")
26
+ def health():
27
+ return jsonify(status="ok")
28
+
29
+ # ------------------------------------------------------------------
30
+ @app.route("/run", methods=["POST"])
31
+ def run():
32
+ try:
33
+ # 1) حاول قراءة كـ JSON مباشر (وضع التطويـر)
34
+ if request.is_json:
35
+ data = request.get_json()
36
+ else:
37
+ # 2) وإلا اعتبره Payload مُشفَّر (وضع الإنتاج)
38
+ encrypted = request.get_data()
39
+ try:
40
+ decrypted = SECURITY.decrypt_data(encrypted)
41
+ data = json.loads(decrypted.decode())
42
+ except Exception as e:
43
+ logging.error(f"⚠️ فشل فك التشفير: {e}")
44
+ return jsonify(error="Decryption failed"), 400
45
+
46
+ # 3) التحقّق من التوقيع إن وُجد
47
+ if "_signature" in data:
48
+ if not SECURITY.verify_task(data):
49
+ logging.warning("❌ توقيع غير صالح")
50
+ return jsonify(error="Invalid signature"), 403
51
+ # أزل عناصر موقّعة إضافية
52
+ data = {k: v for k, v in data.items() if k not in ("_signature", "sender_id")}
53
+
54
+ func_name = data.get("func")
55
+ args = data.get("args", [])
56
+ kwargs = data.get("kwargs", {})
57
+
58
+ fn = getattr(smart_tasks, func_name, None)
59
+ if not fn:
60
+ logging.warning(f"❌ لم يتم العثور على الدالة: {func_name}")
61
+ return jsonify(error="Function not found"), 404
62
+
63
+ logging.info(f"⚙️ تنفيذ الدالة: {func_name} من جهاز آخر")
64
+ result = fn(*args, **kwargs)
65
+ return jsonify(result=result)
66
+
67
+ except Exception as e:
68
+ logging.error(f"🔥 خطأ أثناء تنفيذ المهمة: {str(e)}")
69
+ return jsonify(error=str(e)), 500
70
+
71
+ # ------------------------------------------------------------------
72
+ if name == "main":
73
+ # تأكد أن المنفذ PORT مفتوح
74
+ app.run(host="0.0.0.0", port=PORT)
run_task.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @flask_app.route("/run_task", methods=["POST"])
2
+ def run_task():
3
+ task_id = request.form.get("task_id")
4
+ result = None
5
+ # قبول البيانات سواء كانت JSON أو form-urlencoded
6
+ if request.is_json:
7
+ data = request.get_json()
8
+ task_id = data.get("task_id")
9
+ else:
10
+ task_id = request.form.get("task_id")
11
+
12
+ if not task_id:
13
+ return jsonify(error="Missing task_id"), 400
14
+
15
+ if task_id == "1":
16
+ result = matrix_multiply(500)
17
+ elif task_id == "2":
18
+ result = prime_calculation(100_000)
19
+ elif task_id == "3":
20
+ result = data_processing(10_000)
21
+
22
+ return jsonify(result=result) # إرجاع JSON بدل HTML
security_layer.py ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # security_layer.py (مُحدَّث)
2
+ # ============================================================
3
+ # إدارة التشفير والتوقيع وتبادل المفاتيح بين العقد
4
+ # ============================================================
5
+
6
+ from cryptography.hazmat.primitives import hashes, serialization
7
+ from cryptography.hazmat.primitives.asymmetric import rsa, padding
8
+ 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:
16
+ """طبقة أمان موحّدة لكل العقد."""
17
+
18
+ def __init__(self, shared_secret: str):
19
+ # مفتاح متماثل لاستخدام Fernet
20
+ self._key = self._derive_key(shared_secret)
21
+ self._cipher = Fernet(self._key)
22
+
23
+ # زوج مفاتيح غير متماثل للتوقيع الرقمي
24
+ self._private_key = rsa.generate_private_key(
25
+ public_exponent=65537,
26
+ key_size=2048,
27
+ )
28
+ self._public_pem = (
29
+ self._private_key.public_key()
30
+ .public_bytes(
31
+ encoding=serialization.Encoding.PEM,
32
+ format=serialization.PublicFormat.SubjectPublicKeyInfo,
33
+ )
34
+ .decode()
35
+ )
36
+ # مفاتيح العقد الأخرى {peer_id: public_key_obj}
37
+ self._peer_keys: Dict[str, rsa.RSAPublicKey] = {}
38
+
39
+ # ------------------------------------------------------------
40
+ # تشفير / فك تشفير متماثل
41
+ # ------------------------------------------------------------
42
+ def encrypt_data(self, data: bytes) -> bytes:
43
+ return self._cipher.encrypt(data)
44
+
45
+ def decrypt_data(self, encrypted: bytes) -> bytes:
46
+ return self._cipher.decrypt(encrypted)
47
+
48
+ # ------------------------------------------------------------
49
+ # توقيع/تحقّق رقمي غير متماثل
50
+ # ------------------------------------------------------------
51
+ def sign_task(self, task: Dict) -> Dict:
52
+ """يُرجع نسخة موقّعة من الـtask مضافًا إليها المفتاح العام والمعرّف."""
53
+ signature = self._private_key.sign(
54
+ json.dumps(task, separators=(",", ":")).encode(),
55
+ padding.PSS(
56
+ mgf=padding.MGF1(hashes.SHA256()),
57
+ salt_length=padding.PSS.MAX_LENGTH,
58
+ ),
59
+ hashes.SHA256(),
60
+ )
61
+ task_signed = task.copy()
62
+ task_signed.update(
63
+ {
64
+ "_signature": base64.b64encode(signature).decode(),
65
+ "sender_id": os.getenv("NODE_ID", "unknown"),
66
+ "sender_key": self._public_pem,
67
+ }
68
+ )
69
+ return task_signed
70
+
71
+ def verify_task(self, signed_task: Dict) -> bool:
72
+ """يتحقق من صحة التوقيع باستخدام المفتاح العام للمرسل."""
73
+ if "_signature" not in signed_task or "sender_id" not in signed_task:
74
+ return False
75
+ sig = base64.b64decode(signed_task["_signature"])
76
+ task_copy = {k: v for k, v in signed_task.items() if k not in {"_signature", "sender_key"}}
77
+
78
+ peer_id = signed_task["sender_id"]
79
+ if peer_id not in self._peer_keys:
80
+ # حاول إضافة المفتاح المرسل إن وجد
81
+ if "sender_key" in signed_task:
82
+ self.add_peer_key(peer_id, signed_task["sender_key"])
83
+ else:
84
+ return False
85
+ try:
86
+ self._peer_keys[peer_id].verify(
87
+ sig,
88
+ json.dumps(task_copy, separators=(",", ":")).encode(),
89
+ padding.PSS(
90
+ mgf=padding.MGF1(hashes.SHA256()),
91
+ salt_length=padding.PSS.MAX_LENGTH,
92
+ ),
93
+ hashes.SHA256(),
94
+ )
95
+ return True
96
+ except Exception:
97
+ return False
98
+
99
+ # ------------------------------------------------------------
100
+ # إدارة المفاتيح العامة للأقران
101
+ # ------------------------------------------------------------
102
+ def add_peer_key(self, peer_id: str, public_key_pem: str):
103
+ """تخزين/تحديث المفتاح العام لعقدة أخرى."""
104
+ self._peer_keys[peer_id] = serialization.load_pem_public_key(
105
+ public_key_pem.encode()
106
+ )
107
+
108
+ # ------------------------------------------------------------
109
+ # أدوات داخلية
110
+ # ------------------------------------------------------------
111
+ @staticmethod
112
+ def _derive_key(password: str) -> bytes:
113
+ salt = b"nora_salt_2025" # ◀️ عدِّل في الإنتاج
114
+ kdf = PBKDF2HMAC(
115
+ algorithm=hashes.SHA256(),
116
+ length=32,
117
+ salt=salt,
118
+ iterations=150_000,
119
+ )
120
+ return base64.urlsafe_b64encode(kdf.derive(password.encode()))
121
+