bea288e414
== 已部署上线 (9项) == - 代办事项真实数据源集成 (企微审批API 8bug修复链) - H5/坐席端 Logo样式统一+绿色背景 - 视频引导页修复 (localStorage key v2) - 坐席端 v9 Vue版本修复 (ElMessage._context) - 截图按钮 v10 修复 (getDisplayMedia user gesture) - 扫码样式恢复+H5扫码登录跳转修复 - H5截图快捷键提示 == 代码完成待部署 (3项) == - 知识迭代3Bug修复 (#8 POST端点/#7 MERGE幂等/#6 过期检查) - 会议室预定-小鱼易联终端 (40文件, 40/40测试通过) - IT资产升级审批推送 (asset_service.py) == 需求文档 (2项) == - 坐席端AI辅助消息框-PRD (4项新功能确认) - 坐席端布局优化建议 v2.0 (7天计划) == 新增文档 == - 日报-2026-07-11.md - 知识迭代Bug修复报告-20260711.md - 会议室预定-部署指南.md - CHANGELOG.md 更新 == 测试 == - test_todo_integration.py: 40/40 - test_meetingroom.py: 40/40 - test_bugfix_ki_suggestions.py: 21/21
88 lines
3.6 KiB
Python
88 lines
3.6 KiB
Python
"""
|
|
大文件上传脚本 - 通过 JumpServer plink PTY 使用 base64 通道上传
|
|
使用 4000 字符的大块,比 jms_ops.py 的 500 字符快 8 倍
|
|
"""
|
|
import sys, os, base64, hashlib, time
|
|
|
|
# 导入 jms_ops 模块
|
|
SKILL_DIR = r"C:\Users\simon\.workbuddy\skills\jumpserver-ops\scripts"
|
|
sys.path.insert(0, SKILL_DIR)
|
|
import jms_ops
|
|
|
|
def upload_large_file(local_path, remote_path, chunk_size=4000):
|
|
"""通过 plink PTY 上传大文件,使用大块 base64 编码"""
|
|
local_data = open(local_path, 'rb').read()
|
|
local_md5 = hashlib.md5(local_data).hexdigest()
|
|
b64_data = base64.b64encode(local_data).decode('ascii')
|
|
|
|
total_chunks = (len(b64_data) + chunk_size - 1) // chunk_size
|
|
print(f"📤 上传: {local_path} → {remote_path}")
|
|
print(f" 原始: {len(local_data)} bytes, base64: {len(b64_data)} chars")
|
|
print(f" 分 {total_chunks} 块发送 (每块 {chunk_size} chars)")
|
|
|
|
# 获取 token + 启动会话
|
|
tokens = jms_ops.get_connection_tokens(1)
|
|
if not tokens:
|
|
print("❌ 获取 token 失败")
|
|
return False
|
|
|
|
token_id, token_secret = tokens[0]
|
|
session = jms_ops.PlinkSession(f"JMS-{token_id}", token_secret)
|
|
if not session.connect():
|
|
print("❌ 会话启动失败")
|
|
return False
|
|
|
|
try:
|
|
# 1. 清空目标文件
|
|
session.run_command(f'> {remote_path}', timeout=5)
|
|
|
|
# 2. 逐块追加 (大块)
|
|
start_time = time.time()
|
|
for i in range(0, len(b64_data), chunk_size):
|
|
chunk = b64_data[i:i+chunk_size]
|
|
chunk_num = i // chunk_size + 1
|
|
cmd = f"echo '{chunk}' | base64 -d >> {remote_path}"
|
|
r = session.run_command(cmd, timeout=15)
|
|
if not r["success"]:
|
|
print(f" ❌ 块 {chunk_num}/{total_chunks} 发送失败")
|
|
return False
|
|
if chunk_num % 50 == 0 or chunk_num == total_chunks:
|
|
elapsed = time.time() - start_time
|
|
pct = chunk_num / total_chunks * 100
|
|
print(f" 📦 已发送 {chunk_num}/{total_chunks} 块 ({pct:.0f}%) - {elapsed:.1f}s")
|
|
|
|
# 3. 验证大小
|
|
r = session.run_command(f'wc -c < {remote_path}', timeout=5)
|
|
if r["success"]:
|
|
remote_size = int(r["output"].strip()) if r["output"].strip().isdigit() else -1
|
|
if remote_size == len(local_data):
|
|
elapsed = time.time() - start_time
|
|
print(f" ✅ 上传成功! 大小匹配 ({remote_size} bytes), 耗时 {elapsed:.1f}s")
|
|
# 4. MD5 验证
|
|
r2 = session.run_command(f'md5sum {remote_path}', timeout=5)
|
|
if r2["success"]:
|
|
remote_md5 = r2["output"].split()[0]
|
|
if remote_md5 == local_md5:
|
|
print(f" ✅ MD5 匹配! 文件完整")
|
|
else:
|
|
print(f" ⚠️ MD5 不匹配 (本地 {local_md5[:12]}, 远程 {remote_md5[:12]})")
|
|
return True
|
|
else:
|
|
print(f" ❌ 大小不匹配 (本地 {len(local_data)}, 远程 {remote_size})")
|
|
return False
|
|
else:
|
|
print(" ⚠️ 无法验证远程文件大小")
|
|
return False
|
|
finally:
|
|
session.close()
|
|
|
|
if __name__ == '__main__':
|
|
local = r"D:\资料\03-项目开发\wecom_it_smart_desk\tmp-agent-dist.tar.gz"
|
|
remote = "/tmp/agent-dist.tar.gz"
|
|
success = upload_large_file(local, remote, chunk_size=4000)
|
|
if success:
|
|
print("\n✅ 上传完成,可以在服务器上解压了")
|
|
else:
|
|
print("\n❌ 上传失败")
|
|
sys.exit(1)
|