rcoder 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,443 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Rcoder 系统进程管理模块
4
+ 支持守护进程模式和系统服务注册
5
+ """
6
+
7
+ import os
8
+ import sys
9
+ import time
10
+ import daemon
11
+ import psutil
12
+ import platform
13
+ import subprocess
14
+ from typing import Optional, Dict, Any
15
+
16
+
17
+ class ProcessManager:
18
+ """
19
+ 进程管理器
20
+ """
21
+
22
+ def __init__(self):
23
+ """
24
+ 初始化进程管理器
25
+ """
26
+ self.pid_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'rcoder.pid')
27
+ self.log_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'rcoder.log')
28
+ self.platform = platform.system().lower()
29
+
30
+ def is_running(self) -> bool:
31
+ """
32
+ 检查rcoder是否正在运行
33
+
34
+ Returns:
35
+ bool: 是否正在运行
36
+ """
37
+ if not os.path.exists(self.pid_file):
38
+ return False
39
+
40
+ try:
41
+ with open(self.pid_file, 'r') as f:
42
+ pid = int(f.read().strip())
43
+
44
+ # 检查进程是否存在
45
+ process = psutil.Process(pid)
46
+ return process.is_running()
47
+ except:
48
+ return False
49
+
50
+ def get_pid(self) -> Optional[int]:
51
+ """
52
+ 获取当前运行的PID
53
+
54
+ Returns:
55
+ int: PID或None
56
+ """
57
+ if not os.path.exists(self.pid_file):
58
+ return None
59
+
60
+ try:
61
+ with open(self.pid_file, 'r') as f:
62
+ return int(f.read().strip())
63
+ except:
64
+ return None
65
+
66
+ def start_daemon(self, main_func):
67
+ """
68
+ 以守护进程模式启动
69
+
70
+ Args:
71
+ main_func: 主函数
72
+ """
73
+ if self.is_running():
74
+ print(f"❌ Rcoder已经在运行 (PID: {self.get_pid()})")
75
+ return False
76
+
77
+ print(f"🔄 以守护进程模式启动Rcoder...")
78
+ print(f"📋 PID文件: {self.pid_file}")
79
+ print(f"📋 日志文件: {self.log_file}")
80
+
81
+ # 创建日志目录
82
+ log_dir = os.path.dirname(self.log_file)
83
+ os.makedirs(log_dir, exist_ok=True)
84
+
85
+ # 以守护进程模式运行
86
+ with open(self.log_file, 'a') as log:
87
+ with daemon.DaemonContext(
88
+ stdout=log,
89
+ stderr=log,
90
+ working_directory=os.path.dirname(os.path.abspath(__file__))
91
+ ):
92
+ # 写入PID
93
+ with open(self.pid_file, 'w') as f:
94
+ f.write(str(os.getpid()))
95
+
96
+ try:
97
+ print(f"✅ Rcoder守护进程已启动 (PID: {os.getpid()})")
98
+ main_func()
99
+ finally:
100
+ # 清理PID文件
101
+ if os.path.exists(self.pid_file):
102
+ try:
103
+ os.remove(self.pid_file)
104
+ except:
105
+ pass
106
+
107
+ return True
108
+
109
+ def stop(self):
110
+ """
111
+ 停止运行的Rcoder进程
112
+
113
+ Returns:
114
+ bool: 是否停止成功
115
+ """
116
+ if not self.is_running():
117
+ print("❌ Rcoder未在运行")
118
+ return False
119
+
120
+ pid = self.get_pid()
121
+ print(f"🔄 停止Rcoder进程 (PID: {pid})...")
122
+
123
+ try:
124
+ process = psutil.Process(pid)
125
+ process.terminate()
126
+
127
+ # 等待进程退出
128
+ for _ in range(10):
129
+ if not process.is_running():
130
+ break
131
+ time.sleep(0.5)
132
+
133
+ # 如果进程仍在运行,强制终止
134
+ if process.is_running():
135
+ process.kill()
136
+ time.sleep(0.5)
137
+
138
+ # 清理PID文件
139
+ if os.path.exists(self.pid_file):
140
+ os.remove(self.pid_file)
141
+
142
+ print("✅ Rcoder进程已停止")
143
+ return True
144
+ except Exception as e:
145
+ print(f"❌ 停止进程失败: {e}")
146
+ return False
147
+
148
+ def restart(self, main_func):
149
+ """
150
+ 重启Rcoder进程
151
+
152
+ Args:
153
+ main_func: 主函数
154
+
155
+ Returns:
156
+ bool: 是否重启成功
157
+ """
158
+ print("🔄 重启Rcoder进程...")
159
+
160
+ # 停止当前进程
161
+ self.stop()
162
+
163
+ # 启动新进程
164
+ return self.start_daemon(main_func)
165
+
166
+ def status(self):
167
+ """
168
+ 查看Rcoder运行状态
169
+ """
170
+ if self.is_running():
171
+ pid = self.get_pid()
172
+ process = psutil.Process(pid)
173
+ status = {
174
+ 'pid': pid,
175
+ 'status': process.status(),
176
+ 'memory': f"{process.memory_info().rss / 1024 / 1024:.2f} MB",
177
+ 'cpu': f"{process.cpu_percent(interval=1):.1f}%",
178
+ 'start_time': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(process.create_time()))
179
+ }
180
+
181
+ print("✅ Rcoder运行状态:")
182
+ for key, value in status.items():
183
+ print(f" {key}: {value}")
184
+
185
+ return status
186
+ else:
187
+ print("❌ Rcoder未在运行")
188
+ return None
189
+
190
+ def register_service(self):
191
+ """
192
+ 注册为系统服务
193
+ """
194
+ print(f"🔄 在{self.platform}平台注册系统服务...")
195
+
196
+ if self.platform == 'linux':
197
+ return self._register_linux_service()
198
+ elif self.platform == 'windows':
199
+ return self._register_windows_service()
200
+ elif self.platform == 'darwin':
201
+ return self._register_mac_service()
202
+ else:
203
+ print(f"❌ 不支持的平台: {self.platform}")
204
+ return False
205
+
206
+ def _register_linux_service(self):
207
+ """
208
+ 在Linux上注册系统服务
209
+ """
210
+ service_file = '/etc/systemd/system/rcoder.service'
211
+ python_path = sys.executable
212
+ script_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'rcoder_main.py')
213
+
214
+ service_content = f"""
215
+ [Unit]
216
+ Description=Rcoder - 远程代码执行与管理系统
217
+ After=network.target
218
+
219
+ [Service]
220
+ Type=simple
221
+ ExecStart={python_path} {script_path} --daemon
222
+ WorkingDirectory={os.path.dirname(script_path)}
223
+ Restart=always
224
+ RestartSec=5
225
+
226
+ [Install]
227
+ WantedBy=multi-user.target
228
+ """
229
+
230
+ try:
231
+ # 写入服务文件
232
+ with open(service_file, 'w') as f:
233
+ f.write(service_content)
234
+
235
+ # 重新加载systemd
236
+ subprocess.run(['systemctl', 'daemon-reload'], check=True)
237
+
238
+ # 启用服务
239
+ subprocess.run(['systemctl', 'enable', 'rcoder.service'], check=True)
240
+
241
+ print(f"✅ 已在Linux上注册系统服务: {service_file}")
242
+ print("📋 服务命令:")
243
+ print(" systemctl start rcoder.service # 启动服务")
244
+ print(" systemctl stop rcoder.service # 停止服务")
245
+ print(" systemctl status rcoder.service # 查看状态")
246
+ print(" systemctl enable rcoder.service # 开机自启")
247
+ print(" systemctl disable rcoder.service # 禁用开机自启")
248
+
249
+ return True
250
+ except Exception as e:
251
+ print(f"❌ 注册Linux服务失败: {e}")
252
+ print("⚠️ 可能需要sudo权限")
253
+ return False
254
+
255
+ def _register_windows_service(self):
256
+ """
257
+ 在Windows上注册系统服务
258
+ """
259
+ try:
260
+ # 使用sc命令创建服务
261
+ python_path = sys.executable
262
+ script_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'rcoder_main.py')
263
+
264
+ # 构建命令
265
+ command = f'sc create Rcoder binPath= "{python_path} {script_path} --daemon" start= auto DisplayName= "Rcoder - 远程代码执行与管理系统"'
266
+
267
+ result = subprocess.run(command, shell=True, capture_output=True, text=True)
268
+
269
+ if 'SUCCESS' in result.stdout:
270
+ print("✅ 已在Windows上注册系统服务: Rcoder")
271
+ print("📋 服务命令:")
272
+ print(" net start Rcoder # 启动服务")
273
+ print(" net stop Rcoder # 停止服务")
274
+ print(" sc query Rcoder # 查看状态")
275
+ print(" sc delete Rcoder # 删除服务")
276
+ return True
277
+ else:
278
+ print(f"❌ 注册Windows服务失败: {result.stderr}")
279
+ print("⚠️ 可能需要管理员权限")
280
+ return False
281
+ except Exception as e:
282
+ print(f"❌ 注册Windows服务失败: {e}")
283
+ return False
284
+
285
+ def _register_mac_service(self):
286
+ """
287
+ 在Mac上注册系统服务
288
+ """
289
+ launchd_plist = '~/Library/LaunchAgents/com.rcoder.plist'
290
+ python_path = sys.executable
291
+ script_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'rcoder_main.py')
292
+
293
+ plist_content = f"""
294
+ <?xml version="1.0" encoding="UTF-8"?>
295
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
296
+ <plist version="1.0">
297
+ <dict>
298
+ <key>Label</key>
299
+ <string>com.rcoder</string>
300
+ <key>ProgramArguments</key>
301
+ <array>
302
+ <string>{python_path}</string>
303
+ <string>{script_path}</string>
304
+ <string>--daemon</string>
305
+ </array>
306
+ <key>RunAtLoad</key>
307
+ <true/>
308
+ <key>KeepAlive</key>
309
+ <true/>
310
+ <key>StandardOutPath</key>
311
+ <string>{self.log_file}</string>
312
+ <key>StandardErrorPath</key>
313
+ <string>{self.log_file}</string>
314
+ </dict>
315
+ </plist>
316
+ """
317
+
318
+ try:
319
+ plist_path = os.path.expanduser(launchd_plist)
320
+ plist_dir = os.path.dirname(plist_path)
321
+ os.makedirs(plist_dir, exist_ok=True)
322
+
323
+ # 写入plist文件
324
+ with open(plist_path, 'w') as f:
325
+ f.write(plist_content)
326
+
327
+ # 加载服务
328
+ subprocess.run(['launchctl', 'load', plist_path], check=True)
329
+
330
+ print(f"✅ 已在Mac上注册系统服务: {plist_path}")
331
+ print("📋 服务命令:")
332
+ print(f" launchctl load {plist_path} # 加载服务")
333
+ print(f" launchctl unload {plist_path} # 卸载服务")
334
+ print(f" launchctl start com.rcoder # 启动服务")
335
+ print(f" launchctl stop com.rcoder # 停止服务")
336
+
337
+ return True
338
+ except Exception as e:
339
+ print(f"❌ 注册Mac服务失败: {e}")
340
+ return False
341
+
342
+ def unregister_service(self):
343
+ """
344
+ 注销系统服务
345
+ """
346
+ print(f"🔄 注销系统服务...")
347
+
348
+ if self.platform == 'linux':
349
+ return self._unregister_linux_service()
350
+ elif self.platform == 'windows':
351
+ return self._unregister_windows_service()
352
+ elif self.platform == 'darwin':
353
+ return self._unregister_mac_service()
354
+ else:
355
+ print(f"❌ 不支持的平台: {self.platform}")
356
+ return False
357
+
358
+ def _unregister_linux_service(self):
359
+ """
360
+ 在Linux上注销系统服务
361
+ """
362
+ try:
363
+ subprocess.run(['systemctl', 'stop', 'rcoder.service'], check=True)
364
+ subprocess.run(['systemctl', 'disable', 'rcoder.service'], check=True)
365
+ subprocess.run(['rm', '/etc/systemd/system/rcoder.service'], check=True)
366
+ subprocess.run(['systemctl', 'daemon-reload'], check=True)
367
+
368
+ print("✅ 已注销Linux系统服务")
369
+ return True
370
+ except Exception as e:
371
+ print(f"❌ 注销Linux服务失败: {e}")
372
+ return False
373
+
374
+ def _unregister_windows_service(self):
375
+ """
376
+ 在Windows上注销系统服务
377
+ """
378
+ try:
379
+ subprocess.run('sc stop Rcoder', shell=True, capture_output=True)
380
+ result = subprocess.run('sc delete Rcoder', shell=True, capture_output=True, text=True)
381
+
382
+ if 'SUCCESS' in result.stdout:
383
+ print("✅ 已注销Windows系统服务")
384
+ return True
385
+ else:
386
+ print(f"❌ 注销Windows服务失败: {result.stderr}")
387
+ return False
388
+ except Exception as e:
389
+ print(f"❌ 注销Windows服务失败: {e}")
390
+ return False
391
+
392
+ def _unregister_mac_service(self):
393
+ """
394
+ 在Mac上注销系统服务
395
+ """
396
+ plist_path = os.path.expanduser('~/Library/LaunchAgents/com.rcoder.plist')
397
+
398
+ try:
399
+ subprocess.run(['launchctl', 'unload', plist_path], check=True)
400
+ if os.path.exists(plist_path):
401
+ os.remove(plist_path)
402
+
403
+ print("✅ 已注销Mac系统服务")
404
+ return True
405
+ except Exception as e:
406
+ print(f"❌ 注销Mac服务失败: {e}")
407
+ return False
408
+
409
+
410
+ # 测试代码
411
+ if __name__ == "__main__":
412
+ def test_main():
413
+ print("✅ Rcoder守护进程测试")
414
+ while True:
415
+ time.sleep(1)
416
+
417
+ pm = ProcessManager()
418
+
419
+ import argparse
420
+ parser = argparse.ArgumentParser(description='Rcoder进程管理')
421
+ parser.add_argument('--start', action='store_true', help='启动守护进程')
422
+ parser.add_argument('--stop', action='store_true', help='停止进程')
423
+ parser.add_argument('--restart', action='store_true', help='重启进程')
424
+ parser.add_argument('--status', action='store_true', help='查看状态')
425
+ parser.add_argument('--register-service', action='store_true', help='注册系统服务')
426
+ parser.add_argument('--unregister-service', action='store_true', help='注销系统服务')
427
+
428
+ args = parser.parse_args()
429
+
430
+ if args.start:
431
+ pm.start_daemon(test_main)
432
+ elif args.stop:
433
+ pm.stop()
434
+ elif args.restart:
435
+ pm.restart(test_main)
436
+ elif args.status:
437
+ pm.status()
438
+ elif args.register_service:
439
+ pm.register_service()
440
+ elif args.unregister_service:
441
+ pm.unregister_service()
442
+ else:
443
+ parser.print_help()