THEZYZSTUDIO commited on
Commit
135ebc5
·
verified ·
1 Parent(s): be47c3c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +364 -43
app.py CHANGED
@@ -1,45 +1,366 @@
1
- from fastapi import FastAPI, Request, UploadFile, File, HTTPException
2
- from fastapi.responses import JSONResponse
3
- from fastapi.middleware.cors import CORSMiddleware
4
- from pydantic import BaseModel
5
- from pc_agent import run_command, list_files, cleanup, ensure_workspace
6
- import aiofiles
 
 
 
 
 
 
 
 
 
 
7
  import os
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
- app = FastAPI()
10
- app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])
11
-
12
- class CommandRequest(BaseModel):
13
- cmd: str
14
-
15
- @app.post("/agent/run")
16
- async def execute_command(req: CommandRequest):
17
- res = run_command(req.cmd)
18
- status = res.pop("code", 200)
19
- return JSONResponse(status_code=status, content=res)
20
-
21
- @app.get("/agent/files")
22
- async def get_files():
23
- return {"files": list_files()}
24
-
25
- @app.post("/agent/cleanup")
26
- async def reset_workspace():
27
- cleanup()
28
- return {"status": "workspace cleared"}
29
-
30
- @app.post("/agent/upload")
31
- async def upload_file(file: UploadFile = File(...)):
32
- ws = ensure_workspace()
33
- dest = ws / "uploads" / file.filename
34
- # منع تجاوز المسار
35
- if not str(dest.resolve()).startswith(str(ws.resolve())):
36
- raise HTTPException(400, "Invalid file path")
37
-
38
- async with aiofiles.open(dest, "wb") as out_file:
39
- content = await file.read()
40
- await out_file.write(content)
41
- return {"status": "uploaded", "path": f"uploads/{file.filename}"}
42
-
43
- @app.get("/health")
44
- def health():
45
- return {"status": "pc_agent_online"}
 
1
+ """
2
+ ╔══════════════════════════════════════════════════════════════╗
3
+ ║ THE Z AI/AGENT — LINUX SYSTEM SERVER ║
4
+ ║ 🖥️ سيرفر نظام Linux — يتحكم فيه الذكاء الاصطناعي ║
5
+ ╚══════════════════════════════════════════════════════════════╝
6
+
7
+ هذا الملف خاص بـ: سيرفر 2 (سيرفر نظام Linux)
8
+ This file belongs to: SERVER 2 (Linux System Server)
9
+
10
+ ✅ تنفيذ أوامر Terminal
11
+ ✅ تصفح الإنترنت (browser automation)
12
+ ✅ كتابة وتشغيل Python/JS
13
+ ✅ إدارة الملفات والمجلدات
14
+ ✅ حماية بـ API Token
15
+ """
16
+
17
  import os
18
+ import json
19
+ import subprocess
20
+ import shutil
21
+ import tempfile
22
+ import signal
23
+ import platform
24
+ import psutil
25
+ import time
26
+ from pathlib import Path
27
+ from flask import Flask, request, jsonify, send_from_directory
28
+ from flask_cors import CORS
29
+
30
+ app = Flask(__name__)
31
+ CORS(app)
32
+
33
+ # ══════════════════════════════════════════
34
+ # Security — API Token
35
+ # ══════════════════════════════════════════
36
+ API_TOKEN = os.environ.get("LINUX_API_TOKEN", "zyz-linux-secret-2025")
37
+ WORKSPACE = "/workspace"
38
+ os.makedirs(WORKSPACE, exist_ok=True)
39
+
40
+
41
+ def check_token():
42
+ token = request.headers.get("X-API-Token", "")
43
+ if token != API_TOKEN:
44
+ return False
45
+ return True
46
+
47
+
48
+ def require_token(fn):
49
+ from functools import wraps
50
+ @wraps(fn)
51
+ def wrapper(*args, **kwargs):
52
+ if not check_token():
53
+ return jsonify({"error": "Unauthorized — invalid or missing API token"}), 401
54
+ return fn(*args, **kwargs)
55
+ return wrapper
56
+
57
+
58
+ # ══════════════════════════════════════════
59
+ # /api/status — حالة السيرفر
60
+ # ══════════════════════════════════════════
61
+ @app.route("/api/status", methods=["GET"])
62
+ @require_token
63
+ def status():
64
+ return jsonify({
65
+ "status": "online",
66
+ "server": "Linux System Server — THE Z AI",
67
+ "platform": platform.system() + " " + platform.release(),
68
+ "python": platform.python_version(),
69
+ "workspace": WORKSPACE,
70
+ "uptime": int(time.time())
71
+ })
72
+
73
+
74
+ # ══════════════════════════════════════════
75
+ # /api/execute — تنفيذ أمر Terminal
76
+ # ══════════════════════════════════════════
77
+ @app.route("/api/execute", methods=["POST"])
78
+ @require_token
79
+ def execute():
80
+ data = request.json or {}
81
+ command = data.get("command", "").strip()
82
+ cwd = data.get("cwd", WORKSPACE)
83
+ timeout = int(data.get("timeout", 60))
84
+
85
+ if not command:
86
+ return jsonify({"error": "No command provided"}), 400
87
+
88
+ # تأكد من مجلد العمل موجود
89
+ if not os.path.isdir(cwd):
90
+ cwd = WORKSPACE
91
+
92
+ try:
93
+ proc = subprocess.run(
94
+ command,
95
+ shell=True,
96
+ cwd=cwd,
97
+ capture_output=True,
98
+ text=True,
99
+ timeout=timeout,
100
+ env={**os.environ, "HOME": "/root", "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/nodejs/bin"}
101
+ )
102
+ return jsonify({
103
+ "stdout": proc.stdout,
104
+ "stderr": proc.stderr,
105
+ "returncode": proc.returncode,
106
+ "command": command,
107
+ "cwd": cwd
108
+ })
109
+ except subprocess.TimeoutExpired:
110
+ return jsonify({
111
+ "stdout": "",
112
+ "stderr": f"⏰ Command timed out after {timeout}s",
113
+ "returncode": -1,
114
+ "command": command,
115
+ "cwd": cwd
116
+ })
117
+ except Exception as e:
118
+ return jsonify({
119
+ "stdout": "",
120
+ "stderr": str(e),
121
+ "returncode": -1,
122
+ "command": command,
123
+ "cwd": cwd
124
+ })
125
+
126
+
127
+ # ══════════════════════════════════════════
128
+ # /api/sysinfo — معلومات النظام الكاملة
129
+ # ═���════════════════════════════════════════
130
+ @app.route("/api/sysinfo", methods=["GET"])
131
+ @require_token
132
+ def sysinfo():
133
+ try:
134
+ cpu_percent = psutil.cpu_percent(interval=1)
135
+ mem = psutil.virtual_memory()
136
+ disk = psutil.disk_usage("/")
137
+ boot_time = psutil.boot_time()
138
+ uptime_sec = int(time.time() - boot_time)
139
+ h = uptime_sec // 3600
140
+ m = (uptime_sec % 3600) // 60
141
+ s = uptime_sec % 60
142
+
143
+ return jsonify({
144
+ "platform": platform.system(),
145
+ "platform_ver": platform.release(),
146
+ "python_ver": platform.python_version(),
147
+ "cpu_count": psutil.cpu_count(),
148
+ "cpu_percent": cpu_percent,
149
+ "ram_total_gb": round(mem.total / (1024**3), 2),
150
+ "ram_used_gb": round(mem.used / (1024**3), 2),
151
+ "ram_percent": mem.percent,
152
+ "disk_total_gb": round(disk.total / (1024**3), 2),
153
+ "disk_used_gb": round(disk.used / (1024**3), 2),
154
+ "disk_percent": disk.percent,
155
+ "uptime": f"{h}h {m}m {s}s",
156
+ "workspace": WORKSPACE
157
+ })
158
+ except Exception as e:
159
+ return jsonify({"error": str(e)}), 500
160
+
161
+
162
+ # ══════════════════════════════════════════
163
+ # /api/files/list — قائمة الملفات
164
+ # ══════════════════════════════════════════
165
+ @app.route("/api/files/list", methods=["GET"])
166
+ @require_token
167
+ def files_list():
168
+ path = request.args.get("path", WORKSPACE)
169
+ if not os.path.isdir(path):
170
+ return jsonify({"error": "Directory not found"}), 404
171
+ try:
172
+ items = []
173
+ for name in sorted(os.listdir(path)):
174
+ full = os.path.join(path, name)
175
+ items.append({
176
+ "name": name,
177
+ "type": "dir" if os.path.isdir(full) else "file",
178
+ "size": os.path.getsize(full) if os.path.isfile(full) else 0,
179
+ "path": full
180
+ })
181
+ return jsonify({"path": path, "items": items})
182
+ except Exception as e:
183
+ return jsonify({"error": str(e)}), 500
184
+
185
+
186
+ # ══════════════════════════════════════════
187
+ # /api/files/read — قراءة محتوى ملف
188
+ # ══════════════════════════════════════════
189
+ @app.route("/api/files/read", methods=["GET"])
190
+ @require_token
191
+ def files_read():
192
+ path = request.args.get("path", "")
193
+ if not path or not os.path.isfile(path):
194
+ return jsonify({"error": "File not found"}), 404
195
+ try:
196
+ with open(path, "r", encoding="utf-8", errors="replace") as f:
197
+ content = f.read()
198
+ return jsonify({"path": path, "content": content, "size": len(content)})
199
+ except Exception as e:
200
+ return jsonify({"error": str(e)}), 500
201
+
202
+
203
+ # ══════════════════════════════════════════
204
+ # /api/files/write — كتابة ملف
205
+ # ══════════════════════════════════════════
206
+ @app.route("/api/files/write", methods=["POST"])
207
+ @require_token
208
+ def files_write():
209
+ data = request.json or {}
210
+ path = data.get("path", "")
211
+ content = data.get("content", "")
212
+ if not path:
213
+ return jsonify({"error": "path required"}), 400
214
+ try:
215
+ os.makedirs(os.path.dirname(path) or WORKSPACE, exist_ok=True)
216
+ with open(path, "w", encoding="utf-8") as f:
217
+ f.write(content)
218
+ return jsonify({"success": True, "path": path, "size": len(content)})
219
+ except Exception as e:
220
+ return jsonify({"error": str(e)}), 500
221
+
222
+
223
+ # ══════════════════════════════════════════
224
+ # /api/files/delete — حذف ملف أو مجلد
225
+ # ══════════════════════════════════════════
226
+ @app.route("/api/files/delete", methods=["POST"])
227
+ @require_token
228
+ def files_delete():
229
+ data = request.json or {}
230
+ path = data.get("path", "")
231
+ if not path or not os.path.exists(path):
232
+ return jsonify({"error": "Path not found"}), 404
233
+ try:
234
+ if os.path.isdir(path):
235
+ shutil.rmtree(path)
236
+ else:
237
+ os.remove(path)
238
+ return jsonify({"success": True, "path": path})
239
+ except Exception as e:
240
+ return jsonify({"error": str(e)}), 500
241
+
242
+
243
+ # ══════════════════════════════════════════
244
+ # /api/files/download — تنزيل ملف
245
+ # ══════════════════════════════════════════
246
+ @app.route("/api/files/download", methods=["GET"])
247
+ @require_token
248
+ def files_download():
249
+ path = request.args.get("path", "")
250
+ if not path or not os.path.isfile(path):
251
+ return jsonify({"error": "File not found"}), 404
252
+ directory = os.path.dirname(path)
253
+ filename = os.path.basename(path)
254
+ return send_from_directory(directory, filename, as_attachment=True)
255
+
256
+
257
+ # ══════════════════════════════════════════
258
+ # /api/files/upload — رفع ملف
259
+ # ══════════════════════════════════════════
260
+ @app.route("/api/files/upload", methods=["POST"])
261
+ @require_token
262
+ def files_upload():
263
+ if "file" not in request.files:
264
+ return jsonify({"error": "No file"}), 400
265
+ f = request.files["file"]
266
+ dest = request.form.get("dest", WORKSPACE)
267
+ os.makedirs(dest, exist_ok=True)
268
+ save_path = os.path.join(dest, os.path.basename(f.filename))
269
+ f.save(save_path)
270
+ return jsonify({"success": True, "path": save_path, "size": os.path.getsize(save_path)})
271
+
272
+
273
+ # ══════════════════════════════════════════
274
+ # /api/run/python — تشغيل Python مباشرة
275
+ # ══════════════════════════════════════════
276
+ @app.route("/api/run/python", methods=["POST"])
277
+ @require_token
278
+ def run_python():
279
+ data = request.json or {}
280
+ code = data.get("code", "")
281
+ timeout = int(data.get("timeout", 30))
282
+ if not code:
283
+ return jsonify({"error": "No code provided"}), 400
284
+
285
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".py", dir=WORKSPACE, delete=False, encoding="utf-8") as tmp:
286
+ tmp.write(code)
287
+ tmp_path = tmp.name
288
+
289
+ try:
290
+ proc = subprocess.run(
291
+ ["python3", tmp_path],
292
+ capture_output=True, text=True,
293
+ timeout=timeout, cwd=WORKSPACE
294
+ )
295
+ return jsonify({
296
+ "stdout": proc.stdout,
297
+ "stderr": proc.stderr,
298
+ "returncode": proc.returncode
299
+ })
300
+ except subprocess.TimeoutExpired:
301
+ return jsonify({"stdout": "", "stderr": f"Timeout after {timeout}s", "returncode": -1})
302
+ except Exception as e:
303
+ return jsonify({"stdout": "", "stderr": str(e), "returncode": -1})
304
+ finally:
305
+ try:
306
+ os.remove(tmp_path)
307
+ except Exception:
308
+ pass
309
+
310
+
311
+ # ══════════════════════════════════════════
312
+ # /api/run/javascript — تشغيل JavaScript
313
+ # ══════════════════════════════════════════
314
+ @app.route("/api/run/javascript", methods=["POST"])
315
+ @require_token
316
+ def run_javascript():
317
+ data = request.json or {}
318
+ code = data.get("code", "")
319
+ timeout = int(data.get("timeout", 30))
320
+ if not code:
321
+ return jsonify({"error": "No code provided"}), 400
322
+
323
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".js", dir=WORKSPACE, delete=False, encoding="utf-8") as tmp:
324
+ tmp.write(code)
325
+ tmp_path = tmp.name
326
+
327
+ try:
328
+ proc = subprocess.run(
329
+ ["node", tmp_path],
330
+ capture_output=True, text=True,
331
+ timeout=timeout, cwd=WORKSPACE
332
+ )
333
+ return jsonify({
334
+ "stdout": proc.stdout,
335
+ "stderr": proc.stderr,
336
+ "returncode": proc.returncode
337
+ })
338
+ except subprocess.TimeoutExpired:
339
+ return jsonify({"stdout": "", "stderr": f"Timeout after {timeout}s", "returncode": -1})
340
+ except Exception as e:
341
+ return jsonify({"stdout": "", "stderr": str(e), "returncode": -1})
342
+ finally:
343
+ try:
344
+ os.remove(tmp_path)
345
+ except Exception:
346
+ pass
347
+
348
+
349
+ # ══════════════════════════════════════════
350
+ # Root — ping check
351
+ # ══════════════════════════════════════════
352
+ @app.route("/")
353
+ def root():
354
+ return jsonify({
355
+ "server": "THE Z AI — Linux System Server",
356
+ "status": "online",
357
+ "docs": "/api/status"
358
+ })
359
+
360
 
361
+ if __name__ == "__main__":
362
+ port = int(os.environ.get("PORT", 7860))
363
+ print(f"🖥️ Linux System Server starting on port {port}")
364
+ print(f"📁 Workspace: {WORKSPACE}")
365
+ print(f"🔑 Token: {'SET' if API_TOKEN else 'NOT SET'}")
366
+ app.run(host="0.0.0.0", port=port, debug=False, threaded=True)