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/async_proxy.py ADDED
@@ -0,0 +1,556 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Rcoder 异步代理通讯模块
4
+ 优化中转服务器场景下的异步通讯机制 - 带消息队列
5
+ """
6
+
7
+ import asyncio
8
+ import json
9
+ import time
10
+ import os
11
+ import pickle
12
+ from typing import Optional, Dict, Any, Callable, List
13
+
14
+ class MessageQueue:
15
+ """
16
+ 消息队列管理器
17
+ 确保命令按顺序执行且不丢失
18
+ """
19
+
20
+ def __init__(self, queue_dir: str = "./message_queue"):
21
+ """
22
+ 初始化消息队列
23
+
24
+ Args:
25
+ queue_dir: 队列持久化目录
26
+ """
27
+ self.queue_dir = queue_dir
28
+ self.queue = []
29
+ self.processing = set()
30
+ self._lock = asyncio.Lock()
31
+
32
+ # 创建队列目录
33
+ os.makedirs(queue_dir, exist_ok=True)
34
+
35
+ # 加载持久化队列
36
+ self._load_queue()
37
+
38
+ async def enqueue(self, item: Dict[str, Any]) -> str:
39
+ """
40
+ 入队
41
+
42
+ Args:
43
+ item: 队列项
44
+
45
+ Returns:
46
+ 队列项ID
47
+ """
48
+ async with self._lock:
49
+ item_id = item.get('id', f"msg_{int(time.time())}_{len(self.queue)}")
50
+ item['id'] = item_id
51
+ item['status'] = 'pending'
52
+ item['timestamp'] = time.time()
53
+ item['sequence'] = len(self.queue)
54
+
55
+ self.queue.append(item)
56
+ self._save_queue()
57
+
58
+ return item_id
59
+
60
+ async def dequeue(self) -> Optional[Dict[str, Any]]:
61
+ """
62
+ 出队
63
+
64
+ Returns:
65
+ 队列项或None
66
+ """
67
+ async with self._lock:
68
+ if not self.queue:
69
+ return None
70
+
71
+ # 找到第一个待处理的项
72
+ for i, item in enumerate(self.queue):
73
+ if item['status'] == 'pending' and item['id'] not in self.processing:
74
+ item['status'] = 'processing'
75
+ item['processing_time'] = time.time()
76
+ self.processing.add(item['id'])
77
+ self._save_queue()
78
+ return item
79
+
80
+ return None
81
+
82
+ async def complete(self, item_id: str, result: Dict[str, Any]) -> bool:
83
+ """
84
+ 完成处理
85
+
86
+ Args:
87
+ item_id: 队列项ID
88
+ result: 处理结果
89
+
90
+ Returns:
91
+ 是否成功
92
+ """
93
+ async with self._lock:
94
+ for item in self.queue:
95
+ if item['id'] == item_id:
96
+ item['status'] = 'completed'
97
+ item['result'] = result
98
+ item['completion_time'] = time.time()
99
+ self.processing.remove(item_id)
100
+ self._save_queue()
101
+ return True
102
+ return False
103
+
104
+ async def fail(self, item_id: str, error: str) -> bool:
105
+ """
106
+ 处理失败
107
+
108
+ Args:
109
+ item_id: 队列项ID
110
+ error: 错误信息
111
+
112
+ Returns:
113
+ 是否成功
114
+ """
115
+ async with self._lock:
116
+ for item in self.queue:
117
+ if item['id'] == item_id:
118
+ item['status'] = 'failed'
119
+ item['error'] = error
120
+ item['completion_time'] = time.time()
121
+ self.processing.remove(item_id)
122
+ self._save_queue()
123
+ return True
124
+ return False
125
+
126
+ def get_queue_status(self) -> Dict[str, Any]:
127
+ """
128
+ 获取队列状态
129
+
130
+ Returns:
131
+ 队列状态
132
+ """
133
+ status = {
134
+ 'total': len(self.queue),
135
+ 'pending': sum(1 for item in self.queue if item['status'] == 'pending'),
136
+ 'processing': sum(1 for item in self.queue if item['status'] == 'processing'),
137
+ 'completed': sum(1 for item in self.queue if item['status'] == 'completed'),
138
+ 'failed': sum(1 for item in self.queue if item['status'] == 'failed')
139
+ }
140
+ return status
141
+
142
+ def _save_queue(self):
143
+ """
144
+ 持久化队列
145
+ """
146
+ queue_file = os.path.join(self.queue_dir, "message_queue.pkl")
147
+ try:
148
+ with open(queue_file, 'wb') as f:
149
+ pickle.dump(self.queue, f)
150
+ except Exception as e:
151
+ print(f"❌ 保存队列失败: {e}")
152
+
153
+ def _load_queue(self):
154
+ """
155
+ 加载持久化队列
156
+ """
157
+ queue_file = os.path.join(self.queue_dir, "message_queue.pkl")
158
+ try:
159
+ if os.path.exists(queue_file):
160
+ with open(queue_file, 'rb') as f:
161
+ self.queue = pickle.load(f)
162
+ # 重置处理状态
163
+ for item in self.queue:
164
+ if item['status'] == 'processing':
165
+ item['status'] = 'pending'
166
+ self.processing.clear()
167
+ print(f"✅ 加载队列成功,共 {len(self.queue)} 项")
168
+ except Exception as e:
169
+ print(f"❌ 加载队列失败: {e}")
170
+ self.queue = []
171
+
172
+
173
+ class AsyncProxyManager:
174
+ """
175
+ 异步代理管理器
176
+ 实现中转服务器场景下的异步通讯机制 - 带消息队列
177
+ """
178
+
179
+ def __init__(self, remote_host):
180
+ """
181
+ 初始化异步代理管理器
182
+
183
+ Args:
184
+ remote_host: 远程主机实例
185
+ """
186
+ self.remote = remote_host
187
+ self.command_counter = 0
188
+ self._lock = asyncio.Lock()
189
+ self._event_loop = asyncio.get_event_loop()
190
+
191
+ # 创建消息队列
192
+ self.message_queue = MessageQueue()
193
+
194
+ # 启动队列处理器
195
+ self._queue_processor_task = self._event_loop.create_task(self._process_queue())
196
+
197
+ async def _process_queue(self):
198
+ """
199
+ 处理消息队列
200
+ """
201
+ while True:
202
+ try:
203
+ # 从队列中获取待处理项
204
+ item = await self.message_queue.dequeue()
205
+ if not item:
206
+ await asyncio.sleep(0.1) # 避免忙等
207
+ continue
208
+
209
+ print(f"🔄 处理队列项: {item['id']} (序列: {item['sequence']})")
210
+
211
+ # 执行代理命令
212
+ result = await self._execute_proxy_command(
213
+ item['proxy_command'],
214
+ item['id'],
215
+ item.get('callback')
216
+ )
217
+
218
+ # 标记完成
219
+ await self.message_queue.complete(item['id'], result)
220
+ print(f"✅ 队列项处理完成: {item['id']}")
221
+
222
+ except Exception as e:
223
+ print(f"❌ 队列处理器错误: {e}")
224
+ await asyncio.sleep(1) # 出错后暂停一下
225
+
226
+ async def _execute_proxy_command(self, proxy_command: str, command_id: str, callback: Optional[Callable]) -> Dict[str, Any]:
227
+ """
228
+ 执行代理命令
229
+
230
+ Args:
231
+ proxy_command: 代理命令
232
+ command_id: 命令ID
233
+ callback: 回调函数
234
+
235
+ Returns:
236
+ 执行结果
237
+ """
238
+ try:
239
+ result = await self.remote.run_async(proxy_command)
240
+
241
+ # 解析结果
242
+ try:
243
+ feedback = json.loads(result.strip())
244
+ print(f"✅ 收到中转服务器反馈: {command_id} - {feedback.get('status')}")
245
+
246
+ # 执行回调
247
+ if callback:
248
+ callback(feedback)
249
+
250
+ return feedback
251
+
252
+ except Exception as e:
253
+ error_msg = f"解析反馈失败: {str(e)}"
254
+ print(f"❌ {error_msg}")
255
+
256
+ # 执行回调(错误情况)
257
+ if callback:
258
+ callback({
259
+ 'id': command_id,
260
+ 'status': 'error',
261
+ 'result': error_msg,
262
+ 'timestamp': time.time()
263
+ })
264
+
265
+ return {
266
+ 'id': command_id,
267
+ 'status': 'error',
268
+ 'result': error_msg,
269
+ 'timestamp': time.time()
270
+ }
271
+
272
+ except Exception as e:
273
+ error_msg = f"执行代理命令失败: {str(e)}"
274
+ print(f"❌ {error_msg}")
275
+
276
+ # 执行回调(错误情况)
277
+ if callback:
278
+ callback({
279
+ 'id': command_id,
280
+ 'status': 'error',
281
+ 'result': error_msg,
282
+ 'timestamp': time.time()
283
+ })
284
+
285
+ return {
286
+ 'id': command_id,
287
+ 'status': 'error',
288
+ 'result': error_msg,
289
+ 'timestamp': time.time()
290
+ }
291
+
292
+ async def send_command(self, command: str,
293
+ target_server: str,
294
+ callback: Optional[Callable] = None) -> Dict[str, Any]:
295
+ """
296
+ 发送命令到中转服务器(带消息队列)
297
+
298
+ Args:
299
+ command: 要执行的命令
300
+ target_server: 目标服务器标识
301
+ callback: 回调函数(可选)
302
+
303
+ Returns:
304
+ 命令提交结果
305
+ """
306
+ # 生成命令ID
307
+ async with self._lock:
308
+ command_id = f"cmd_{self.command_counter}_{int(time.time())}"
309
+ self.command_counter += 1
310
+
311
+ print(f"📡 发送命令到中转服务器: {command_id}")
312
+
313
+ # 构建代理命令
314
+ proxy_command = f"python -c \""
315
+ proxy_command += "import json\n"
316
+ proxy_command += "import subprocess\n"
317
+ proxy_command += "import time\n"
318
+ proxy_command += "\n"
319
+ proxy_command += f"# 命令信息\n"
320
+ proxy_command += f"command_id = '{command_id}'\n"
321
+ proxy_command += f"command = '{command}'\n"
322
+ proxy_command += f"target_server = '{target_server}'\n"
323
+ proxy_command += f"timestamp = {time.time()}\n"
324
+ proxy_command += "\n"
325
+ proxy_command += "# 无状态邮局模式处理\n"
326
+ proxy_command += "print('🔄 中转服务器接收命令:', command_id)\n"
327
+ proxy_command += "print('🚀 向目标服务器推送指令...')\n"
328
+ proxy_command += "\n"
329
+ proxy_command += "# 执行命令(模拟目标服务器执行)\n"
330
+ proxy_command += "try:\n"
331
+ proxy_command += " result = subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT, text=True)\n"
332
+ proxy_command += " status = 'success'\n"
333
+ proxy_command += " print('✅ 目标服务器执行成功')\n"
334
+ proxy_command += "except Exception as e:\n"
335
+ proxy_command += " result = str(e)\n"
336
+ proxy_command += " status = 'error'\n"
337
+ proxy_command += " print('❌ 目标服务器执行失败:', result)\n"
338
+ proxy_command += "\n"
339
+ proxy_command += "# 构建反馈信息\n"
340
+ proxy_command += "feedback = json.dumps({\n"
341
+ proxy_command += " 'id': command_id,\n"
342
+ proxy_command += " 'status': status,\n"
343
+ proxy_command += " 'result': result,\n"
344
+ proxy_command += " 'timestamp': time.time()\n"
345
+ proxy_command += "})\n"
346
+ proxy_command += "print('📨 反馈信息:', feedback)\n"
347
+ proxy_command += "\"""
348
+
349
+ # 创建队列项
350
+ queue_item = {
351
+ 'id': command_id,
352
+ 'command': command,
353
+ 'target_server': target_server,
354
+ 'proxy_command': proxy_command,
355
+ 'callback': callback,
356
+ 'timestamp': time.time()
357
+ }
358
+
359
+ # 入队
360
+ item_id = await self.message_queue.enqueue(queue_item)
361
+ print(f"📋 命令已加入队列: {item_id}")
362
+
363
+ # 获取队列状态
364
+ queue_status = self.message_queue.get_queue_status()
365
+ print(f"📊 当前队列状态: {queue_status}")
366
+
367
+ # 立即返回,不阻塞
368
+ return {
369
+ 'id': command_id,
370
+ 'status': 'queued',
371
+ 'message': '命令已加入队列',
372
+ 'sequence': queue_item['sequence'],
373
+ 'queue_status': queue_status,
374
+ 'timestamp': time.time()
375
+ }
376
+
377
+ async def send_batch_commands(self, commands: list,
378
+ target_server: str,
379
+ concurrency: int = 5) -> List[Dict[str, Any]]:
380
+ """
381
+ 批量发送命令到中转服务器(带消息队列)
382
+
383
+ Args:
384
+ commands: 命令列表
385
+ target_server: 目标服务器标识
386
+ concurrency: 并发数
387
+
388
+ Returns:
389
+ 命令提交结果列表
390
+ """
391
+ results = []
392
+
393
+ for cmd in commands:
394
+ result = await self.send_command(cmd, target_server)
395
+ results.append(result)
396
+
397
+ return results
398
+
399
+ def get_queue_status(self) -> Dict[str, Any]:
400
+ """
401
+ 获取队列状态
402
+
403
+ Returns:
404
+ 队列状态
405
+ """
406
+ return self.message_queue.get_queue_status()
407
+
408
+ async def shutdown(self):
409
+ """
410
+ 关闭管理器
411
+ """
412
+ # 取消队列处理器
413
+ if self._queue_processor_task:
414
+ self._queue_processor_task.cancel()
415
+ try:
416
+ await self._queue_processor_task
417
+ except asyncio.CancelledError:
418
+ pass
419
+
420
+ print("✅ 异步代理管理器已关闭")
421
+
422
+
423
+
424
+
425
+ class ProxyServerManager:
426
+ """
427
+ 代理服务器管理器
428
+ 管理中转服务器和目标服务器之间的通讯
429
+ """
430
+
431
+ def __init__(self, proxy_host: str,
432
+ proxy_port: int,
433
+ proxy_password: str):
434
+ """
435
+ 初始化代理服务器管理器
436
+
437
+ Args:
438
+ proxy_host: 中转服务器主机
439
+ proxy_port: 中转服务器端口
440
+ proxy_password: 中转服务器密码
441
+ """
442
+ self.proxy_host = proxy_host
443
+ self.proxy_port = proxy_port
444
+ self.proxy_password = proxy_password
445
+ self.target_servers = {} # 目标服务器配置
446
+
447
+ def add_target_server(self, server_id: str,
448
+ server_host: str,
449
+ server_port: int,
450
+ server_password: str):
451
+ """
452
+ 添加目标服务器
453
+
454
+ Args:
455
+ server_id: 服务器标识
456
+ server_host: 服务器主机
457
+ server_port: 服务器端口
458
+ server_password: 服务器密码
459
+ """
460
+ self.target_servers[server_id] = {
461
+ 'host': server_host,
462
+ 'port': server_port,
463
+ 'password': server_password
464
+ }
465
+
466
+ def get_target_server(self, server_id: str) -> Optional[Dict[str, Any]]:
467
+ """
468
+ 获取目标服务器配置
469
+
470
+ Args:
471
+ server_id: 服务器标识
472
+
473
+ Returns:
474
+ 服务器配置
475
+ """
476
+ return self.target_servers.get(server_id)
477
+
478
+ def remove_target_server(self, server_id: str):
479
+ """
480
+ 移除目标服务器
481
+
482
+ Args:
483
+ server_id: 服务器标识
484
+ """
485
+ if server_id in self.target_servers:
486
+ del self.target_servers[server_id]
487
+
488
+
489
+ async def main():
490
+ """
491
+ 示例代码 - 带消息队列
492
+ """
493
+ from rcoder.core_optimized import get_remote_host
494
+
495
+ # 创建中转服务器连接
496
+ proxy_remote = get_remote_host(
497
+ host='proxy.example.com',
498
+ port=443,
499
+ password='proxy_password'
500
+ )
501
+
502
+ # 创建异步代理管理器
503
+ proxy_manager = AsyncProxyManager(proxy_remote)
504
+ print("✅ 异步代理管理器创建成功!")
505
+
506
+ # 定义回调函数
507
+ def callback(result):
508
+ print(f"🔔 回调通知 - 命令 {result['id']} 执行完成: {result['status']}")
509
+ print(f" 结果: {result['result'][:100]}{'...' if len(result['result']) > 100 else ''}")
510
+
511
+ # 发送测试命令(带消息队列)
512
+ print(f"\n📡 发送测试命令...")
513
+ result = await proxy_manager.send_command(
514
+ command='ls -la',
515
+ target_server='target1',
516
+ callback=callback
517
+ )
518
+
519
+ print(f"📋 命令提交结果: {result}")
520
+ print("✅ 命令已加入队列,不阻塞后续操作")
521
+
522
+ # 批量发送命令
523
+ commands = [
524
+ 'ls -la',
525
+ 'uptime',
526
+ 'free -h',
527
+ 'df -h',
528
+ 'ps aux | head -10'
529
+ ]
530
+
531
+ print(f"\n📡 批量发送命令...")
532
+ batch_results = await proxy_manager.send_batch_commands(
533
+ commands=commands,
534
+ target_server='target1',
535
+ concurrency=2
536
+ )
537
+
538
+ print(f"📋 批量命令提交结果:")
539
+ for i, batch_result in enumerate(batch_results):
540
+ print(f"命令 {i+1}: {batch_result}")
541
+
542
+ # 定期检查队列状态
543
+ print("\n⏳ 定期检查队列状态...")
544
+ for i in range(5):
545
+ queue_status = proxy_manager.get_queue_status()
546
+ print(f"📊 队列状态 ({i+1}/5): {queue_status}")
547
+ await asyncio.sleep(2)
548
+
549
+ # 关闭管理器
550
+ print("\n🔄 关闭异步代理管理器...")
551
+ await proxy_manager.shutdown()
552
+ print("✅ 异步代理管理器已关闭")
553
+
554
+
555
+ if __name__ == "__main__":
556
+ asyncio.run(main())