osamabyc commited on
Commit
1dd36e0
·
verified ·
1 Parent(s): 6c555a6

Upload 25 files

Browse files
autostart_config.py ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ import platform
4
+ from pathlib import Path
5
+
6
+ class AutoStartManager:
7
+ def __init__(self, app_name="DistributedTaskSystem"):
8
+ self.app_name = app_name
9
+ self.config_file = Path.home() / f".{app_name}_autostart.json"
10
+ self.load_config()
11
+
12
+ def load_config(self):
13
+ """تحميل إعدادات التشغيل التلقائي"""
14
+ try:
15
+ with open(self.config_file, 'r') as f:
16
+ self.config = json.load(f)
17
+ except (FileNotFoundError, json.JSONDecodeError):
18
+ self.config = {
19
+ 'enabled': False,
20
+ 'startup_script': str(Path(__file__).parent / "startup.py")
21
+ }
22
+
23
+ def save_config(self):
24
+ """حفظ الإعدادات"""
25
+ with open(self.config_file, 'w') as f:
26
+ json.dump(self.config, f, indent=2)
27
+
28
+ def enable_autostart(self):
29
+ """تفعيل التشغيل التلقائي"""
30
+ self.config['enabled'] = True
31
+ self._setup_autostart()
32
+ self.save_config()
33
+
34
+ def disable_autostart(self):
35
+ """تعطيل التشغيل التلقائي"""
36
+ self.config['enabled'] = False
37
+ self._remove_autostart()
38
+ self.save_config()
39
+
40
+ def _setup_autostart(self):
41
+ """إعداد التشغيل التلقائي حسب نظام التشغيل"""
42
+ system = platform.system()
43
+
44
+ if system == "Windows":
45
+ self._setup_windows()
46
+ elif system == "Linux":
47
+ self._setup_linux()
48
+ elif system == "Darwin":
49
+ self._setup_mac()
50
+
51
+ def _setup_windows(self):
52
+ """إعداد التشغيل التلقائي لـ Windows"""
53
+ import winreg
54
+ key = winreg.OpenKey(
55
+ winreg.HKEY_CURRENT_USER,
56
+ r"Software\Microsoft\Windows\CurrentVersion\Run",
57
+ 0, winreg.KEY_SET_VALUE
58
+ )
59
+ winreg.SetValueEx(
60
+ key, self.app_name, 0, winreg.REG_SZ,
61
+ f'python "{self.config["startup_script"]}"'
62
+ )
63
+ winreg.CloseKey(key)
64
+
65
+ def _setup_linux(self):
66
+ """إعداد التشغيل التلقائي لـ Linux"""
67
+ autostart_dir = Path.home() / ".config/autostart"
68
+ autostart_dir.mkdir(exist_ok=True)
69
+
70
+ desktop_file = autostart_dir / f"{self.app_name}.desktop"
71
+ desktop_file.write_text(f"""
72
+ [Desktop Entry]
73
+ Type=Application
74
+ Name={self.app_name}
75
+ Exec=python3 {self.config['startup_script']}
76
+ Terminal=false
77
+ """)
78
+
79
+ def _setup_mac(self):
80
+ """إعداد التشغيل التلقائي لـ macOS"""
81
+ plist_dir = Path.home() / "Library/LaunchAgents"
82
+ plist_dir.mkdir(exist_ok=True)
83
+
84
+ plist_file = plist_dir / f"com.{self.app_name.lower()}.plist"
85
+ plist_file.write_text(f"""
86
+ <?xml version="1.0" encoding="UTF-8"?>
87
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
88
+ <plist version="1.0">
89
+ <dict>
90
+ <key>Label</key>
91
+ <string>com.{self.app_name.lower()}</string>
92
+ <key>ProgramArguments</key>
93
+ <array>
94
+ <string>python</string>
95
+ <string>{self.config['startup_script']}</string>
96
+ </array>
97
+ <key>RunAtLoad</key>
98
+ <true/>
99
+ </dict>
100
+ </plist>
101
+ """)
102
+
103
+ def _remove_autostart(self):
104
+ """إزالة التشغيل التلقائي"""
105
+ system = platform.system()
106
+
107
+ if system == "Windows":
108
+ import winreg
109
+ try:
110
+ key = winreg.OpenKey(
111
+ winreg.HKEY_CURRENT_USER,
112
+ r"Software\Microsoft\Windows\CurrentVersion\Run",
113
+ 0, winreg.KEY_SET_VALUE
114
+ )
115
+ winreg.DeleteValue(key, self.app_name)
116
+ winreg.CloseKey(key)
117
+ except WindowsError:
118
+ pass
119
+
120
+ elif system == "Linux":
121
+ autostart_file = Path.home() / f".config/autostart/{self.app_name}.desktop"
122
+ if autostart_file.exists():
123
+ autostart_file.unlink()
124
+
125
+ elif system == "Darwin":
126
+ plist_file = Path.home() / f"Library/LaunchAgents/com.{self.app_name.lower()}.plist"
127
+ if plist_file.exists():
128
+ plist_file.unlink()
buildozer.spec ADDED
@@ -0,0 +1,466 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [app]
2
+
3
+ # (str) Title of your application
4
+ # اسم التطبيق
5
+ title = My Offload App
6
+
7
+ # اسم الباكيج (فريد)
8
+ package.name = myoffloadapp
9
+ package.domain = org.osama
10
+
11
+
12
+ # المتطلبات:
13
+ requirements = python3,kivy,requests,zeroconf,numpy,setuptools
14
+
15
+ # نسخة API
16
+ android.api = 31
17
+
18
+ # الحد الأدنى للأندرويد
19
+ android.minapi = 21
20
+
21
+ # NDK وسكّة البنية
22
+ android.ndk = 25b
23
+ android.sdk = 33
24
+
25
+ # تفعيل الوصول إلى الإنترنت مثلاً
26
+ android.permissions = INTERNET
27
+
28
+ # (str) Package domain (needed for android/ios packaging)
29
+
30
+ # (str) Source code where the main.py live
31
+ source.dir = .
32
+
33
+ # (list) Source files to include (let empty to include all the files)
34
+
35
+ # (list) List of inclusions using pattern matching
36
+ #source.include_patterns = assets/*,images/*.png
37
+
38
+ # (list) Source files to exclude (let empty to not exclude anything)
39
+ #source.exclude_exts = spec
40
+
41
+ # (list) List of directory to exclude (let empty to not exclude anything)
42
+ #source.exclude_dirs = tests, bin, venv
43
+
44
+ # (list) List of exclusions using pattern matching
45
+ # Do not prefix with './'
46
+ #source.exclude_patterns = license,images/*/*.jpg
47
+
48
+ # (str) Application versioning (method 1)
49
+ version = 0.1
50
+
51
+ # (str) Application versioning (method 2)
52
+ # version.regex = __version__ = ['"](.*)['"]
53
+ # version.filename = %(source.dir)s/main.py
54
+
55
+
56
+ # (str) Custom source folders for requirements
57
+ # Sets custom source for any requirements with recipes
58
+ # requirements.source.kivy = ../../kivy
59
+
60
+ # (str) Presplash of the application
61
+ #presplash.filename = %(source.dir)s/data/presplash.png
62
+
63
+ # (str) Icon of the application
64
+ #icon.filename = %(source.dir)s/data/icon.png
65
+
66
+ # (list) Supported orientations
67
+ # Valid options are: landscape, portrait, portrait-reverse or landscape-reverse
68
+ orientation = portrait
69
+
70
+ # (list) List of service to declare
71
+ #services = NAME:ENTRYPOINT_TO_PY,NAME2:ENTRYPOINT2_TO_PY
72
+
73
+ #
74
+ # OSX Specific
75
+ #
76
+
77
+ #
78
+ # author = © Copyright Info
79
+
80
+ # change the major version of python used by the app
81
+ osx.python_version = 3
82
+
83
+ # Kivy version to use
84
+ osx.kivy_version = 1.9.1
85
+
86
+ #
87
+ # Android specific
88
+ #
89
+
90
+ # (bool) Indicate if the application should be fullscreen or not
91
+ fullscreen = 0
92
+
93
+ # (string) Presplash background color (for android toolchain)
94
+ # Supported formats are: #RRGGBB #AARRGGBB or one of the following names:
95
+ # red, blue, green, black, white, gray, cyan, magenta, yellow, lightgray,
96
+ # darkgray, grey, lightgrey, darkgrey, aqua, fuchsia, lime, maroon, navy,
97
+ # olive, purple, silver, teal.
98
+ #android.presplash_color = #FFFFFF
99
+
100
+ # (string) Presplash animation using Lottie format.
101
+ # see https://lottiefiles.com/ for examples and https://airbnb.design/lottie/
102
+ # for general documentation.
103
+ # Lottie files can be created using various tools, like Adobe After Effect or Synfig.
104
+ #android.presplash_lottie = "path/to/lottie/file.json"
105
+
106
+ # (str) Adaptive icon of the application (used if Android API level is 26+ at runtime)
107
+ #icon.adaptive_foreground.filename = %(source.dir)s/data/icon_fg.png
108
+ #icon.adaptive_background.filename = %(source.dir)s/data/icon_bg.png
109
+
110
+ # (list) Permissions
111
+ # (See https://python-for-android.readthedocs.io/en/latest/buildoptions/#build-options-1 for all the supported syntaxes and properties)
112
+ #android.permissions = android.permission.INTERNET, (name=android.permission.WRITE_EXTERNAL_STORAGE;maxSdkVersion=18)
113
+
114
+ # (list) features (adds uses-feature -tags to manifest)
115
+ #android.features = android.hardware.usb.host
116
+
117
+ # (int) Target Android API, should be as high as possible.
118
+ #android.api = 31
119
+
120
+ # (int) Minimum API your APK / AAB will support.
121
+ #android.minapi = 21
122
+
123
+ # (int) Android SDK version to use
124
+ #android.sdk = 20
125
+
126
+ # (str) Android NDK version to use
127
+ #android.ndk = 23b
128
+
129
+ # (int) Android NDK API to use. This is the minimum API your app will support, it should usually match android.minapi.
130
+ #android.ndk_api = 21
131
+
132
+ # (bool) Use --private data storage (True) or --dir public storage (False)
133
+ #android.private_storage = True
134
+
135
+ # (str) Android NDK directory (if empty, it will be automatically downloaded.)
136
+ #android.ndk_path =
137
+
138
+ # (str) Android SDK directory (if empty, it will be automatically downloaded.)
139
+ #android.sdk_path =
140
+
141
+ # (str) ANT directory (if empty, it will be automatically downloaded.)
142
+ #android.ant_path =
143
+
144
+ # (bool) If True, then skip trying to update the Android sdk
145
+ # This can be useful to avoid excess Internet downloads or save time
146
+ # when an update is due and you just want to test/build your package
147
+ # android.skip_update = False
148
+
149
+ # (bool) If True, then automatically accept SDK license
150
+ # agreements. This is intended for automation only. If set to False,
151
+ # the default, you will be shown the license when first running
152
+ # buildozer.
153
+ # android.accept_sdk_license = False
154
+
155
+ # (str) Android entry point, default is ok for Kivy-based app
156
+ #android.entrypoint = org.kivy.android.PythonActivity
157
+
158
+ # (str) Full name including package path of the Java class that implements Android Activity
159
+ # use that parameter together with android.entrypoint to set custom Java class instead of PythonActivity
160
+ #android.activity_class_name = org.kivy.android.PythonActivity
161
+
162
+ # (str) Extra xml to write directly inside the <manifest> element of AndroidManifest.xml
163
+ # use that parameter to provide a filename from where to load your custom XML code
164
+ #android.extra_manifest_xml = ./src/android/extra_manifest.xml
165
+
166
+ # (str) Extra xml to write directly inside the <manifest><application> tag of AndroidManifest.xml
167
+ # use that parameter to provide a filename from where to load your custom XML arguments:
168
+ #android.extra_manifest_application_arguments = ./src/android/extra_manifest_application_arguments.xml
169
+
170
+ # (str) Full name including package path of the Java class that implements Python Service
171
+ # use that parameter to set custom Java class which extends PythonService
172
+ #android.service_class_name = org.kivy.android.PythonService
173
+
174
+ # (str) Android app theme, default is ok for Kivy-based app
175
+ # android.apptheme = "@android:style/Theme.NoTitleBar"
176
+
177
+ # (list) Pattern to whitelist for the whole project
178
+ #android.whitelist =
179
+
180
+ # (str) Path to a custom whitelist file
181
+ #android.whitelist_src =
182
+
183
+ # (str) Path to a custom blacklist file
184
+ #android.blacklist_src =
185
+
186
+ # (list) List of Java .jar files to add to the libs so that pyjnius can access
187
+ # their classes. Don't add jars that you do not need, since extra jars can slow
188
+ # down the build process. Allows wildcards matching, for example:
189
+ # OUYA-ODK/libs/*.jar
190
+ #android.add_jars = foo.jar,bar.jar,path/to/more/*.jar
191
+
192
+ # (list) List of Java files to add to the android project (can be java or a
193
+ # directory containing the files)
194
+ #android.add_src =
195
+
196
+ # (list) Android AAR archives to add
197
+ #android.add_aars =
198
+
199
+ # (list) Put these files or directories in the apk assets directory.
200
+ # Either form may be used, and assets need not be in 'source.include_exts'.
201
+ # 1) android.add_assets = source_asset_relative_path
202
+ # 2) android.add_assets = source_asset_path:destination_asset_relative_path
203
+ #android.add_assets =
204
+
205
+ # (list) Put these files or directories in the apk res directory.
206
+ # The option may be used in three ways, the value may contain one or zero ':'
207
+ # Some examples:
208
+ # 1) A file to add to resources, legal resource names contain ['a-z','0-9','_']
209
+ # android.add_resources = my_icons/all-inclusive.png:drawable/all_inclusive.png
210
+ # 2) A directory, here 'legal_icons' must contain resources of one kind
211
+ # android.add_resources = legal_icons:drawable
212
+ # 3) A directory, here 'legal_resources' must contain one or more directories,
213
+ # each of a resource kind: drawable, xml, etc...
214
+ # android.add_resources = legal_resources
215
+ #android.add_resources =
216
+
217
+ # (list) Gradle dependencies to add
218
+ #android.gradle_dependencies =
219
+
220
+ # (bool) Enable AndroidX support. Enable when 'android.gradle_dependencies'
221
+ # contains an 'androidx' package, or any package from Kotlin source.
222
+ # android.enable_androidx requires android.api >= 28
223
+ #android.enable_androidx = True
224
+
225
+ # (list) add java compile options
226
+ # this can for example be necessary when importing certain java libraries using the 'android.gradle_dependencies' option
227
+ # see https://developer.android.com/studio/write/java8-support for further information
228
+ # android.add_compile_options = "sourceCompatibility = 1.8", "targetCompatibility = 1.8"
229
+
230
+ # (list) Gradle repositories to add {can be necessary for some android.gradle_dependencies}
231
+ # please enclose in double quotes
232
+ # e.g. android.gradle_repositories = "maven { url 'https://kotlin.bintray.com/ktor' }"
233
+ #android.add_gradle_repositories =
234
+
235
+ # (list) packaging options to add
236
+ # see https://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.PackagingOptions.html
237
+ # can be necessary to solve conflicts in gradle_dependencies
238
+ # please enclose in double quotes
239
+ # e.g. android.add_packaging_options = "exclude 'META-INF/common.kotlin_module'", "exclude 'META-INF/*.kotlin_module'"
240
+ #android.add_packaging_options =
241
+
242
+ # (list) Java classes to add as activities to the manifest.
243
+ #android.add_activities = com.example.ExampleActivity
244
+
245
+ # (str) OUYA Console category. Should be one of GAME or APP
246
+ # If you leave this blank, OUYA support will not be enabled
247
+ #android.ouya.category = GAME
248
+
249
+ # (str) Filename of OUYA Console icon. It must be a 732x412 png image.
250
+ #android.ouya.icon.filename = %(source.dir)s/data/ouya_icon.png
251
+
252
+ # (str) XML file to include as an intent filters in <activity> tag
253
+ #android.manifest.intent_filters =
254
+
255
+ # (list) Copy these files to src/main/res/xml/ (used for example with intent-filters)
256
+ #android.res_xml = PATH_TO_FILE,
257
+
258
+ # (str) launchMode to set for the main activity
259
+ #android.manifest.launch_mode = standard
260
+
261
+ # (str) screenOrientation to set for the main activity.
262
+ # Valid values can be found at https://developer.android.com/guide/topics/manifest/activity-element
263
+ #android.manifest.orientation = fullSensor
264
+
265
+ # (list) Android additional libraries to copy into libs/armeabi
266
+ #android.add_libs_armeabi = libs/android/*.so
267
+ #android.add_libs_armeabi_v7a = libs/android-v7/*.so
268
+ #android.add_libs_arm64_v8a = libs/android-v8/*.so
269
+ #android.add_libs_x86 = libs/android-x86/*.so
270
+ #android.add_libs_mips = libs/android-mips/*.so
271
+
272
+ # (bool) Indicate whether the screen should stay on
273
+ # Don't forget to add the WAKE_LOCK permission if you set this to True
274
+ #android.wakelock = False
275
+
276
+ # (list) Android application meta-data to set (key=value format)
277
+ #android.meta_data =
278
+
279
+ # (list) Android library project to add (will be added in the
280
+ # project.properties automatically.)
281
+ #android.library_references =
282
+
283
+ # (list) Android shared libraries which will be added to AndroidManifest.xml using <uses-library> tag
284
+ #android.uses_library =
285
+
286
+ # (str) Android logcat filters to use
287
+ #android.logcat_filters = *:S python:D
288
+
289
+ # (bool) Android logcat only display log for activity's pid
290
+ #android.logcat_pid_only = False
291
+
292
+ # (str) Android additional adb arguments
293
+ #android.adb_args = -H host.docker.internal
294
+
295
+ # (bool) Copy library instead of making a libpymodules.so
296
+ #android.copy_libs = 1
297
+
298
+ # (list) The Android archs to build for, choices: armeabi-v7a, arm64-v8a, x86, x86_64
299
+ # In past, was `android.arch` as we weren't supporting builds for multiple archs at the same time.
300
+ android.archs = arm64-v8a, armeabi-v7a
301
+
302
+ # (int) overrides automatic versionCode computation (used in build.gradle)
303
+ # this is not the same as app version and should only be edited if you know what you're doing
304
+ # android.numeric_version = 1
305
+
306
+ # (bool) enables Android auto backup feature (Android API >=23)
307
+ android.allow_backup = True
308
+
309
+ # (str) XML file for custom backup rules (see official auto backup documentation)
310
+ # android.backup_rules =
311
+
312
+ # (str) If you need to insert variables into your AndroidManifest.xml file,
313
+ # you can do so with the manifestPlaceholders property.
314
+ # This property takes a map of key-value pairs. (via a string)
315
+ # Usage example : android.manifest_placeholders = [myCustomUrl:\"org.kivy.customurl\"]
316
+ # android.manifest_placeholders = [:]
317
+
318
+ # (bool) Skip byte compile for .py files
319
+ # android.no-byte-compile-python = False
320
+
321
+ # (str) The format used to package the app for release mode (aab or apk or aar).
322
+ # android.release_artifact = aab
323
+
324
+ # (str) The format used to package the app for debug mode (apk or aar).
325
+ # android.debug_artifact = apk
326
+
327
+ #
328
+ # Python for android (p4a) specific
329
+ #
330
+
331
+ # (str) python-for-android URL to use for checkout
332
+ #p4a.url =
333
+
334
+ # (str) python-for-android fork to use in case if p4a.url is not specified, defaults to upstream (kivy)
335
+ #p4a.fork = kivy
336
+
337
+ # (str) python-for-android branch to use, defaults to master
338
+ #p4a.branch = master
339
+
340
+ # (str) python-for-android specific commit to use, defaults to HEAD, must be within p4a.branch
341
+ #p4a.commit = HEAD
342
+
343
+ # (str) python-for-android git clone directory (if empty, it will be automatically cloned from github)
344
+ #p4a.source_dir =
345
+
346
+ # (str) The directory in which python-for-android should look for your own build recipes (if any)
347
+ #p4a.local_recipes =
348
+
349
+ # (str) Filename to the hook for p4a
350
+ #p4a.hook =
351
+
352
+ # (str) Bootstrap to use for android builds
353
+ # p4a.bootstrap = sdl2
354
+
355
+ # (int) port number to specify an explicit --port= p4a argument (eg for bootstrap flask)
356
+ #p4a.port =
357
+
358
+ # Control passing the --use-setup-py vs --ignore-setup-py to p4a
359
+ # "in the future" --use-setup-py is going to be the default behaviour in p4a, right now it is not
360
+ # Setting this to false will pass --ignore-setup-py, true will pass --use-setup-py
361
+ # NOTE: this is general setuptools integration, having pyproject.toml is enough, no need to generate
362
+ # setup.py if you're using Poetry, but you need to add "toml" to source.include_exts.
363
+ #p4a.setup_py = false
364
+
365
+ # (str) extra command line arguments to pass when invoking pythonforandroid.toolchain
366
+ #p4a.extra_args =
367
+
368
+
369
+
370
+ #
371
+ # iOS specific
372
+ #
373
+
374
+ # (str) Path to a custom kivy-ios folder
375
+ #ios.kivy_ios_dir = ../kivy-ios
376
+ # Alternately, specify the URL and branch of a git checkout:
377
+ ios.kivy_ios_url = https://github.com/kivy/kivy-ios
378
+ ios.kivy_ios_branch = master
379
+
380
+ # Another platform dependency: ios-deploy
381
+ # Uncomment to use a custom checkout
382
+ #ios.ios_deploy_dir = ../ios_deploy
383
+ # Or specify URL and branch
384
+ ios.ios_deploy_url = https://github.com/phonegap/ios-deploy
385
+ ios.ios_deploy_branch = 1.10.0
386
+
387
+ # (bool) Whether or not to sign the code
388
+ ios.codesign.allowed = false
389
+
390
+ # (str) Name of the certificate to use for signing the debug version
391
+ # Get a list of available identities: buildozer ios list_identities
392
+ #ios.codesign.debug = "iPhone Developer: <lastname> <firstname> (<hexstring>)"
393
+
394
+ # (str) The development team to use for signing the debug version
395
+ #ios.codesign.development_team.debug = <hexstring>
396
+
397
+ # (str) Name of the certificate to use for signing the release version
398
+ #ios.codesign.release = %(ios.codesign.debug)s
399
+
400
+ # (str) The development team to use for signing the release version
401
+ #ios.codesign.development_team.release = <hexstring>
402
+
403
+ # (str) URL pointing to .ipa file to be installed
404
+ # This option should be defined along with `display_image_url` and `full_size_image_url` options.
405
+ #ios.manifest.app_url =
406
+
407
+ # (str) URL pointing to an icon (57x57px) to be displayed during download
408
+ # This option should be defined along with `app_url` and `full_size_image_url` options.
409
+ #ios.manifest.display_image_url =
410
+
411
+ # (str) URL pointing to a large icon (512x512px) to be used by iTunes
412
+ # This option should be defined along with `app_url` and `display_image_url` options.
413
+ #ios.manifest.full_size_image_url =
414
+
415
+
416
+ [buildozer]
417
+
418
+ # (int) Log level (0 = error only, 1 = info, 2 = debug (with command output))
419
+ log_level = 2
420
+
421
+ # (int) Display warning if buildozer is run as root (0 = False, 1 = True)
422
+ warn_on_root = 1
423
+
424
+ # (str) Path to build artifact storage, absolute or relative to spec file
425
+ # build_dir = ./.buildozer
426
+
427
+ # (str) Path to build output (i.e. .apk, .aab, .ipa) storage
428
+ # bin_dir = ./bin
429
+
430
+ # -----------------------------------------------------------------------------
431
+ # List as sections
432
+ #
433
+ # You can define all the "list" as [section:key].
434
+ # Each line will be considered as a option to the list.
435
+ # Let's take [app] / source.exclude_patterns.
436
+ # Instead of doing:
437
+ #
438
+ #[app]
439
+ #source.exclude_patterns = license,data/audio/*.wav,data/images/original/*
440
+ #
441
+ # This can be translated into:
442
+ #
443
+ #[app:source.exclude_patterns]
444
+ #license
445
+ #data/audio/*.wav
446
+ #data/images/original/*
447
+ #
448
+
449
+
450
+ # -----------------------------------------------------------------------------
451
+ # Profiles
452
+ #
453
+ # You can extend section / key with a profile
454
+ # For example, you want to deploy a demo version of your application without
455
+ # HD content. You could first change the title to add "(demo)" in the name
456
+ # and extend the excluded directories to remove the HD content.
457
+ #
458
+ #[app@demo]
459
+ #title = My Application (demo)
460
+ #
461
+ #[app:source.exclude_patterns@demo]
462
+ #images/hd/*
463
+ #
464
+ # Then, invoke the command line with the "demo" profile:
465
+ #
466
+ #buildozer --profile demo android debug
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,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # dashboard.py
2
+ from flask import Flask, render_template, jsonify
3
+ from peer_discovery import discover_peers
4
+ import threading
5
+ import time
6
+ from typing import List, Dict
7
+ import logging
8
+
9
+ app = Flask(__name__)
10
+ app.logger.setLevel(logging.INFO)
11
+
12
+ # تهيئة قائمة الأقران
13
+ current_peers: Dict[str, List[Dict[str, str]]] = {"local": [], "external": []}
14
+
15
+ def update_peers_loop() -> None:
16
+ """حلقة تحديث قائمة الأقران بشكل دوري"""
17
+ global current_peers
18
+ while True:
19
+ try:
20
+ new_peers = discover_peers()
21
+ current_peers = new_peers
22
+ total_peers = len(new_peers["local"]) + len(new_peers["external"])
23
+ app.logger.info(f"تم تحديث قائمة الأقران: {total_peers} جهاز")
24
+ except Exception as e:
25
+ app.logger.error(f"خطأ في اكتشاف الأقران: {str(e)}")
26
+ time.sleep(10)
27
+
28
+ @app.route("/")
29
+ def dashboard() -> str:
30
+ """عرض لوحة التحكم الرئيسية"""
31
+ total_peers = len(current_peers["local"]) + len(current_peers["external"])
32
+ return render_template("dashboard.html",
33
+ peers_count=total_peers,
34
+ last_update=time.strftime("%Y-%m-%d %H:%M:%S"))
35
+
36
+ @app.route("/api/peers")
37
+ def get_peers() -> dict:
38
+ """واجهة API للحصول على قائمة الأقران"""
39
+ total_peers = len(current_peers["local"]) + len(current_peers["external"])
40
+ return jsonify({
41
+ "peers": current_peers,
42
+ "count": total_peers,
43
+ "status": "success"
44
+ })
45
+
46
+ def start_background_thread() -> None:
47
+ """بدء خيط الخلفية لتحديث الأقران"""
48
+ thread = threading.Thread(target=update_peers_loop)
49
+ thread.daemon = True
50
+ thread.start()
51
+
52
+ if __name__ == "__main__":
53
+ start_background_thread()
54
+ app.run(host="0.0.0.0", port=7530, debug=False)
55
+
distributed_executor.py ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # distributed_executor.py
2
+ import threading
3
+ import queue
4
+ import time
5
+ import json
6
+ from typing import Callable, Dict, List
7
+ import socket
8
+ from zeroconf import Zeroconf, ServiceBrowser, ServiceInfo
9
+ import logging
10
+
11
+ class PeerRegistry:
12
+ def __init__(self):
13
+ self._peers = {}
14
+ self._zeroconf = Zeroconf()
15
+ self.local_node_id = socket.gethostname()
16
+
17
+ def register_service(self, name: str, port: int, load: float = 0.0):
18
+ service_info = ServiceInfo(
19
+ "_tasknode._tcp.local.",
20
+ f"{name}._tasknode._tcp.local.",
21
+ addresses=[socket.inet_aton(self._get_local_ip())],
22
+ port=port,
23
+ properties={'load': str(load), 'node_id': self.local_node_id},
24
+ server=f"{name}.local."
25
+ )
26
+ self._zeroconf.register_service(service_info)
27
+
28
+ def discover_peers(self, timeout: int = 3) -> List[Dict]:
29
+ class Listener:
30
+ def __init__(self):
31
+ self.peers = []
32
+
33
+ def add_service(self, zc, type_, name):
34
+ info = zc.get_service_info(type_, name)
35
+ if info:
36
+ ip = socket.inet_ntoa(info.addresses[0])
37
+ self.peers.append({
38
+ 'ip': ip,
39
+ 'port': info.port,
40
+ 'load': float(info.properties[b'load']),
41
+ 'node_id': info.properties[b'node_id'].decode(),
42
+ 'last_seen': time.time()
43
+ })
44
+
45
+ listener = Listener()
46
+ browser = ServiceBrowser(self._zeroconf, "_tasknode._tcp.local.", listener)
47
+ time.sleep(timeout)
48
+ return sorted(listener.peers, key=lambda x: x['load'])
49
+
50
+ def _get_local_ip(self) -> str:
51
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
52
+ try:
53
+ s.connect(('10.255.255.255', 1))
54
+ ip = s.getsockname()[0]
55
+ except:
56
+ ip = '127.0.0.1'
57
+ finally:
58
+ s.close()
59
+ return ip
60
+
61
+ class DistributedExecutor:
62
+ def __init__(self, shared_secret: str):
63
+ self.peer_registry = PeerRegistry()
64
+ self.shared_secret = shared_secret
65
+ self.task_queue = queue.PriorityQueue()
66
+ self.result_cache = {}
67
+ self._init_peer_discovery()
68
+ logging.basicConfig(level=logging.INFO)
69
+
70
+ def _init_peer_discovery(self):
71
+ def discovery_loop():
72
+ while True:
73
+ self.available_peers = self.peer_registry.discover_peers()
74
+ time.sleep(10)
75
+
76
+ threading.Thread(target=discovery_loop, daemon=True).start()
77
+
78
+ def submit(self, task_func: Callable, *args, **kwargs):
79
+ """إرسال مهمة جديدة للنظام"""
80
+ task_id = f"{task_func.__name__}_{time.time()}"
81
+
82
+ # تجهيز المهمة
83
+ task = {
84
+ 'task_id': task_id,
85
+ 'function': task_func.__name__,
86
+ 'args': args,
87
+ 'kwargs': kwargs,
88
+ 'sender_id': self.peer_registry.local_node_id
89
+ }
90
+
91
+ # إرسال المهمة (تبسيط الإرسال في هذا المثال)
92
+ if self.available_peers:
93
+ peer = min(self.available_peers, key=lambda x: x['load'])
94
+ self._send_to_peer(peer, task)
95
+ else:
96
+ logging.warning("لا توجد أجهزة متاحة - سيتم تنفيذ المهمة محلياً")
97
+
98
+ def _send_to_peer(self, peer: Dict, task: Dict):
99
+ """إرسال مهمة إلى جهاز آخر"""
100
+ try:
101
+ url = f"http://{peer['ip']}:{peer['port']}/run"
102
+ response = requests.post(
103
+ url,
104
+ json=task,
105
+ timeout=10
106
+ )
107
+ response.raise_for_status()
108
+ return response.json()
109
+ except Exception as e:
110
+ logging.error(f"فشل إرسال المهمة لـ {peer['node_id']}: {str(e)}")
111
+ return None
112
+
113
+ # نموذج استخدام مبسط
114
+ if __name__ == "__main__":
115
+ executor = DistributedExecutor("my_secret_key")
116
+ executor.peer_registry.register_service("node1", 7520, load=0.1)
117
+ print("نظام توزيع المهام جاهز...")
dts.service ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [Unit]
2
+ Description=Distributed Task System
3
+ After=network.target
4
+
5
+ [Service]
6
+ ExecStart=/usr/local/bin/dts-start
7
+ Restart=always
8
+ User=root
9
+ Group=root
10
+ Environment=PATH=/usr/bin:/usr/local/bin
11
+ Environment=PYTHONUNBUFFERED=1
12
+
13
+ [Install]
14
+ WantedBy=multi-user.target
dts_cli.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # dts_cli.py
2
+ import click
3
+ from dashboard import app
4
+ from rpc_server import app as rpc_app
5
+ import threading
6
+
7
+ @click.group()
8
+ def cli():
9
+ pass
10
+
11
+ @cli.command()
12
+ def start():
13
+ """بدء النظام الموزع"""
14
+ print("جارِ تشغيل النظام الموزع...")
15
+
16
+ # تشغيل واجهة التحكم في خيط منفصل
17
+ dashboard_thread = threading.Thread(
18
+ target=lambda: app.run(host="0.0.0.0", port=5000)
19
+ )
20
+ dashboard_thread.daemon = True
21
+ dashboard_thread.start()
22
+
23
+ # تشغيل خادم RPC
24
+ rpc_app.run(host="0.0.0.0", port=7520)
25
+
26
+ @cli.command()
27
+ def discover():
28
+ """عرض الأجهزة المتصلة"""
29
+ from peer_discovery import discover_peers
30
+ peers = discover_peers()
31
+ print("الأجهزة المتصلة:")
32
+ for i, peer in enumerate(peers, 1):
33
+ print(f"{i}. {peer}")
34
+
35
+ if __name__ == "__main__":
36
+ cli()
main.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # main.py
2
+ import time
3
+ import json
4
+ from distributed_executor import DistributedExecutor
5
+ from your_tasks import *
6
+ # main.py
7
+ from distributed_executor import DistributedExecutor
8
+ import logging
9
+
10
+ def main():
11
+ logging.basicConfig(level=logging.INFO)
12
+
13
+ try:
14
+ # تهيئة النظام
15
+ executor = DistributedExecutor("my_shared_secret_123")
16
+ executor.peer_registry.register_service("main_node", 7520)
17
+
18
+ logging.info("نظام توزيع المهام يعمل...")
19
+
20
+ # يمكنك هنا إضافة مهام للتنفيذ
21
+ while True:
22
+ time.sleep(1)
23
+
24
+ except Exception as e:
25
+ logging.error(f"خطأ رئيسي: {str(e)}")
26
+
27
+ if __name__ == "__main__":
28
+ main()
29
+ def example_task(x):
30
+ # مهمة معقدة قابلة للتوزيع
31
+ return x * x + complex_operation(x)
32
+
33
+ def benchmark(task_func, *args):
34
+ """قياس أداء المهمة"""
35
+ start = time.time()
36
+ result = task_func(*args)
37
+ duration = time.time() - start
38
+ return duration, result
39
+
40
+ def main():
41
+ executor = DistributedExecutor("my_shared_secret_123")
42
+ executor.peer_registry.register_service("node1", 7520, load=0.2)
43
+
44
+ tasks = {
45
+ "1": ("ضرب المصفوفات", matrix_multiply, 500),
46
+ "2": ("حساب الأعداد الأولية", prime_calculation, 100000),
47
+ "3": ("معالجة البيانات", data_processing, 10000),
48
+ "4": ("محاكاة معالجة الصور", image_processing_emulation, 100),
49
+ "5": ("مهمة موزعة معقدة", example_task, 42)
50
+ }
51
+
52
+ while True:
53
+ print("\nنظام توزيع المهام الذكي")
54
+ print("اختر مهمة لتشغيلها:")
55
+ for k, v in tasks.items():
56
+ print(f"{k}: {v[0]}")
57
+ choice = input("اختر المهمة (أو 'q' للخروج): ")
58
+
59
+ if choice.lower() == 'q':
60
+ break
61
+
62
+ if choice in tasks:
63
+ name, func, arg = tasks[choice]
64
+ print(f"\nتشغيل: {name}...")
65
+
66
+ if choice == "5":
67
+ print("تم إرسال المهمة إلى العقدة الموزعة...")
68
+ future = executor.submit(func, arg)
69
+ result = future.result()
70
+ print(f"النتيجة (موزعة): {result}")
71
+ else:
72
+ duration, result = benchmark(func, arg)
73
+ print(f"النتيجة: {json.dumps(result, indent=2)[:200]}...")
74
+ print(f"الوقت المستغرق: {duration:.2f} ثانية")
75
+ else:
76
+ print("اختيار غير صحيح!")
77
+
78
+ if __name__ == "__main__":
79
+ main()
80
+
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
+ )
offload_debug.log ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 2025-06-25 08:58:55,491 - INFO - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
2
+ * Running on all addresses (0.0.0.0)
3
+ * Running on http://127.0.0.1:7520
4
+ * Running on http://192.168.100.37:7520
5
+ 2025-06-25 08:58:55,492 - INFO - Press CTRL+C to quit
6
+ 2025-06-25 09:05:53,645 - INFO - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
7
+ * Running on all addresses (0.0.0.0)
8
+ * Running on http://127.0.0.1:7520
9
+ * Running on http://192.168.100.37:7520
10
+ 2025-06-25 09:05:53,647 - INFO - Press CTRL+C to quit
11
+ 2025-06-25 10:17:35,364 - INFO - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
12
+ * Running on all addresses (0.0.0.0)
13
+ * Running on http://127.0.0.1:7520
14
+ * Running on http://192.168.100.37:7520
15
+ 2025-06-25 10:17:35,365 - INFO - Press CTRL+C to quit
offload_lib.py ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # offload_lib.py
2
+ import time
3
+ import math
4
+ import random
5
+ import psutil
6
+ import requests
7
+ import socket
8
+ from functools import wraps
9
+ from zeroconf import Zeroconf, ServiceBrowser
10
+ import logging
11
+
12
+ # إعداد السجل
13
+ logging.basicConfig(
14
+ level=logging.INFO,
15
+ format='%(asctime)s - %(levelname)s - %(message)s'
16
+ )
17
+
18
+ # إعدادات التحميل
19
+ MAX_CPU = 0.6 # عتبة استخدام CPU
20
+ MIN_MEM = 500 # الحد الأدنى للذاكرة (MB)
21
+
22
+ class PeerListener:
23
+ def __init__(self):
24
+ self.peers = []
25
+
26
+ def add_service(self, zc, type, name):
27
+ info = zc.get_service_info(type, name)
28
+ if info:
29
+ ip = socket.inet_ntoa(info.addresses[0])
30
+ self.peers.append(f"{ip}:{info.port}")
31
+
32
+ def discover_peers(timeout=1.5):
33
+ """اكتشاف الأجهزة المتاحة على الشبكة"""
34
+ zc = Zeroconf()
35
+ listener = PeerListener()
36
+ ServiceBrowser(zc, "_http._tcp.local.", listener)
37
+ time.sleep(timeout)
38
+ zc.close()
39
+ return listener.peers
40
+
41
+ def try_offload(peer, payload, max_retries=3):
42
+ """محاولة إرسال المهمة إلى جهاز آخر"""
43
+ url = f"http://{peer}/run"
44
+ for attempt in range(max_retries):
45
+ try:
46
+ response = requests.post(url, json=payload, timeout=10)
47
+ response.raise_for_status()
48
+ return response.json()
49
+ except Exception as e:
50
+ logging.warning(f"فشل المحاولة {attempt + 1} لـ {peer}: {str(e)}")
51
+ time.sleep(0.5 * (attempt + 1))
52
+ raise ConnectionError(f"فشل جميع المحاولات لـ {peer}")
53
+
54
+ def estimate_complexity(func, args, kwargs):
55
+ """تقدير تعقيد المهمة"""
56
+ if func.__name__ == "matrix_multiply":
57
+ return args[0] ** 2
58
+ elif func.__name__ == "prime_calculation":
59
+ return args[0] / 100
60
+ elif func.__name__ == "data_processing":
61
+ return args[0] / 10
62
+ elif func.__name__ == "image_processing_emulation":
63
+ return args[0] * 5
64
+ return 1 # قيمة افتراضية
65
+
66
+ def offload(func):
67
+ """ديكوراتور لتوزيع المهام"""
68
+ @wraps(func)
69
+ def wrapper(*args, **kwargs):
70
+ # حساب الحمل الحالي
71
+ cpu = psutil.cpu_percent(interval=0.5) / 100.0
72
+ mem = psutil.virtual_memory().available / (1024**2)
73
+ complexity = estimate_complexity(func, args, kwargs)
74
+
75
+ logging.info(f"حمل النظام - CPU: {cpu:.2f}, الذاكرة: {mem:.1f}MB, تعقيد المهمة: {complexity}")
76
+
77
+ # اتخاذ قرار التوزيع
78
+ if complexity > 50 or cpu > MAX_CPU or mem < MIN_MEM:
79
+ try:
80
+ peers = discover_peers()
81
+ if peers:
82
+ payload = {
83
+ "func": func.__name__,
84
+ "args": args,
85
+ "kwargs": kwargs,
86
+ "complexity": complexity
87
+ }
88
+ selected_peer = random.choice(peers)
89
+ logging.info(f"إرسال المهمة إلى {selected_peer}")
90
+ return try_offload(selected_peer, payload)
91
+ except Exception as e:
92
+ logging.error(f"خطأ في التوزيع: {str(e)}")
93
+
94
+ # التنفيذ المحلي إذا فشل التوزيع
95
+ logging.info("تنفيذ المهمة محلياً")
96
+ return func(*args, **kwargs)
97
+ return wrapper
98
+
99
+ # المهام القابلة للتوزيع:
100
+
101
+ @offload
102
+ def matrix_multiply(size):
103
+ """ضرب مصفوفات كبيرة"""
104
+ import numpy as np
105
+ A = np.random.rand(size, size)
106
+ B = np.random.rand(size, size)
107
+ return {"result": np.dot(A, B).tolist()}
108
+
109
+ @offload
110
+ def prime_calculation(n):
111
+ """حساب الأعداد الأولية"""
112
+ primes = []
113
+ for num in range(2, n + 1):
114
+ is_prime = True
115
+ for i in range(2, int(math.sqrt(num)) + 1):
116
+ if num % i == 0:
117
+ is_prime = False
118
+ break
119
+ if is_prime:
120
+ primes.append(num)
121
+ return {"primes_count": len(primes), "primes": primes}
122
+
123
+ @offload
124
+ def data_processing(data_size):
125
+ """معالجة بيانات كبيرة"""
126
+ processed_data = []
127
+ for i in range(data_size):
128
+ result = sum(math.sin(x) * math.cos(x) for x in range(i, i + 100))
129
+ processed_data.append(result)
130
+ return {"processed_items": len(processed_data)}
131
+
132
+ @offload
133
+ def image_processing_emulation(iterations):
134
+ """محاكاة معالجة الصور"""
135
+ results = []
136
+ for i in range(iterations):
137
+ fake_processing = sum(math.sqrt(x) for x in range(i * 100, (i + 1) * 100))
138
+ results.append(fake_processing)
139
+ time.sleep(0.01)
140
+ return {"iterations": iterations, "results": results}
peer_discovery.py ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import socket
2
+ import time
3
+ import requests
4
+ from zeroconf import Zeroconf, ServiceBrowser
5
+ from typing import List, Dict, Optional
6
+ import urllib3
7
+ import logging
8
+ from dataclasses import dataclass
9
+
10
+ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
11
+
12
+ # إعداد التسجيل
13
+ logging.basicConfig(level=logging.INFO)
14
+ logger = logging.getLogger(__name__)
15
+
16
+ @dataclass
17
+ class Device:
18
+ name: str
19
+ ip: str
20
+ port: Optional[int] = None
21
+ device_type: str = "unknown"
22
+ last_seen: float = time.time()
23
+
24
+ class NetworkDiscoverer:
25
+ def __init__(self):
26
+ self.local_devices: List[Device] = []
27
+ self.external_devices: List[Device] = []
28
+ self.central_server_urls = [
29
+ "https://89.111.171.92:1500/api/discover",
30
+ "https://backup-server.example.com:1500/api/discover"
31
+ ]
32
+
33
+ def discover_all_devices(self, timeout: int = 3) -> Dict[str, List[Device]]:
34
+ """اكتشاف جميع الأجهزة (محلية وخارجية)"""
35
+ self._discover_local_devices(timeout)
36
+ self._discover_external_devices()
37
+ return {
38
+ "local": self.local_devices,
39
+ "external": self.external_devices
40
+ }
41
+
42
+ def _discover_local_devices(self, timeout: int):
43
+ """اكتشاف الأجهزة على الشبكة المحلية"""
44
+ try:
45
+ zc = Zeroconf()
46
+ listener = self.LocalListener(self)
47
+ browser = ServiceBrowser(zc, "_tasknode._tcp.local.", listener)
48
+ time.sleep(timeout)
49
+ zc.close()
50
+ except Exception as e:
51
+ logger.error(f"فشل الاكتشاف المحلي: {e}")
52
+
53
+ def _discover_external_devices(self):
54
+ """اكتشاف الأجهزة عبر الخوادم المركزية"""
55
+ for server_url in self.central_server_urls:
56
+ try:
57
+ response = requests.get(server_url, timeout=5, verify=False)
58
+ if response.ok:
59
+ self._process_external_devices(response.json())
60
+ except Exception as e:
61
+ logger.warning(f"فشل الاتصال بالخادم {server_url}: {e}")
62
+
63
+ def _process_external_devices(self, devices_data):
64
+ """معالجة بيانات الأجهزة الخارجية"""
65
+ for device_data in devices_data.get('nodes', []):
66
+ if not self._is_duplicate_device(device_data):
67
+ device = Device(
68
+ name=device_data.get('name', 'غير معروف'),
69
+ ip=device_data.get('ip'),
70
+ port=device_data.get('port'),
71
+ device_type='external'
72
+ )
73
+ self.external_devices.append(device)
74
+
75
+ def _is_duplicate_device(self, device_data) -> bool:
76
+ """التحقق من عدم تكرار الجهاز"""
77
+ return any(
78
+ d.ip == device_data.get('ip')
79
+ for d in self.local_devices + self.external_devices
80
+ )
81
+
82
+ class LocalListener:
83
+ def __init__(self, discoverer):
84
+ self.discoverer = discoverer
85
+
86
+ def add_service(self, zc, type_, name):
87
+ self._process_service(zc, type_, name)
88
+
89
+ def update_service(self, zc, type_, name):
90
+ self._process_service(zc, type_, name)
91
+
92
+ def _process_service(self, zc, type_, name):
93
+ info = zc.get_service_info(type_, name)
94
+ if info and info.addresses:
95
+ ip = socket.inet_ntoa(info.addresses[0])
96
+ device = Device(
97
+ name=name,
98
+ ip=ip,
99
+ port=info.port,
100
+ device_type='local'
101
+ )
102
+ if not self.discoverer._is_duplicate_device(device.__dict__):
103
+ self.discoverer.local_devices.append(device)
104
+
105
+ def main():
106
+ discoverer = NetworkDiscoverer()
107
+
108
+ while True:
109
+ try:
110
+ devices = discoverer.discover_all_devices()
111
+
112
+ print("\n" + "="*40)
113
+ print(f"الأجهزة المحلية ({len(devices['local'])}):") # تم تصحيح الأقواس هنا
114
+ for device in devices['local']:
115
+ print(f"- {device.name} ({device.ip}:{device.port})")
116
+
117
+ print(f"\nالأجهزة الخارجية ({len(devices['external'])}):") # و هنا
118
+ for device in devices['external']:
119
+ print(f"- {device.name} ({device.ip})")
120
+
121
+ time.sleep(10)
122
+ except KeyboardInterrupt:
123
+ print("\nتم إيقاف الاكتشاف.")
124
+ break
125
+
126
+ if __name__ == "__main__":
127
+ main()
peer_registry.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # peer_registry.py
2
+ import socket
3
+ import time
4
+ from zeroconf import Zeroconf, ServiceBrowser
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
+ port = info.port
15
+ self.peers.append(f"{ip}:{port}")
16
+
17
+ def discover_peers(timeout=2):
18
+ zc = Zeroconf()
19
+ listener = Listener()
20
+ ServiceBrowser(zc, "_http._tcp.local.", listener)
21
+ time.sleep(timeout)
22
+ zc.close()
23
+ return listener.peers
24
+
25
+ # استخدام Zeroconf لاكتشاف الأقران
26
+ zeroconf = Zeroconf()
27
+ listener = Listener()
28
+ browser = ServiceBrowser(zeroconf, "_taskdist._tcp.local.", listener)
29
+ time.sleep(2) # انتظار لاكتشاف الأقران
30
+ available_peers = listener.peers # ["192.168.1.2:7520", "10.0.0.5:7520"]
31
+
processor_manager.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # processor_manager.py
2
+ import psutil
3
+ from collections import deque
4
+
5
+ cpu_load = psutil.cpu_percent(interval=1) # نسبة استخدام CPU خلال ثانية
6
+ mem_available = psutil.virtual_memory().available / (1024**2) # الذاكرة المتاحة بالميجابايت
7
+
8
+ if cpu_load > 70 or mem_available < 500: # إذا تجاوز CPU 50% أو الذاكرة أقل من 500MB
9
+ trigger_offload() # تشغيل عملية التوزيع
10
+
11
+ class ResourceMonitor:
12
+ def __init__(self):
13
+ self.cpu_history = deque(maxlen=10)
14
+ self.mem_history = deque(maxlen=10)
15
+
16
+ def current_load(self):
17
+ # قياس الحمل الحالي
18
+ cpu = psutil.cpu_percent(interval=0.5) / 100.0
19
+ mem = psutil.virtual_memory().available / (1024**2)
20
+
21
+ # حفظ في التاريخ
22
+ self.cpu_history.append(cpu)
23
+ self.mem_history.append(mem)
24
+
25
+ # حساب المتوسطات
26
+ avg_cpu = sum(self.cpu_history) / len(self.cpu_history)
27
+ avg_mem = sum(self.mem_history) / len(self.mem_history)
28
+
29
+ return {
30
+ "instant": {"cpu": cpu, "mem": mem},
31
+ "average": {"cpu": avg_cpu, "mem": avg_mem},
32
+ "recommendation": "offload" if avg_cpu > 0.7 or avg_mem < 500 else "local"
33
+ }
34
+
35
+ def should_offload(task_complexity=0):
36
+ monitor = ResourceMonitor()
37
+ status = monitor.current_load()
38
+
39
+ # قرار التوزيع يعتمد على:
40
+ if (
41
+ status['average']['cpu'] > 0.6 or
42
+ status['average']['mem'] < 500 or
43
+ task_complexity > 75
44
+ ):
45
+ return True
46
+ return False
47
+
remote_executor.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # remote_executor.py
2
+ import requests
3
+ import os
4
+
5
+ # استخدم عنوان السيرفر الخارجي من المتغير البيئي أو قيمة افتراضية
6
+ REMOTE_SERVER = os.getenv("REMOTE_SERVER", "http://89.111.171.92:7520/run")
7
+
8
+ def execute_remotely(func_name, args=[], kwargs={}):
9
+ try:
10
+ payload = {
11
+ "func": func_name,
12
+ "args": args,
13
+ "kwargs": kwargs
14
+ }
15
+ response = requests.post(REMOTE_SERVER, json=payload, timeout=10)
16
+ response.raise_for_status()
17
+ data = response.json()
18
+ return data.get("result", "⚠️ لا يوجد نتيجة")
19
+ except Exception as e:
20
+ return f"❌ فشل التنفيذ البعيد: {str(e)}"
21
+
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ flask
2
+ requests
3
+ psutil
4
+ zeroconf
5
+ flask_cors
rpc_server.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # rpc_server.py
2
+
3
+ from flask import Flask, request, jsonify
4
+ import smart_tasks # ✅ غيّرنا من your_tasks إلى الاسم الحقيقي لملف المهام
5
+ import logging
6
+
7
+ # إعداد تسجيل الأحداث في ملف
8
+ logging.basicConfig(
9
+ filename="server.log",
10
+ level=logging.INFO,
11
+ format="%(asctime)s - %(levelname)s - %(message)s"
12
+ )
13
+
14
+ app = Flask(__name__)
15
+
16
+ @app.route("/health")
17
+ def health():
18
+ return jsonify(status="ok")
19
+
20
+ @app.route("/run", methods=["POST"])
21
+ def run():
22
+ try:
23
+ data = request.get_json()
24
+ func_name = data.get("func")
25
+ args = data.get("args", [])
26
+ kwargs = data.get("kwargs", {})
27
+
28
+ fn = getattr(smart_tasks, func_name, None)
29
+ if not fn:
30
+ logging.warning(f"❌ لم يتم العثور على الدالة: {func_name}")
31
+ return jsonify(error="Function not found"), 404
32
+
33
+ logging.info(f"⚙️ تنفيذ الدالة: {func_name} من جهاز آخر")
34
+ result = fn(*args, **kwargs)
35
+ return jsonify(result=result)
36
+
37
+ except Exception as e:
38
+ logging.error(f"🔥 خطأ أثناء تنفيذ المهمة: {str(e)}")
39
+ return jsonify(error=str(e)), 500
40
+
41
+ if __name__ == "__main__":
42
+ # ✅ تأكد أن هذا المنفذ 7520 أو اللي خصصته مفتوح في الجدار الناري
43
+ app.run(host="0.0.0.0", port=7520)
44
+
security_layer.py ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # security_layer.py
2
+ from cryptography.hazmat.primitives import hashes, serialization
3
+ from cryptography.hazmat.primitives.asymmetric import rsa, padding
4
+ from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
5
+ from cryptography.fernet import Fernet
6
+ import os
7
+ import base64
8
+
9
+ class SecurityManager:
10
+ def __init__(self, shared_secret: str):
11
+ self._key = self._derive_key(shared_secret)
12
+ self._cipher = Fernet(self._key)
13
+ self._private_key = rsa.generate_private_key(
14
+ public_exponent=65537,
15
+ key_size=2048
16
+ )
17
+ self._peer_keys = {}
18
+
19
+ def encrypt_data(self, data: bytes) -> bytes:
20
+ """تشفير البيانات بالمفتاح المتماثل"""
21
+ return self._cipher.encrypt(data)
22
+
23
+ def decrypt_data(self, encrypted: bytes) -> bytes:
24
+ """فك تشفير البيانات"""
25
+ return self._cipher.decrypt(encrypted)
26
+
27
+ def sign_task(self, task: Dict) -> Dict:
28
+ """توقيع المهمة رقميًا"""
29
+ signature = self._private_key.sign(
30
+ json.dumps(task).encode(),
31
+ padding.PSS(
32
+ mgf=padding.MGF1(hashes.SHA256()),
33
+ salt_length=padding.PSS.MAX_LENGTH
34
+ ),
35
+ hashes.SHA256()
36
+ )
37
+ return {**task, '_signature': base64.b64encode(signature).decode()}
38
+
39
+ def verify_task(self, signed_task: Dict) -> bool:
40
+ """التحقق من صحة التوقيع"""
41
+ if '_signature' not in signed_task:
42
+ return False
43
+
44
+ signature = base64.b64decode(signed_task['_signature'])
45
+ task_copy = {k: v for k, v in signed_task.items() if k != '_signature'}
46
+
47
+ try:
48
+ self._peer_keys[signed_task['sender_id']].verify(
49
+ signature,
50
+ json.dumps(task_copy).encode(),
51
+ padding.PSS(
52
+ mgf=padding.MGF1(hashes.SHA256()),
53
+ salt_length=padding.PSS.MAX_LENGTH
54
+ ),
55
+ hashes.SHA256()
56
+ )
57
+ return True
58
+ except:
59
+ return False
60
+
61
+ def _derive_key(self, password: str) -> bytes:
62
+ """اشتقاق مفتاح تشفير من كلمة المرور"""
63
+ salt = b'salt_placeholder' # يجب تغييره في الإنتاج
64
+ kdf = PBKDF2HMAC(
65
+ algorithm=hashes.SHA256(),
66
+ length=32,
67
+ salt=salt,
68
+ iterations=100000
69
+ )
70
+ return base64.urlsafe_b64encode(kdf.derive(password.encode()))
server.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, jsonify
2
+ from flask_cors import CORS
3
+ from your_tasks import multiply_task # دالة مربوطة بـ @offload
4
+
5
+ app = Flask(__name__)
6
+ CORS(app)
7
+
8
+ @app.route('/multiply', methods=['POST'])
9
+ def multiply():
10
+ try:
11
+ data = request.get_json()
12
+ a = data.get("a", 0)
13
+ b = data.get("b", 0)
14
+ result_dict = multiply_task(a, b) # دالة offload
15
+ return jsonify({"result": result_dict["result"]})
16
+ except Exception as e:
17
+ return jsonify({"error": str(e)}), 500
18
+
19
+ if __name__ == "__main__":
20
+ # هذا العنوان يسمح بالاستماع على IP خارجي لتلقي الاتصالات من الإنترنت
21
+ app.run(host="0.0.0.0", port=7520)
22
+
23
+
setup.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # setup.py
2
+ from setuptools import setup, find_packages
3
+
4
+ setup(
5
+ name="distributed-task-system",
6
+ version="1.0",
7
+ packages=find_packages(),
8
+ install_requires=[
9
+ "flask",
10
+ "requests",
11
+ "psutil",
12
+ "zeroconf",
13
+ "flask_cors",
14
+ "numpy"
15
+ ],
16
+ entry_points={
17
+ "console_scripts": [
18
+ "dts-start=dts_cli:main",
19
+ ],
20
+ },
21
+ data_files=[
22
+ ("/etc/systemd/system", ["dts.service"])
23
+ ]
24
+ )
setup_fonts.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import requests
3
+
4
+ FONT_DIR = "fonts"
5
+ FONT_PATH = os.path.join(FONT_DIR, "Cairo-Regular.ttf")
6
+
7
+ # 🔥 رابط مباشر من Google Fonts CDN - Cairo Regular وزن 400
8
+ URL = "https://fonts.cdnfonts.com/s/12667/Cairo-Regular.woff"
9
+
10
+ os.makedirs(FONT_DIR, exist_ok=True)
11
+
12
+ print("[+] تحميل الخط Cairo-Regular...")
13
+ response = requests.get(URL)
14
+ if response.status_code == 200:
15
+ with open(FONT_PATH, "wb") as f:
16
+ f.write(response.content)
17
+ print(f"[✅] تم حفظ الخط في {FONT_PATH}")
18
+ else:
19
+ print(f"[❌] فشل تحميل الخط! كود الحالة: {response.status_code}")
20
+
startup.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from autostart_config import AutoStartManager
2
+ from distributed_executor import DistributedExecutor
3
+ import logging
4
+ import sys
5
+
6
+ def main():
7
+ # إعداد السجل
8
+ logging.basicConfig(
9
+ filename='autostart.log',
10
+ level=logging.INFO,
11
+ format='%(asctime)s - %(levelname)s - %(message)s'
12
+ )
13
+
14
+ try:
15
+ # تحميل الإعدادات
16
+ autostart = AutoStartManager()
17
+ if not autostart.config['enabled']:
18
+ logging.info("التشغيل التلقائي معطل في الإعدادات")
19
+ return
20
+
21
+ # بدء النظام الرئيسي
22
+ logging.info("بدء تشغيل النظام الموزع تلقائياً")
23
+ executor = DistributedExecutor("my_shared_secret_123")
24
+ executor.peer_registry.register_service("auto_node", 7520)
25
+
26
+ # هنا يمكنك إضافة أي مهام تريد تشغيلها تلقائياً
27
+ # executor.submit(...)
28
+
29
+ # البقاء نشطاً
30
+ while True:
31
+ time.sleep(60)
32
+
33
+ except Exception as e:
34
+ logging.error(f"خطأ في التشغيل التلقائي: {str(e)}")
35
+ sys.exit(1)
36
+
37
+ if __name__ == "__main__":
38
+ main()
task_interceptor.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ from processor_manager import should_offload
2
+ from remote_executor import execute_remotely
3
+
4
+ def offload_if_needed(func):
5
+ def wrapper(*args, **kwargs):
6
+ if should_offload():
7
+ return execute_remotely(func.__name__, args, kwargs)
8
+ return func(*args, **kwargs)
9
+ return wrapper
task_splitter.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # task_splitter.py
2
+ from typing import Dict, Any, List
3
+ import networkx as nx
4
+ import hashlib
5
+
6
+ class TaskSplitter:
7
+ def __init__(self):
8
+ self._dependency_graph = nx.DiGraph()
9
+
10
+ def add_task(self, task_id: str, task: Dict[str, Any], deps: List[str] = []):
11
+ """إضافة مهمة مع تبعياتها"""
12
+ self._dependency_graph.add_node(task_id, task=task)
13
+ for dep in deps:
14
+ self._dependency_graph.add_edge(dep, task_id)
15
+
16
+ def split_tasks(self) -> Dict[str, List[Dict]]:
17
+ """تقسيم المهام إلى مجموعات متوازية"""
18
+ clusters = {}
19
+ for component in nx.weakly_connected_components(self._dependency_graph):
20
+ subgraph = self._dependency_graph.subgraph(component)
21
+ for level, nodes in enumerate(nx.topological_generations(subgraph)):
22
+ for node in nodes:
23
+ cluster_id = self._generate_cluster_id(node, level)
24
+ if cluster_id not in clusters:
25
+ clusters[cluster_id] = []
26
+ clusters[cluster_id].append({
27
+ 'task_id': node,
28
+ 'task': self._dependency_graph.nodes[node]['task']
29
+ })
30
+ return clusters
31
+
32
+ def _generate_cluster_id(self, node: str, level: int) -> str:
33
+ """إنشاء معرف فريد لكل مجموعة مهام"""
34
+ deps = list(self._dependency_graph.predecessors(node))
35
+ deps_hash = hashlib.md5(','.join(sorted(deps)).encode()).hexdigest()[:8]
36
+ return f"L{level}-{deps_hash}"
your_tasks.py ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from offload_lib import offload
2
+ import time
3
+ import math
4
+ import numpy as np
5
+ from typing import Dict, List, Union
6
+
7
+ # ============= وظائف مساعدة =============
8
+ def _validate_positive_integer(value: int, name: str) -> None:
9
+ """تحقق من أن القيمة عدد صحيح موجب."""
10
+ if not isinstance(value, int) or value <= 0:
11
+ raise ValueError(f"{name} يجب أن يكون عددًا صحيحًا موجبًا")
12
+
13
+ # ============= المهام الرئيسية =============
14
+ @offload
15
+ def matrix_multiply(size: int) -> Dict[str, List[List[float]]]:
16
+ """
17
+ ضرب مصفوفات كبير (عملية كثيفة الحساب)
18
+
19
+ Args:
20
+ size: حجم المصفوفة (size x size)
21
+
22
+ Returns:
23
+ نتيجة الضرب كقائمة ثنائية الأبعاد
24
+ """
25
+ _validate_positive_integer(size, "حجم المصفوفة")
26
+
27
+ A = np.random.rand(size, size)
28
+ B = np.random.rand(size, size)
29
+ return {"result": np.dot(A, B).tolist()}
30
+
31
+ @offload
32
+ def prime_calculation(n: int) -> Dict[str, Union[int, List[int]]]:
33
+ """
34
+ حساب الأعداد الأولية حتى n
35
+
36
+ Args:
37
+ n: الحد الأعلى للبحث عن الأعداد الأولية
38
+
39
+ Returns:
40
+ قامة بالأعداد الأولية وعددها
41
+ """
42
+ _validate_positive_integer(n, "الحد الأعلى للأعداد الأولية")
43
+
44
+ primes = []
45
+ for num in range(2, n + 1):
46
+ is_prime = True
47
+ for i in range(2, int(math.sqrt(num)) + 1):
48
+ if num % i == 0:
49
+ is_prime = False
50
+ break
51
+ if is_prime:
52
+ primes.append(num)
53
+ return {"primes_count": len(primes), "primes": primes}
54
+
55
+ @offload
56
+ def data_processing(data_size: int) -> Dict[str, int]:
57
+ """
58
+ محاكاة معالجة بيانات كبيرة
59
+
60
+ Args:
61
+ data_size: عدد عناصر البيانات المراد معالجتها
62
+
63
+ Returns:
64
+ عدد العناصر المعالجة
65
+ """
66
+ _validate_positive_integer(data_size, "حجم البيانات")
67
+
68
+ processed_data = []
69
+ for i in range(data_size):
70
+ result = sum(math.sin(x) * math.cos(x) for x in range(i, i+100))
71
+ processed_data.append(result)
72
+ return {"processed_items": len(processed_data)}
73
+
74
+ @offload
75
+ def image_processing_emulation(iterations: int) -> Dict[str, Union[int, float]]:
76
+ """
77
+ محاكاة معالجة الصور (عملية كثيفة الحساب)
78
+
79
+ Args:
80
+ iterations: عدد التكرارات للمحاكاة
81
+
82
+ Returns:
83
+ نتائج المحاكاة
84
+ """
85
+ _validate_positive_integer(iterations, "عدد التكرارات")
86
+
87
+ results = []
88
+ for i in range(iterations):
89
+ value = sum(math.exp(math.sin(x)) for x in range(i, i+50))
90
+ results.append(value)
91
+ return {"iterations": iterations, "result": sum(results)}
92
+
93
+ # ============= اختبار الوظائف محلياً =============
94
+ if __name__ == "__main__":
95
+ # اختبار جميع الوظائف مع معالجة الأخطاء
96
+ test_cases = [
97
+ ("matrix_multiply", matrix_multiply, 100),
98
+ ("prime_calculation", prime_calculation, 1000),
99
+ ("data_processing", data_processing, 500),
100
+ ("image_processing", image_processing_emulation, 50)
101
+ ]
102
+
103
+ for name, func, arg in test_cases:
104
+ try:
105
+ print(f"\nجارِ تشغيل: {name}...")
106
+ start = time.time()
107
+ result = func(arg)
108
+ duration = time.time() - start
109
+
110
+ print(f"النتيجة: {str(result)[:200]}...")
111
+ print(f"الوقت المستغرق: {duration:.2f} ثانية")
112
+ except Exception as e:
113
+ print(f"فشل {name}: {str(e)}")