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
rcoder/core_optimized.py
ADDED
|
@@ -0,0 +1,958 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Rcoder核心模块(优化版本)
|
|
4
|
+
针对低带宽场景和异步操作进行了优化
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import ssl
|
|
8
|
+
import socket
|
|
9
|
+
import json
|
|
10
|
+
import time
|
|
11
|
+
import asyncio
|
|
12
|
+
import hashlib
|
|
13
|
+
import threading
|
|
14
|
+
import queue
|
|
15
|
+
import gzip
|
|
16
|
+
import zlib
|
|
17
|
+
from typing import Dict, Any, Optional, List, Tuple, Callable
|
|
18
|
+
from dataclasses import dataclass
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class CommandResult:
|
|
22
|
+
"""命令执行结果"""
|
|
23
|
+
stdout: str
|
|
24
|
+
stderr: str
|
|
25
|
+
returncode: int
|
|
26
|
+
execution_time: float
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class BatchResult:
|
|
30
|
+
"""批量命令执行结果"""
|
|
31
|
+
command: str
|
|
32
|
+
results: Dict[str, CommandResult]
|
|
33
|
+
success_count: int
|
|
34
|
+
failure_count: int
|
|
35
|
+
total_time: float
|
|
36
|
+
|
|
37
|
+
class RcoderCore:
|
|
38
|
+
"""
|
|
39
|
+
Rcoder核心类(优化版本)
|
|
40
|
+
针对低带宽场景和异步操作进行了优化
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
def __init__(self, host: str = '192.168.1.8', port: int = 443, use_https_disguise: bool = True,
|
|
44
|
+
proxy_server: Optional[Tuple[str, int]] = None, enable_compression: bool = True,
|
|
45
|
+
enable_connection_pool: bool = True, connection_pool_size: int = 5, password: Optional[str] = None):
|
|
46
|
+
"""
|
|
47
|
+
初始化Rcoder核心
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
host: 服务器主机
|
|
51
|
+
port: 服务器端口 (默认443,支持HTTPS伪装)
|
|
52
|
+
use_https_disguise: 是否使用HTTPS伪装
|
|
53
|
+
proxy_server: 中转服务器 (host, port),如 ('1.2.3.4', 443)
|
|
54
|
+
enable_compression: 是否启用数据压缩
|
|
55
|
+
enable_connection_pool: 是否启用连接池
|
|
56
|
+
connection_pool_size: 连接池大小
|
|
57
|
+
password: 认证密码
|
|
58
|
+
"""
|
|
59
|
+
self.host = host
|
|
60
|
+
self.port = port
|
|
61
|
+
self.use_https_disguise = use_https_disguise
|
|
62
|
+
self.proxy_server = proxy_server
|
|
63
|
+
self.enable_compression = enable_compression
|
|
64
|
+
self.enable_connection_pool = enable_connection_pool
|
|
65
|
+
self.connection_pool_size = connection_pool_size
|
|
66
|
+
self.password = password
|
|
67
|
+
self.ssl_context = self._create_ssl_context()
|
|
68
|
+
self.token = None
|
|
69
|
+
self._monitoring_enabled = False
|
|
70
|
+
self._monitoring_thread = None
|
|
71
|
+
self._alert_queue = queue.Queue()
|
|
72
|
+
self._command_queue = queue.Queue()
|
|
73
|
+
self._results = {}
|
|
74
|
+
self._lock = threading.Lock()
|
|
75
|
+
self._session_id = hashlib.sha256(str(time.time()).encode()).hexdigest()
|
|
76
|
+
|
|
77
|
+
# 连接池相关
|
|
78
|
+
self._connection_pool = queue.Queue(maxsize=connection_pool_size)
|
|
79
|
+
self._pool_lock = threading.Lock()
|
|
80
|
+
self._connection_expiry = 300 # 连接过期时间(秒)
|
|
81
|
+
self._connection_times = {}
|
|
82
|
+
|
|
83
|
+
# 缓存相关
|
|
84
|
+
self._command_cache = {}
|
|
85
|
+
self._cache_expiry = 60 # 缓存过期时间(秒)
|
|
86
|
+
|
|
87
|
+
# 网络优化参数
|
|
88
|
+
self._timeout = 60
|
|
89
|
+
self._retry_delay = 0.5 # 初始重试延迟
|
|
90
|
+
self._max_retry_delay = 5 # 最大重试延迟
|
|
91
|
+
|
|
92
|
+
# 新增策略参数
|
|
93
|
+
self.enable_minimal_payload = False # 是否启用最小化负载
|
|
94
|
+
self.enable_exponential_backoff = False # 是否启用指数退避
|
|
95
|
+
self.enable_breakpoint_resume = False # 是否启用断点续传
|
|
96
|
+
|
|
97
|
+
config_info = f"{host}:{port} (HTTPS伪装: {'启用' if use_https_disguise else '禁用'})"
|
|
98
|
+
if proxy_server:
|
|
99
|
+
config_info += f" (中转服务器: {proxy_server[0]}:{proxy_server[1]})"
|
|
100
|
+
|
|
101
|
+
# 优化功能提示
|
|
102
|
+
optimizations = []
|
|
103
|
+
if enable_compression:
|
|
104
|
+
optimizations.append("数据压缩")
|
|
105
|
+
if enable_connection_pool:
|
|
106
|
+
optimizations.append("连接池")
|
|
107
|
+
if optimizations:
|
|
108
|
+
config_info += f" (优化: {', '.join(optimizations)})"
|
|
109
|
+
|
|
110
|
+
print(f"✅ Rcoder初始化完成 (会话ID: {self._session_id[:8]})]")
|
|
111
|
+
print(f"📡 连接配置: {config_info}")
|
|
112
|
+
|
|
113
|
+
def _create_ssl_context(self) -> ssl.SSLContext:
|
|
114
|
+
"""创建SSL上下文,增强HTTPS伪装"""
|
|
115
|
+
context = ssl.create_default_context()
|
|
116
|
+
|
|
117
|
+
# 增强HTTPS伪装
|
|
118
|
+
if self.use_https_disguise:
|
|
119
|
+
# 模拟标准HTTPS客户端行为
|
|
120
|
+
context.minimum_version = ssl.TLSVersion.TLSv1_2
|
|
121
|
+
context.maximum_version = ssl.TLSVersion.TLSv1_3
|
|
122
|
+
|
|
123
|
+
# 禁用主机名检查以支持自定义端口
|
|
124
|
+
context.check_hostname = False
|
|
125
|
+
context.verify_mode = ssl.CERT_NONE
|
|
126
|
+
|
|
127
|
+
# 模拟常见浏览器的密码套件偏好
|
|
128
|
+
context.set_ciphers('ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:AES128-GCM-SHA256:AES256-GCM-SHA384')
|
|
129
|
+
else:
|
|
130
|
+
# 标准模式
|
|
131
|
+
context.check_hostname = False
|
|
132
|
+
context.verify_mode = ssl.CERT_NONE
|
|
133
|
+
|
|
134
|
+
return context
|
|
135
|
+
|
|
136
|
+
def _get_connection(self):
|
|
137
|
+
"""从连接池获取连接"""
|
|
138
|
+
if not self.enable_connection_pool:
|
|
139
|
+
return self._create_connection()
|
|
140
|
+
|
|
141
|
+
with self._pool_lock:
|
|
142
|
+
# 清理过期连接
|
|
143
|
+
current_time = time.time()
|
|
144
|
+
valid_connections = []
|
|
145
|
+
while not self._connection_pool.empty():
|
|
146
|
+
conn = self._connection_pool.get()
|
|
147
|
+
conn_id = id(conn)
|
|
148
|
+
if current_time - self._connection_times.get(conn_id, 0) < self._connection_expiry:
|
|
149
|
+
try:
|
|
150
|
+
# 测试连接是否有效
|
|
151
|
+
conn.send(b'')
|
|
152
|
+
valid_connections.append(conn)
|
|
153
|
+
except:
|
|
154
|
+
pass
|
|
155
|
+
|
|
156
|
+
# 将有效连接放回池
|
|
157
|
+
for conn in valid_connections:
|
|
158
|
+
if not self._connection_pool.full():
|
|
159
|
+
self._connection_pool.put(conn)
|
|
160
|
+
|
|
161
|
+
# 获取连接
|
|
162
|
+
if not self._connection_pool.empty():
|
|
163
|
+
conn = self._connection_pool.get()
|
|
164
|
+
self._connection_times[id(conn)] = current_time
|
|
165
|
+
return conn
|
|
166
|
+
|
|
167
|
+
# 没有可用连接,创建新连接
|
|
168
|
+
return self._create_connection()
|
|
169
|
+
|
|
170
|
+
def _create_connection(self):
|
|
171
|
+
"""创建新连接"""
|
|
172
|
+
# 建立TCP连接(支持中转服务器)
|
|
173
|
+
if self.proxy_server:
|
|
174
|
+
sock = socket.create_connection((self.proxy_server[0], self.proxy_server[1]), timeout=self._timeout)
|
|
175
|
+
|
|
176
|
+
# 发送代理连接请求(简化版,减少数据传输)
|
|
177
|
+
proxy_connect = f"CONNECT {self.host}:{self.port} HTTP/1.1\r\n"
|
|
178
|
+
proxy_connect += f"Host: {self.host}:{self.port}\r\n"
|
|
179
|
+
proxy_connect += "Connection: Keep-Alive\r\n"
|
|
180
|
+
proxy_connect += "\r\n"
|
|
181
|
+
|
|
182
|
+
sock.send(proxy_connect.encode())
|
|
183
|
+
# 读取代理响应(丢弃)
|
|
184
|
+
sock.recv(4096)
|
|
185
|
+
else:
|
|
186
|
+
# 直接连接
|
|
187
|
+
sock = socket.create_connection((self.host, self.port), timeout=self._timeout)
|
|
188
|
+
|
|
189
|
+
# 增强HTTPS伪装:添加HTTP请求头模拟(简化版)
|
|
190
|
+
if self.use_https_disguise:
|
|
191
|
+
# 简化的HTTP伪装,减少数据传输
|
|
192
|
+
http_request = "GET / HTTP/1.1\r\n"
|
|
193
|
+
http_request += f"Host: {self.host}:{self.port}\r\n"
|
|
194
|
+
http_request += "User-Agent: Mozilla/5.0\r\n"
|
|
195
|
+
http_request += "Connection: keep-alive\r\n"
|
|
196
|
+
http_request += "\r\n"
|
|
197
|
+
|
|
198
|
+
sock.send(http_request.encode())
|
|
199
|
+
# 读取HTTP响应(丢弃)
|
|
200
|
+
sock.recv(4096)
|
|
201
|
+
|
|
202
|
+
# 包装为TLS连接
|
|
203
|
+
server_hostname = f"{self.host}" if self.use_https_disguise else "rcoder"
|
|
204
|
+
tls_sock = self.ssl_context.wrap_socket(sock, server_hostname=server_hostname)
|
|
205
|
+
|
|
206
|
+
return tls_sock
|
|
207
|
+
|
|
208
|
+
def _return_connection(self, conn):
|
|
209
|
+
"""将连接放回连接池"""
|
|
210
|
+
if self.enable_connection_pool:
|
|
211
|
+
with self._pool_lock:
|
|
212
|
+
if not self._connection_pool.full():
|
|
213
|
+
try:
|
|
214
|
+
self._connection_pool.put(conn)
|
|
215
|
+
self._connection_times[id(conn)] = time.time()
|
|
216
|
+
return True
|
|
217
|
+
except:
|
|
218
|
+
pass
|
|
219
|
+
|
|
220
|
+
# 无法放回池,关闭连接
|
|
221
|
+
try:
|
|
222
|
+
conn.close()
|
|
223
|
+
except:
|
|
224
|
+
pass
|
|
225
|
+
return False
|
|
226
|
+
|
|
227
|
+
def _compress_data(self, data):
|
|
228
|
+
"""压缩数据"""
|
|
229
|
+
if not self.enable_compression:
|
|
230
|
+
return data
|
|
231
|
+
|
|
232
|
+
try:
|
|
233
|
+
compressed = gzip.compress(data)
|
|
234
|
+
# 只有当压缩后数据更小时才使用压缩
|
|
235
|
+
if len(compressed) < len(data):
|
|
236
|
+
return compressed
|
|
237
|
+
except:
|
|
238
|
+
pass
|
|
239
|
+
return data
|
|
240
|
+
|
|
241
|
+
def _decompress_data(self, data):
|
|
242
|
+
"""解压数据"""
|
|
243
|
+
if not self.enable_compression:
|
|
244
|
+
return data
|
|
245
|
+
|
|
246
|
+
try:
|
|
247
|
+
return gzip.decompress(data)
|
|
248
|
+
except:
|
|
249
|
+
return data
|
|
250
|
+
|
|
251
|
+
def _call(self, method: str, params: Dict[str, Any] = None,
|
|
252
|
+
retry_on_failure: bool = True, max_retries: int = 3) -> Dict[str, Any]:
|
|
253
|
+
"""执行JSON-RPC调用,优化低带宽场景
|
|
254
|
+
|
|
255
|
+
Args:
|
|
256
|
+
method: RPC方法名
|
|
257
|
+
params: RPC参数
|
|
258
|
+
retry_on_failure: 是否在失败时重试
|
|
259
|
+
max_retries: 最大重试次数
|
|
260
|
+
"""
|
|
261
|
+
retry_count = 0
|
|
262
|
+
current_delay = self._retry_delay
|
|
263
|
+
|
|
264
|
+
while retry_count <= max_retries:
|
|
265
|
+
conn = None
|
|
266
|
+
try:
|
|
267
|
+
# 获取连接
|
|
268
|
+
conn = self._get_connection()
|
|
269
|
+
|
|
270
|
+
# 构建请求
|
|
271
|
+
request = {
|
|
272
|
+
"jsonrpc": "2.0",
|
|
273
|
+
"id": int(time.time() * 1000),
|
|
274
|
+
"method": method,
|
|
275
|
+
"params": params or {},
|
|
276
|
+
"sid": self._session_id[:8], # 简化的session_id
|
|
277
|
+
"ts": int(time.time())
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
# 添加认证信息
|
|
281
|
+
if self.password:
|
|
282
|
+
request['auth'] = {
|
|
283
|
+
'type': 'password',
|
|
284
|
+
'password': self.password
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
# 最小化负载
|
|
288
|
+
if self.enable_minimal_payload:
|
|
289
|
+
# 移除可选字段
|
|
290
|
+
if "params" in request and not request["params"]:
|
|
291
|
+
del request["params"]
|
|
292
|
+
|
|
293
|
+
# 序列化请求
|
|
294
|
+
request_data = json.dumps(request, separators=(',', ':')).encode()
|
|
295
|
+
|
|
296
|
+
# 压缩数据
|
|
297
|
+
if self.enable_compression:
|
|
298
|
+
compressed_data = self._compress_data(request_data)
|
|
299
|
+
# 添加压缩标记
|
|
300
|
+
if len(compressed_data) < len(request_data):
|
|
301
|
+
request_data = b'COMPRESSED:' + compressed_data
|
|
302
|
+
|
|
303
|
+
# 发送请求
|
|
304
|
+
conn.send(request_data + b"\n")
|
|
305
|
+
|
|
306
|
+
# 接收响应(优化:使用循环接收,处理大数据)
|
|
307
|
+
response_data = b''
|
|
308
|
+
while True:
|
|
309
|
+
chunk = conn.recv(8192) # 增大接收缓冲区
|
|
310
|
+
if not chunk:
|
|
311
|
+
break
|
|
312
|
+
response_data += chunk
|
|
313
|
+
# 如果收到完整的JSON响应,提前结束
|
|
314
|
+
if b'\n' in response_data:
|
|
315
|
+
break
|
|
316
|
+
|
|
317
|
+
# 处理压缩响应
|
|
318
|
+
if response_data.startswith(b'COMPRESSED:'):
|
|
319
|
+
response_data = self._decompress_data(response_data[10:])
|
|
320
|
+
|
|
321
|
+
if not response_data:
|
|
322
|
+
if retry_on_failure and retry_count < max_retries:
|
|
323
|
+
retry_count += 1
|
|
324
|
+
# 指数退避
|
|
325
|
+
if self.enable_exponential_backoff:
|
|
326
|
+
current_delay = min(current_delay * (2 ** retry_count), self._max_retry_delay * 2)
|
|
327
|
+
else:
|
|
328
|
+
current_delay = min(current_delay * 1.5, self._max_retry_delay)
|
|
329
|
+
time.sleep(current_delay)
|
|
330
|
+
continue
|
|
331
|
+
raise Exception("Empty response from server")
|
|
332
|
+
|
|
333
|
+
# 解析响应
|
|
334
|
+
response = json.loads(response_data)
|
|
335
|
+
|
|
336
|
+
# 检查认证错误
|
|
337
|
+
if 'error' in response:
|
|
338
|
+
error_msg = response['error'].get('message', str(response['error']))
|
|
339
|
+
if 'auth' in error_msg.lower() or 'password' in error_msg.lower() or 'login' in error_msg.lower():
|
|
340
|
+
raise Exception(f"认证失败: {error_msg}. 请检查用户名和密码是否正确。")
|
|
341
|
+
raise Exception(f"服务器错误: {error_msg}")
|
|
342
|
+
|
|
343
|
+
return response
|
|
344
|
+
|
|
345
|
+
except (socket.error, ConnectionResetError, ConnectionRefusedError) as e:
|
|
346
|
+
error_msg = str(e)
|
|
347
|
+
if 'Connection refused' in error_msg or '10061' in error_msg:
|
|
348
|
+
if self.password:
|
|
349
|
+
raise Exception(f"连接失败: {error_msg}. 可能的原因: 服务器未运行、端口错误或认证失败。")
|
|
350
|
+
else:
|
|
351
|
+
raise Exception(f"连接失败: {error_msg}. 可能的原因: 服务器未运行或端口错误。")
|
|
352
|
+
|
|
353
|
+
if retry_on_failure and retry_count < max_retries:
|
|
354
|
+
retry_count += 1
|
|
355
|
+
# 指数退避
|
|
356
|
+
if self.enable_exponential_backoff:
|
|
357
|
+
current_delay = min(current_delay * (2 ** retry_count), self._max_retry_delay * 2)
|
|
358
|
+
else:
|
|
359
|
+
current_delay = min(current_delay * 1.5, self._max_retry_delay)
|
|
360
|
+
time.sleep(current_delay)
|
|
361
|
+
continue
|
|
362
|
+
raise
|
|
363
|
+
except json.JSONDecodeError as e:
|
|
364
|
+
if retry_on_failure and retry_count < max_retries:
|
|
365
|
+
retry_count += 1
|
|
366
|
+
# 指数退避
|
|
367
|
+
if self.enable_exponential_backoff:
|
|
368
|
+
current_delay = min(current_delay * (2 ** retry_count), self._max_retry_delay * 2)
|
|
369
|
+
else:
|
|
370
|
+
current_delay = min(current_delay * 1.5, self._max_retry_delay)
|
|
371
|
+
time.sleep(current_delay)
|
|
372
|
+
continue
|
|
373
|
+
raise
|
|
374
|
+
except Exception as e:
|
|
375
|
+
if retry_on_failure and retry_count < max_retries:
|
|
376
|
+
# 跳过认证错误的重试
|
|
377
|
+
if '认证失败' in str(e):
|
|
378
|
+
raise
|
|
379
|
+
|
|
380
|
+
retry_count += 1
|
|
381
|
+
# 指数退避
|
|
382
|
+
if self.enable_exponential_backoff:
|
|
383
|
+
current_delay = min(current_delay * (2 ** retry_count), self._max_retry_delay * 2)
|
|
384
|
+
else:
|
|
385
|
+
current_delay = min(current_delay * 1.5, self._max_retry_delay)
|
|
386
|
+
time.sleep(current_delay)
|
|
387
|
+
continue
|
|
388
|
+
raise
|
|
389
|
+
finally:
|
|
390
|
+
if conn:
|
|
391
|
+
self._return_connection(conn)
|
|
392
|
+
|
|
393
|
+
def _get_cache_key(self, method, params):
|
|
394
|
+
"""生成缓存键"""
|
|
395
|
+
return hashlib.md5(f"{method}:{json.dumps(params, sort_keys=True)}".encode()).hexdigest()
|
|
396
|
+
|
|
397
|
+
def _get_cached_result(self, method, params):
|
|
398
|
+
"""获取缓存的结果"""
|
|
399
|
+
cache_key = self._get_cache_key(method, params)
|
|
400
|
+
if cache_key in self._command_cache:
|
|
401
|
+
cached = self._command_cache[cache_key]
|
|
402
|
+
if time.time() - cached['timestamp'] < self._cache_expiry:
|
|
403
|
+
return cached['result']
|
|
404
|
+
# 缓存过期,删除
|
|
405
|
+
del self._command_cache[cache_key]
|
|
406
|
+
return None
|
|
407
|
+
|
|
408
|
+
def _set_cached_result(self, method, params, result):
|
|
409
|
+
"""设置缓存的结果"""
|
|
410
|
+
cache_key = self._get_cache_key(method, params)
|
|
411
|
+
self._command_cache[cache_key] = {
|
|
412
|
+
'result': result,
|
|
413
|
+
'timestamp': time.time()
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
# 清理过期缓存
|
|
417
|
+
current_time = time.time()
|
|
418
|
+
expired_keys = [k for k, v in self._command_cache.items()
|
|
419
|
+
if current_time - v['timestamp'] >= self._cache_expiry]
|
|
420
|
+
for key in expired_keys:
|
|
421
|
+
del self._command_cache[key]
|
|
422
|
+
|
|
423
|
+
def execute(self, server: str, command: str, timeout: int = 60,
|
|
424
|
+
wait_for_restart: bool = False, restart_check_interval: int = 2,
|
|
425
|
+
restart_max_wait: int = 60, use_cache: bool = True) -> str:
|
|
426
|
+
"""执行命令,优化低带宽场景
|
|
427
|
+
|
|
428
|
+
Args:
|
|
429
|
+
server: 服务器名称
|
|
430
|
+
command: 命令
|
|
431
|
+
timeout: 超时时间
|
|
432
|
+
wait_for_restart: 是否等待重启完成
|
|
433
|
+
restart_check_interval: 重启检查间隔
|
|
434
|
+
restart_max_wait: 最大重启等待时间
|
|
435
|
+
use_cache: 是否使用缓存
|
|
436
|
+
"""
|
|
437
|
+
# 检查缓存
|
|
438
|
+
if use_cache:
|
|
439
|
+
cache_key = f"execute:{server}:{command}"
|
|
440
|
+
if cache_key in self._command_cache:
|
|
441
|
+
cached = self._command_cache[cache_key]
|
|
442
|
+
if time.time() - cached['timestamp'] < self._cache_expiry:
|
|
443
|
+
return cached['result']
|
|
444
|
+
|
|
445
|
+
# 检查是否为重启命令
|
|
446
|
+
is_restart_command = any(keyword in command.lower() for keyword in [
|
|
447
|
+
'restart', 'systemctl restart', 'service restart', 'reboot'
|
|
448
|
+
])
|
|
449
|
+
|
|
450
|
+
if is_restart_command and wait_for_restart:
|
|
451
|
+
print(f"执行重启命令并等待完成...")
|
|
452
|
+
print(f"命令: {command}")
|
|
453
|
+
print(f"最大等待时间: {restart_max_wait}秒")
|
|
454
|
+
|
|
455
|
+
try:
|
|
456
|
+
# 执行重启命令
|
|
457
|
+
result = self._call("tools/call", {
|
|
458
|
+
"name": "ssh_exec",
|
|
459
|
+
"arguments": {"name": server, "command": command, "timeout": timeout}
|
|
460
|
+
})
|
|
461
|
+
|
|
462
|
+
if "result" in result:
|
|
463
|
+
data = json.loads(result["result"]["content"][0]["text"])
|
|
464
|
+
print(f"重启命令执行结果: {data.get('stdout', '').strip() or data.get('stderr', '').strip()}")
|
|
465
|
+
except Exception as e:
|
|
466
|
+
print(f"重启命令执行异常: {e}")
|
|
467
|
+
# 继续等待,因为重启命令可能已经开始执行
|
|
468
|
+
|
|
469
|
+
# 等待重启完成
|
|
470
|
+
start_time = time.time()
|
|
471
|
+
elapsed = 0
|
|
472
|
+
|
|
473
|
+
print("等待服务重启...")
|
|
474
|
+
while elapsed < restart_max_wait:
|
|
475
|
+
time.sleep(restart_check_interval)
|
|
476
|
+
elapsed = time.time() - start_time
|
|
477
|
+
|
|
478
|
+
try:
|
|
479
|
+
# 尝试重新连接并检查服务是否可用(使用更简单的命令)
|
|
480
|
+
test_result = self._call(
|
|
481
|
+
"tools/call",
|
|
482
|
+
{
|
|
483
|
+
"name": "ssh_exec",
|
|
484
|
+
"arguments": {"name": server, "command": "echo 1", "timeout": 5}
|
|
485
|
+
},
|
|
486
|
+
retry_on_failure=True,
|
|
487
|
+
max_retries=1 # 减少重试次数,加快检测
|
|
488
|
+
)
|
|
489
|
+
|
|
490
|
+
if "result" in test_result:
|
|
491
|
+
print(f"✅ 服务已重启完成 (耗时: {elapsed:.1f}秒)")
|
|
492
|
+
result = f"重启完成 (耗时: {elapsed:.1f}秒)"
|
|
493
|
+
# 缓存结果
|
|
494
|
+
if use_cache:
|
|
495
|
+
self._command_cache[cache_key] = {
|
|
496
|
+
'result': result,
|
|
497
|
+
'timestamp': time.time()
|
|
498
|
+
}
|
|
499
|
+
return result
|
|
500
|
+
|
|
501
|
+
except (socket.error, ConnectionResetError, ConnectionRefusedError):
|
|
502
|
+
# 重启过程中的连接错误是预期的
|
|
503
|
+
print(f" ⏳ 服务正在重启中... ({elapsed:.1f}秒)")
|
|
504
|
+
except Exception:
|
|
505
|
+
# 其他错误
|
|
506
|
+
print(f" ⏳ 等待服务恢复... ({elapsed:.1f}秒)")
|
|
507
|
+
|
|
508
|
+
print(f"⏳ 等待中... ({elapsed:.1f}/{restart_max_wait}秒)")
|
|
509
|
+
|
|
510
|
+
print(f"❌ 重启等待超时 ({restart_max_wait}秒)")
|
|
511
|
+
result = f"重启命令已执行,但等待超时 ({restart_max_wait}秒)"
|
|
512
|
+
# 缓存结果
|
|
513
|
+
if use_cache:
|
|
514
|
+
self._command_cache[cache_key] = {
|
|
515
|
+
'result': result,
|
|
516
|
+
'timestamp': time.time()
|
|
517
|
+
}
|
|
518
|
+
return result
|
|
519
|
+
else:
|
|
520
|
+
# 正常命令执行
|
|
521
|
+
start_time = time.time()
|
|
522
|
+
result = self._call("tools/call", {
|
|
523
|
+
"name": "ssh_exec",
|
|
524
|
+
"arguments": {"name": server, "command": command, "timeout": timeout}
|
|
525
|
+
})
|
|
526
|
+
execution_time = time.time() - start_time
|
|
527
|
+
|
|
528
|
+
if "result" in result:
|
|
529
|
+
data = json.loads(result["result"]["content"][0]["text"])
|
|
530
|
+
output = data.get("stdout", "") or data.get("stderr", "") or data.get("error", "")
|
|
531
|
+
# 缓存结果
|
|
532
|
+
if use_cache:
|
|
533
|
+
self._command_cache[cache_key] = {
|
|
534
|
+
'result': output,
|
|
535
|
+
'timestamp': time.time()
|
|
536
|
+
}
|
|
537
|
+
return output
|
|
538
|
+
|
|
539
|
+
result_str = str(result)
|
|
540
|
+
# 缓存结果
|
|
541
|
+
if use_cache:
|
|
542
|
+
self._command_cache[cache_key] = {
|
|
543
|
+
'result': result_str,
|
|
544
|
+
'timestamp': time.time()
|
|
545
|
+
}
|
|
546
|
+
return result_str
|
|
547
|
+
|
|
548
|
+
async def execute_async(self, server: str, command: str, timeout: int = 60, use_cache: bool = True) -> str:
|
|
549
|
+
"""异步执行命令,优化低带宽场景"""
|
|
550
|
+
# 使用asyncio的事件循环,优化异步性能
|
|
551
|
+
loop = asyncio.get_event_loop()
|
|
552
|
+
return await loop.run_in_executor(
|
|
553
|
+
None,
|
|
554
|
+
self.execute,
|
|
555
|
+
server,
|
|
556
|
+
command,
|
|
557
|
+
timeout,
|
|
558
|
+
False,
|
|
559
|
+
2,
|
|
560
|
+
60,
|
|
561
|
+
use_cache
|
|
562
|
+
)
|
|
563
|
+
|
|
564
|
+
def execute_batch(self, server: str, commands: List[str], timeout: int = 60,
|
|
565
|
+
use_cache: bool = True, parallel: bool = False) -> Dict[str, str]:
|
|
566
|
+
"""批量执行命令,优化低带宽场景
|
|
567
|
+
|
|
568
|
+
Args:
|
|
569
|
+
server: 服务器名称
|
|
570
|
+
commands: 命令列表
|
|
571
|
+
timeout: 超时时间
|
|
572
|
+
use_cache: 是否使用缓存
|
|
573
|
+
parallel: 是否并行执行
|
|
574
|
+
"""
|
|
575
|
+
results = {}
|
|
576
|
+
|
|
577
|
+
# 检查缓存
|
|
578
|
+
cached_commands = []
|
|
579
|
+
for command in commands:
|
|
580
|
+
cache_key = f"execute:{server}:{command}"
|
|
581
|
+
if use_cache and cache_key in self._command_cache:
|
|
582
|
+
cached = self._command_cache[cache_key]
|
|
583
|
+
if time.time() - cached['timestamp'] < self._cache_expiry:
|
|
584
|
+
results[command] = cached['result']
|
|
585
|
+
cached_commands.append(command)
|
|
586
|
+
|
|
587
|
+
# 执行未缓存的命令
|
|
588
|
+
uncached_commands = [cmd for cmd in commands if cmd not in cached_commands]
|
|
589
|
+
|
|
590
|
+
if parallel and uncached_commands:
|
|
591
|
+
# 并行执行
|
|
592
|
+
import concurrent.futures
|
|
593
|
+
with concurrent.futures.ThreadPoolExecutor(max_workers=min(5, len(uncached_commands))) as executor:
|
|
594
|
+
future_to_command = {
|
|
595
|
+
executor.submit(self.execute, server, cmd, timeout, False, 2, 60, use_cache): cmd
|
|
596
|
+
for cmd in uncached_commands
|
|
597
|
+
}
|
|
598
|
+
for future in concurrent.futures.as_completed(future_to_command):
|
|
599
|
+
cmd = future_to_command[future]
|
|
600
|
+
try:
|
|
601
|
+
results[cmd] = future.result()
|
|
602
|
+
except Exception as e:
|
|
603
|
+
results[cmd] = f"Error: {e}"
|
|
604
|
+
else:
|
|
605
|
+
# 串行执行
|
|
606
|
+
for command in uncached_commands:
|
|
607
|
+
try:
|
|
608
|
+
result = self.execute(server, command, timeout=timeout, use_cache=use_cache)
|
|
609
|
+
results[command] = result
|
|
610
|
+
except Exception as e:
|
|
611
|
+
results[command] = f"Error: {e}"
|
|
612
|
+
|
|
613
|
+
return results
|
|
614
|
+
|
|
615
|
+
async def execute_batch_async(self, server: str, commands: List[str], timeout: int = 60,
|
|
616
|
+
use_cache: bool = True) -> Dict[str, str]:
|
|
617
|
+
"""异步批量执行命令,优化低带宽场景"""
|
|
618
|
+
# 优化:先检查缓存
|
|
619
|
+
cached_results = {}
|
|
620
|
+
uncached_commands = []
|
|
621
|
+
|
|
622
|
+
for command in commands:
|
|
623
|
+
cache_key = f"execute:{server}:{command}"
|
|
624
|
+
if use_cache and cache_key in self._command_cache:
|
|
625
|
+
cached = self._command_cache[cache_key]
|
|
626
|
+
if time.time() - cached['timestamp'] < self._cache_expiry:
|
|
627
|
+
cached_results[command] = cached['result']
|
|
628
|
+
continue
|
|
629
|
+
uncached_commands.append(command)
|
|
630
|
+
|
|
631
|
+
# 只对未缓存的命令执行异步操作
|
|
632
|
+
if not uncached_commands:
|
|
633
|
+
return cached_results
|
|
634
|
+
|
|
635
|
+
# 异步执行
|
|
636
|
+
tasks = []
|
|
637
|
+
for command in uncached_commands:
|
|
638
|
+
task = self.execute_async(server, command, timeout, use_cache)
|
|
639
|
+
tasks.append(task)
|
|
640
|
+
|
|
641
|
+
uncached_results = await asyncio.gather(*tasks)
|
|
642
|
+
uncached_dict = dict(zip(uncached_commands, uncached_results))
|
|
643
|
+
|
|
644
|
+
# 合并结果
|
|
645
|
+
cached_results.update(uncached_dict)
|
|
646
|
+
return cached_results
|
|
647
|
+
|
|
648
|
+
def list_connections(self) -> Dict[str, Any]:
|
|
649
|
+
"""列出SSH连接"""
|
|
650
|
+
# 检查缓存
|
|
651
|
+
cache_key = "list_connections"
|
|
652
|
+
if cache_key in self._command_cache:
|
|
653
|
+
cached = self._command_cache[cache_key]
|
|
654
|
+
if time.time() - cached['timestamp'] < self._cache_expiry:
|
|
655
|
+
return cached['result']
|
|
656
|
+
|
|
657
|
+
result = self._call("tools/list")
|
|
658
|
+
|
|
659
|
+
# 缓存结果
|
|
660
|
+
self._command_cache[cache_key] = {
|
|
661
|
+
'result': result,
|
|
662
|
+
'timestamp': time.time()
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
return result
|
|
666
|
+
|
|
667
|
+
def connect(self, server: str) -> Dict[str, Any]:
|
|
668
|
+
"""连接到SSH服务器"""
|
|
669
|
+
result = self._call("tools/call", {
|
|
670
|
+
"name": "ssh_connect",
|
|
671
|
+
"arguments": {"name": server}
|
|
672
|
+
})
|
|
673
|
+
return result
|
|
674
|
+
|
|
675
|
+
def disconnect(self, server: str) -> Dict[str, Any]:
|
|
676
|
+
"""断开SSH连接"""
|
|
677
|
+
result = self._call("tools/call", {
|
|
678
|
+
"name": "ssh_disconnect",
|
|
679
|
+
"arguments": {"name": server}
|
|
680
|
+
})
|
|
681
|
+
return result
|
|
682
|
+
|
|
683
|
+
def start_monitoring(self, interval: int = 30, lightweight: bool = True):
|
|
684
|
+
"""启动监控,优化低带宽场景
|
|
685
|
+
|
|
686
|
+
Args:
|
|
687
|
+
interval: 监控间隔(秒)
|
|
688
|
+
lightweight: 是否使用轻量级监控
|
|
689
|
+
"""
|
|
690
|
+
def monitor():
|
|
691
|
+
while self._monitoring_enabled:
|
|
692
|
+
try:
|
|
693
|
+
if lightweight:
|
|
694
|
+
# 轻量级监控,减少网络请求
|
|
695
|
+
status = self.execute('local', 'uptime')
|
|
696
|
+
print(f"[监控] 服务器状态: {status.strip()}")
|
|
697
|
+
else:
|
|
698
|
+
# 完整监控
|
|
699
|
+
# 检查服务器状态
|
|
700
|
+
status = self.execute('local', 'uptime')
|
|
701
|
+
print(f"[监控] 服务器状态: {status.strip()}")
|
|
702
|
+
|
|
703
|
+
# 检查内存使用
|
|
704
|
+
memory = self.execute('local', 'free -h')
|
|
705
|
+
print(f"[监控] 内存使用:\n{memory.strip()}")
|
|
706
|
+
|
|
707
|
+
# 检查磁盘使用
|
|
708
|
+
disk = self.execute('local', 'df -h')
|
|
709
|
+
print(f"[监控] 磁盘使用:\n{disk.strip()}")
|
|
710
|
+
|
|
711
|
+
except Exception as e:
|
|
712
|
+
print(f"[监控] 错误: {e}")
|
|
713
|
+
|
|
714
|
+
time.sleep(interval)
|
|
715
|
+
|
|
716
|
+
self._monitoring_enabled = True
|
|
717
|
+
self._monitoring_thread = threading.Thread(target=monitor, daemon=True)
|
|
718
|
+
self._monitoring_thread.start()
|
|
719
|
+
print("✅ 监控已启动")
|
|
720
|
+
|
|
721
|
+
def stop_monitoring(self):
|
|
722
|
+
"""停止监控"""
|
|
723
|
+
self._monitoring_enabled = False
|
|
724
|
+
if self._monitoring_thread:
|
|
725
|
+
self._monitoring_thread.join(timeout=5)
|
|
726
|
+
print("✅ 监控已停止")
|
|
727
|
+
|
|
728
|
+
def add_alert(self, condition: Callable[[], bool], message: str):
|
|
729
|
+
"""添加告警"""
|
|
730
|
+
if condition():
|
|
731
|
+
self._alert_queue.put(message)
|
|
732
|
+
print(f"⚠️ 告警: {message}")
|
|
733
|
+
|
|
734
|
+
def get_alerts(self) -> List[str]:
|
|
735
|
+
"""获取告警列表"""
|
|
736
|
+
alerts = []
|
|
737
|
+
while not self._alert_queue.empty():
|
|
738
|
+
alerts.append(self._alert_queue.get())
|
|
739
|
+
return alerts
|
|
740
|
+
|
|
741
|
+
def get_server_info(self) -> Dict[str, Any]:
|
|
742
|
+
"""获取服务器信息"""
|
|
743
|
+
# 检查缓存
|
|
744
|
+
cache_key = "server_info"
|
|
745
|
+
if cache_key in self._command_cache:
|
|
746
|
+
cached = self._command_cache[cache_key]
|
|
747
|
+
if time.time() - cached['timestamp'] < self._cache_expiry * 5: # 服务器信息缓存时间更长
|
|
748
|
+
return cached['result']
|
|
749
|
+
|
|
750
|
+
result = self._call("initialize")
|
|
751
|
+
|
|
752
|
+
# 缓存结果
|
|
753
|
+
self._command_cache[cache_key] = {
|
|
754
|
+
'result': result,
|
|
755
|
+
'timestamp': time.time()
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
return result
|
|
759
|
+
|
|
760
|
+
def get_available_tools(self) -> Dict[str, Any]:
|
|
761
|
+
"""获取可用工具"""
|
|
762
|
+
# 检查缓存
|
|
763
|
+
cache_key = "available_tools"
|
|
764
|
+
if cache_key in self._command_cache:
|
|
765
|
+
cached = self._command_cache[cache_key]
|
|
766
|
+
if time.time() - cached['timestamp'] < self._cache_expiry * 5: # 工具列表缓存时间更长
|
|
767
|
+
return cached['result']
|
|
768
|
+
|
|
769
|
+
result = self._call("tools/list")
|
|
770
|
+
|
|
771
|
+
# 缓存结果
|
|
772
|
+
self._command_cache[cache_key] = {
|
|
773
|
+
'result': result,
|
|
774
|
+
'timestamp': time.time()
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
return result
|
|
778
|
+
|
|
779
|
+
|
|
780
|
+
|
|
781
|
+
def shutdown(self):
|
|
782
|
+
"""关闭资源"""
|
|
783
|
+
# 停止监控
|
|
784
|
+
self.stop_monitoring()
|
|
785
|
+
|
|
786
|
+
# 清理连接池
|
|
787
|
+
if self.enable_connection_pool:
|
|
788
|
+
with self._pool_lock:
|
|
789
|
+
while not self._connection_pool.empty():
|
|
790
|
+
try:
|
|
791
|
+
conn = self._connection_pool.get()
|
|
792
|
+
conn.close()
|
|
793
|
+
except:
|
|
794
|
+
pass
|
|
795
|
+
|
|
796
|
+
print("✅ Rcoder已关闭")
|
|
797
|
+
|
|
798
|
+
|
|
799
|
+
class RemoteHost:
|
|
800
|
+
"""
|
|
801
|
+
远程主机管理类
|
|
802
|
+
提供类似本地主机的使用体验
|
|
803
|
+
"""
|
|
804
|
+
|
|
805
|
+
def __init__(self, rcoder: RcoderCore, server: str = 'local'):
|
|
806
|
+
"""
|
|
807
|
+
初始化远程主机管理
|
|
808
|
+
|
|
809
|
+
Args:
|
|
810
|
+
rcoder: Rcoder核心实例
|
|
811
|
+
server: 服务器名称
|
|
812
|
+
"""
|
|
813
|
+
self.rcoder = rcoder
|
|
814
|
+
self.server = server
|
|
815
|
+
|
|
816
|
+
def run(self, command: str, timeout: int = 60, wait_for_restart: bool = False,
|
|
817
|
+
use_cache: bool = True) -> str:
|
|
818
|
+
"""运行命令,优化低带宽场景
|
|
819
|
+
|
|
820
|
+
Args:
|
|
821
|
+
command: 命令
|
|
822
|
+
timeout: 超时时间
|
|
823
|
+
wait_for_restart: 是否等待重启完成
|
|
824
|
+
use_cache: 是否使用缓存
|
|
825
|
+
"""
|
|
826
|
+
return self.rcoder.execute(
|
|
827
|
+
self.server,
|
|
828
|
+
command,
|
|
829
|
+
timeout=timeout,
|
|
830
|
+
wait_for_restart=wait_for_restart,
|
|
831
|
+
use_cache=use_cache
|
|
832
|
+
)
|
|
833
|
+
|
|
834
|
+
async def run_async(self, command: str, timeout: int = 60, use_cache: bool = True) -> str:
|
|
835
|
+
"""异步运行命令,优化低带宽场景"""
|
|
836
|
+
return await self.rcoder.execute_async(self.server, command, timeout, use_cache)
|
|
837
|
+
|
|
838
|
+
def run_batch(self, commands: List[str], timeout: int = 60,
|
|
839
|
+
use_cache: bool = True, parallel: bool = False) -> Dict[str, str]:
|
|
840
|
+
"""批量运行命令,优化低带宽场景
|
|
841
|
+
|
|
842
|
+
Args:
|
|
843
|
+
commands: 命令列表
|
|
844
|
+
timeout: 超时时间
|
|
845
|
+
use_cache: 是否使用缓存
|
|
846
|
+
parallel: 是否并行执行
|
|
847
|
+
"""
|
|
848
|
+
return self.rcoder.execute_batch(
|
|
849
|
+
self.server,
|
|
850
|
+
commands,
|
|
851
|
+
timeout=timeout,
|
|
852
|
+
use_cache=use_cache,
|
|
853
|
+
parallel=parallel
|
|
854
|
+
)
|
|
855
|
+
|
|
856
|
+
async def run_batch_async(self, commands: List[str], timeout: int = 60,
|
|
857
|
+
use_cache: bool = True) -> Dict[str, str]:
|
|
858
|
+
"""异步批量运行命令,优化低带宽场景"""
|
|
859
|
+
return await self.rcoder.execute_batch_async(
|
|
860
|
+
self.server,
|
|
861
|
+
commands,
|
|
862
|
+
timeout=timeout,
|
|
863
|
+
use_cache=use_cache
|
|
864
|
+
)
|
|
865
|
+
|
|
866
|
+
def ls(self, path: str = '.', use_cache: bool = True) -> str:
|
|
867
|
+
"""列出目录内容,优化低带宽场景"""
|
|
868
|
+
return self.run(f'ls -la {path}', use_cache=use_cache)
|
|
869
|
+
|
|
870
|
+
def cat(self, file: str, use_cache: bool = True) -> str:
|
|
871
|
+
"""查看文件内容,优化低带宽场景"""
|
|
872
|
+
return self.run(f'cat {file}', use_cache=use_cache)
|
|
873
|
+
|
|
874
|
+
def mkdir(self, path: str) -> str:
|
|
875
|
+
"""创建目录"""
|
|
876
|
+
return self.run(f'mkdir -p {path}', use_cache=False) # 不使用缓存,因为是修改操作
|
|
877
|
+
|
|
878
|
+
def rm(self, path: str, recursive: bool = False) -> str:
|
|
879
|
+
"""删除文件或目录"""
|
|
880
|
+
cmd = f'rm -rf {path}' if recursive else f'rm {path}'
|
|
881
|
+
return self.run(cmd, use_cache=False) # 不使用缓存,因为是修改操作
|
|
882
|
+
|
|
883
|
+
def cp(self, source: str, destination: str) -> str:
|
|
884
|
+
"""复制文件或目录"""
|
|
885
|
+
return self.run(f'cp -r {source} {destination}', use_cache=False) # 不使用缓存,因为是修改操作
|
|
886
|
+
|
|
887
|
+
def mv(self, source: str, destination: str) -> str:
|
|
888
|
+
"""移动文件或目录"""
|
|
889
|
+
return self.run(f'mv {source} {destination}', use_cache=False) # 不使用缓存,因为是修改操作
|
|
890
|
+
|
|
891
|
+
def systemctl(self, action: str, service: str) -> str:
|
|
892
|
+
"""管理系统服务"""
|
|
893
|
+
wait_for_restart = action == 'restart'
|
|
894
|
+
return self.run(
|
|
895
|
+
f'sudo systemctl {action} {service}',
|
|
896
|
+
wait_for_restart=wait_for_restart,
|
|
897
|
+
use_cache=False # 不使用缓存,因为是服务操作
|
|
898
|
+
)
|
|
899
|
+
|
|
900
|
+
def ps(self, use_cache: bool = True) -> str:
|
|
901
|
+
"""查看进程,优化低带宽场景"""
|
|
902
|
+
return self.run('ps aux', use_cache=use_cache)
|
|
903
|
+
|
|
904
|
+
def top(self, use_cache: bool = True) -> str:
|
|
905
|
+
"""查看系统负载,优化低带宽场景"""
|
|
906
|
+
return self.run('top -b -n 1', use_cache=use_cache)
|
|
907
|
+
|
|
908
|
+
def free(self, use_cache: bool = True) -> str:
|
|
909
|
+
"""查看内存使用,优化低带宽场景"""
|
|
910
|
+
return self.run('free -h', use_cache=use_cache)
|
|
911
|
+
|
|
912
|
+
def df(self, use_cache: bool = True) -> str:
|
|
913
|
+
"""查看磁盘使用,优化低带宽场景"""
|
|
914
|
+
return self.run('df -h', use_cache=use_cache)
|
|
915
|
+
|
|
916
|
+
def uptime(self, use_cache: bool = True) -> str:
|
|
917
|
+
"""查看系统运行时间,优化低带宽场景"""
|
|
918
|
+
return self.run('uptime', use_cache=use_cache)
|
|
919
|
+
|
|
920
|
+
def hostname(self, use_cache: bool = True) -> str:
|
|
921
|
+
"""查看主机名,优化低带宽场景"""
|
|
922
|
+
return self.run('hostname', use_cache=use_cache)
|
|
923
|
+
|
|
924
|
+
def ip(self, use_cache: bool = True) -> str:
|
|
925
|
+
"""查看IP地址,优化低带宽场景"""
|
|
926
|
+
return self.run('ip addr', use_cache=use_cache)
|
|
927
|
+
|
|
928
|
+
def ping(self, host: str, count: int = 2) -> str:
|
|
929
|
+
"""ping主机,优化低带宽场景(减少ping次数)"""
|
|
930
|
+
return self.run(f'ping -c {count} {host}', use_cache=False)
|
|
931
|
+
|
|
932
|
+
|
|
933
|
+
def get_remote_host(host: str = '192.168.1.8', port: int = 443, server: str = 'local',
|
|
934
|
+
use_https_disguise: bool = True, proxy_server: Optional[Tuple[str, int]] = None,
|
|
935
|
+
enable_compression: bool = True, enable_connection_pool: bool = True,
|
|
936
|
+
password: Optional[str] = None) -> RemoteHost:
|
|
937
|
+
"""获取远程主机管理实例,优化低带宽场景
|
|
938
|
+
|
|
939
|
+
Args:
|
|
940
|
+
host: Rcoder服务器主机
|
|
941
|
+
port: Rcoder服务器端口 (默认443,支持HTTPS伪装)
|
|
942
|
+
server: 服务器名称
|
|
943
|
+
use_https_disguise: 是否使用HTTPS伪装
|
|
944
|
+
proxy_server: 中转服务器 (host, port),如 ('1.2.3.4', 443)
|
|
945
|
+
enable_compression: 是否启用数据压缩
|
|
946
|
+
enable_connection_pool: 是否启用连接池
|
|
947
|
+
password: 认证密码
|
|
948
|
+
"""
|
|
949
|
+
rcoder = RcoderCore(
|
|
950
|
+
host=host,
|
|
951
|
+
port=port,
|
|
952
|
+
use_https_disguise=use_https_disguise,
|
|
953
|
+
proxy_server=proxy_server,
|
|
954
|
+
enable_compression=enable_compression,
|
|
955
|
+
enable_connection_pool=enable_connection_pool,
|
|
956
|
+
password=password
|
|
957
|
+
)
|
|
958
|
+
return RemoteHost(rcoder, server=server)
|