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.
- rcoder/__init__.py +8 -0
- rcoder/async_feedback.py +725 -0
- rcoder/async_proxy.py +556 -0
- rcoder/auto_optimizer.py +648 -0
- rcoder/cli.py +145 -0
- rcoder/conversational_config.py +345 -0
- rcoder/core.py +584 -0
- rcoder/core_optimized.py +958 -0
- rcoder/process_manager.py +443 -0
- rcoder/remote_tools.py +434 -0
- rcoder/server_installer.py +373 -0
- rcoder/utils.py +213 -0
- rcoder-1.0.0.dist-info/METADATA +442 -0
- rcoder-1.0.0.dist-info/RECORD +18 -0
- rcoder-1.0.0.dist-info/WHEEL +5 -0
- rcoder-1.0.0.dist-info/entry_points.txt +2 -0
- rcoder-1.0.0.dist-info/licenses/LICENSE +21 -0
- rcoder-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -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()
|