Spaces:
Runtime error
Runtime error
File size: 11,862 Bytes
fad568b 826bca0 fad568b 826bca0 fad568b 86913fe 826bca0 1e9bb1e fad568b 826bca0 fad568b 86913fe 826bca0 1e9bb1e 826bca0 6129265 826bca0 ae1ebcf 826bca0 ae1ebcf 826bca0 ae1ebcf 826bca0 ae1ebcf 826bca0 1e9bb1e 826bca0 1e9bb1e 826bca0 6129265 826bca0 6129265 826bca0 fad568b 826bca0 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
import asyncio
import websockets
import subprocess
import json
import logging
import sys
import urllib.parse
import base64
import os
import threading
import requests
from urllib.parse import urlparse
# Configure logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# 全局变量,用于在用户输入时访问 WebSocket
global_websocket = None
async def connect(space_id, machine_secret, token, upload_file=None, upload_dir=None):
global global_websocket
# 使用查询参数传递 machine_secret 和 token
encoded_secret = urllib.parse.quote(machine_secret)
encoded_token = urllib.parse.quote(token)
uri = f"wss://remote-terminal-worker.nianxi4563.workers.dev/terminal/{space_id}?secret={encoded_secret}&token={encoded_token}"
logger.info(f"Attempting to connect to {uri}")
try:
async with websockets.connect(uri, ping_interval=20, ping_timeout=60) as websocket:
global_websocket = websocket
logger.info("Connected to WebSocket")
machine_info = {"type": "machine", "space_id": space_id, "token": token}
await websocket.send(json.dumps(machine_info))
logger.debug(f"Sent machine registration: {machine_info}")
# 如果指定了上传文件,发送文件内容
if upload_file:
if os.path.exists(upload_file):
try:
with open(upload_file, 'rb') as f:
file_content = f.read()
file_b64 = base64.b64encode(file_content).decode('utf-8')
file_msg = {
"type": "file_upload",
"filename": os.path.basename(upload_file),
"content": file_b64,
"token": token
}
await websocket.send(json.dumps(file_msg))
logger.info(f"Uploaded file: {upload_file}")
except Exception as e:
logger.error(f"Error uploading file {upload_file}: {e}")
else:
logger.error(f"File not found: {upload_file}")
# 如果指定了上传目录,扫描并上传所有文件
if upload_dir:
if os.path.exists(upload_dir):
all_files = []
for root, dirs, files in os.walk(upload_dir):
for file in files:
file_path = os.path.join(root, file)
if os.path.isfile(file_path):
all_files.append(file_path)
if all_files:
logger.info(f"Found {len(all_files)} files in {upload_dir}, starting upload...")
for file_path in all_files:
try:
with open(file_path, 'rb') as f:
file_content = f.read()
file_b64 = base64.b64encode(file_content).decode('utf-8')
file_msg = {
"type": "file_upload",
"filename": os.path.basename(file_path),
"content": file_b64,
"token": token
}
await websocket.send(json.dumps(file_msg))
logger.info(f"Uploaded file from dir: {file_path}")
except Exception as e:
logger.error(f"Error uploading file {file_path}: {e}")
else:
logger.info(f"No files found in {upload_dir}")
else:
logger.error(f"Directory not found: {upload_dir}")
# 创建下载目录
os.makedirs("./downloads", exist_ok=True)
# 启动用户输入监听(非阻塞)
asyncio.create_task(listen_user_input())
while True:
try:
message = await websocket.recv()
logger.debug(f"Received message: {message}")
data = json.loads(message)
if data["type"] == "command":
command = data["command"]
logger.info(f"Executing command: {command}")
try:
process = subprocess.run(command, shell=True, capture_output=True, text=True)
output = process.stdout + process.stderr
logger.debug(f"Command output: {output}")
if process.returncode == 0:
await websocket.send(json.dumps({"type": "output", "data": output}))
else:
await websocket.send(json.dumps({"type": "error", "data": output}))
except Exception as e:
error_message = f"Error executing command: {e}"
logger.error(error_message)
await websocket.send(json.dumps({"type": "error", "data": error_message}))
elif data["type"] == "file_download_url":
# 处理从服务器发来的文件下载URL
url = data["url"]
filename = data["filename"]
logger.info(f"Received file download URL: {url}")
try:
download_dir = "./downloads"
os.makedirs(download_dir, exist_ok=True)
response = requests.get(url)
if response.status_code == 200:
file_path = os.path.join(download_dir, filename)
with open(file_path, 'wb') as f:
f.write(response.content)
success_msg = f"File downloaded successfully: {file_path}"
logger.info(success_msg)
await websocket.send(json.dumps({
"type": "output",
"data": success_msg
}))
else:
error_msg = f"Failed to download file. Status code: {response.status_code}"
logger.error(error_msg)
await websocket.send(json.dumps({
"type": "error",
"data": error_msg
}))
except Exception as e:
error_msg = f"Error downloading file from URL: {e}"
logger.error(error_msg)
await websocket.send(json.dumps({
"type": "error",
"data": error_msg
}))
elif data["type"] == "ping":
logger.debug("Received ping, sending pong")
await websocket.send(json.dumps({"type": "pong"}))
except websockets.exceptions.ConnectionClosed:
logger.error("WebSocket connection closed")
break
except Exception as e:
logger.error(f"Error processing message: {e}")
await websocket.send(json.dumps({"type": "error", "data": str(e)}))
except Exception as e:
logger.error(f"Failed to connect or maintain connection: {e}")
async def listen_user_input():
global global_websocket
logger.info("Started listening for user input. Use ' --upload' to upload files to server.")
while True:
try:
user_input = await asyncio.to_thread(input, "Enter command or file path to upload: ")
if user_input.strip():
parts = user_input.strip().split()
if len(parts) >= 2 and parts[-1] == "--upload":
filename = " ".join(parts[:-1])
if os.path.exists(filename):
try:
with open(filename, 'rb') as f:
file_content = f.read()
file_b64 = base64.b64encode(file_content).decode('utf-8')
file_msg = {
"type": "file_upload",
"filename": os.path.basename(filename),
"content": file_b64
}
if global_websocket:
await global_websocket.send(json.dumps(file_msg))
logger.info(f"Uploaded file via input: {filename}")
else:
logger.error("WebSocket not connected")
except Exception as e:
logger.error(f"Error uploading file {filename}: {e}")
else:
logger.error(f"File not found: {filename}")
elif len(parts) >= 2 and parts[-1] == "--download":
url = " ".join(parts[:-1])
try:
parsed_url = urlparse(url)
filename = os.path.basename(parsed_url.path)
download_dir = "./downloads"
os.makedirs(download_dir, exist_ok=True)
logger.info(f"Downloading file from URL: {url}")
response = requests.get(url)
if response.status_code == 200:
file_path = os.path.join(download_dir, filename)
with open(file_path, 'wb') as f:
f.write(response.content)
logger.info(f"File downloaded successfully: {file_path}")
else:
logger.error(f"Failed to download file. Status code: {response.status_code}")
except Exception as e:
logger.error(f"Error downloading from URL {url}: {e}")
else:
if global_websocket:
await global_websocket.send(json.dumps({
"type": "command",
"command": user_input
}))
logger.info(f"Sent command: {user_input}")
else:
logger.error("WebSocket not connected")
await asyncio.sleep(0.1)
except Exception as e:
logger.error(f"Error in user input listener: {e}")
await asyncio.sleep(1)
if __name__ == "__main__":
if len(sys.argv) < 4:
print("Usage: python remote_client.py <space_id> <machine_secret> <token> [--upload <file_path>] [--upload-dir <dir_path>]")
sys.exit(1)
space_id = sys.argv[1]
machine_secret = sys.argv[2]
token = sys.argv[3]
upload_file = None
upload_dir = None
if len(sys.argv) > 4:
if sys.argv[4] == "--upload" and len(sys.argv) > 5:
upload_file = sys.argv[5]
elif sys.argv[4] == "--upload-dir" and len(sys.argv) > 5:
upload_dir = sys.argv[5]
asyncio.run(connect(space_id, machine_secret, token, upload_file, upload_dir)) |