|
|
|
@ -142,7 +142,101 @@ class FileTransferApp: |
|
|
|
for widget in self.main_frame.winfo_children(): |
|
|
|
widget.destroy() |
|
|
|
|
|
|
|
|
|
|
|
def show_confirm_dialog(self, stop_command, success_callback): |
|
|
|
"""显示确认对话框""" |
|
|
|
def on_confirm(): |
|
|
|
# 执行停止命令 |
|
|
|
stop_command() |
|
|
|
# 关闭对话框 |
|
|
|
confirm_dialog.destroy() |
|
|
|
# 执行成功回调 |
|
|
|
success_callback() |
|
|
|
|
|
|
|
def on_cancel(): |
|
|
|
confirm_dialog.destroy() |
|
|
|
|
|
|
|
# 创建确认对话框 |
|
|
|
confirm_dialog = tk.Toplevel(self.root) |
|
|
|
confirm_dialog.title("确认离开") |
|
|
|
confirm_dialog.geometry("400x200") |
|
|
|
confirm_dialog.configure(bg='white') |
|
|
|
confirm_dialog.resizable(False, False) |
|
|
|
confirm_dialog.transient(self.root) # 设置为主窗口的临时窗口 |
|
|
|
confirm_dialog.grab_set() # 模态对话框 |
|
|
|
|
|
|
|
# 居中显示 |
|
|
|
confirm_dialog.update_idletasks() |
|
|
|
x = (self.root.winfo_screenwidth() - confirm_dialog.winfo_width()) // 2 |
|
|
|
y = (self.root.winfo_screenheight() - confirm_dialog.winfo_height()) // 2 |
|
|
|
confirm_dialog.geometry(f"+{x}+{y}") |
|
|
|
|
|
|
|
# 图标和提示文字 |
|
|
|
icon_label = tk.Label(confirm_dialog, text="⚠️", font=("Arial", 24), bg='white') |
|
|
|
icon_label.pack(pady=(20, 10)) |
|
|
|
|
|
|
|
message_label = tk.Label( |
|
|
|
confirm_dialog, |
|
|
|
text="你正离开当前界面,会停止运行当前功能", |
|
|
|
font=("Microsoft YaHei", 12), |
|
|
|
fg="#2c3e50", |
|
|
|
bg='white', |
|
|
|
wraplength=350 |
|
|
|
) |
|
|
|
message_label.pack(pady=(0, 20)) |
|
|
|
|
|
|
|
# 按钮框架 |
|
|
|
button_frame = tk.Frame(confirm_dialog, bg='white') |
|
|
|
button_frame.pack(pady=10) |
|
|
|
|
|
|
|
# 取消按钮 |
|
|
|
cancel_button = tk.Button( |
|
|
|
button_frame, |
|
|
|
text="取消", |
|
|
|
command=on_cancel, |
|
|
|
font=("Microsoft YaHei", 11), |
|
|
|
bg="#95a5a6", |
|
|
|
fg="white", |
|
|
|
width=10, |
|
|
|
relief='flat' |
|
|
|
) |
|
|
|
cancel_button.pack(side='left', padx=10) |
|
|
|
|
|
|
|
# 确认按钮 |
|
|
|
confirm_button = tk.Button( |
|
|
|
button_frame, |
|
|
|
text="确认", |
|
|
|
command=on_confirm, |
|
|
|
font=("Microsoft YaHei", 11), |
|
|
|
bg="#e74c3c", |
|
|
|
fg="white", |
|
|
|
width=10, |
|
|
|
relief='flat' |
|
|
|
) |
|
|
|
confirm_button.pack(side='left', padx=10) |
|
|
|
|
|
|
|
# 绑定回车和ESC键 |
|
|
|
confirm_dialog.bind('<Return>', lambda e: on_confirm()) |
|
|
|
confirm_dialog.bind('<Escape>', lambda e: on_cancel()) |
|
|
|
confirm_button.focus_set() |
|
|
|
|
|
|
|
def show_welcome_screen(self): |
|
|
|
"""显示欢迎界面""" |
|
|
|
if self.current_page: |
|
|
|
# 根据当前页面类型决定停止命令 |
|
|
|
if self.current_page == 'send' and self.page_states['send']['is_running']: |
|
|
|
self.show_confirm_dialog(self.stop_send_connection, self._show_welcome_screen) |
|
|
|
return |
|
|
|
elif self.current_page == 'receive' and self.page_states['receive']['is_running']: |
|
|
|
self.show_confirm_dialog(self.stop_frpc_connection, self._show_welcome_screen) |
|
|
|
return |
|
|
|
elif self.current_page == 'cloud' and self.page_states['cloud']['is_running']: |
|
|
|
self.show_confirm_dialog(self.stop_cloud_accel, self._show_welcome_screen) |
|
|
|
return |
|
|
|
|
|
|
|
# 如果没有运行中的功能,直接显示欢迎界面 |
|
|
|
self._show_welcome_screen() |
|
|
|
def _show_welcome_screen(self): |
|
|
|
"""显示欢迎界面""" |
|
|
|
if self.current_page: |
|
|
|
self.save_current_page_state() |
|
|
|
@ -271,7 +365,22 @@ class FileTransferApp: |
|
|
|
bg='white' |
|
|
|
) |
|
|
|
footer_label.pack() |
|
|
|
|
|
|
|
def show_cloud_accel_screen(self): |
|
|
|
"""显示网盘加速界面""" |
|
|
|
if self.current_page and self.current_page != 'cloud': |
|
|
|
# 检查当前页面是否有运行中的功能 |
|
|
|
if self.current_page == 'send' and self.page_states['send']['is_running']: |
|
|
|
self.show_confirm_dialog(self.stop_send_connection, self._show_cloud_accel_screen) |
|
|
|
return |
|
|
|
elif self.current_page == 'receive' and self.page_states['receive']['is_running']: |
|
|
|
self.show_confirm_dialog(self.stop_frpc_connection, self._show_cloud_accel_screen) |
|
|
|
return |
|
|
|
|
|
|
|
# 如果没有运行中的功能,直接显示网盘加速界面 |
|
|
|
self._show_cloud_accel_screen() |
|
|
|
|
|
|
|
def _show_cloud_accel_screen(self): |
|
|
|
"""显示网盘加速界面""" |
|
|
|
if self.current_page: |
|
|
|
self.save_current_page_state() |
|
|
|
@ -368,6 +477,18 @@ class FileTransferApp: |
|
|
|
if hasattr(self, 'cloud_output'): |
|
|
|
self.restore_page_state('cloud') |
|
|
|
|
|
|
|
|
|
|
|
# 修改所有页面切换方法,使用lambda包装 |
|
|
|
def setup_navigation(self): |
|
|
|
"""设置页面导航""" |
|
|
|
# 在欢迎界面中 |
|
|
|
send_button = tk.Button(..., command=lambda: self.show_send_screen()) |
|
|
|
receive_button = tk.Button(..., command=lambda: self.show_receive_screen()) |
|
|
|
cloud_button = tk.Button(..., command=lambda: self.show_cloud_accel_screen()) |
|
|
|
|
|
|
|
# 在各个功能界面中 |
|
|
|
back_button = tk.Button(..., command=lambda: self.show_welcome_screen()) |
|
|
|
|
|
|
|
def create_kodcloud_ini(self): |
|
|
|
"""创建kodcloud.ini配置文件""" |
|
|
|
# 获取当前时间,精确到秒 |
|
|
|
@ -411,6 +532,16 @@ bind_port = 8089 |
|
|
|
|
|
|
|
def start_cloud_accel(self): |
|
|
|
"""启动网盘加速服务""" |
|
|
|
bport = 8089 |
|
|
|
# 检查6000端口是否被占用 |
|
|
|
occupying_pids = self.get_processes_using_port(bport) |
|
|
|
if occupying_pids: |
|
|
|
self.append_send_output(f"[警告] {bport}端口被以下进程占用:\n") |
|
|
|
for pid, process_name in occupying_pids: |
|
|
|
self.append_send_output(f" - PID: {pid}, 进程: {process_name}\n") |
|
|
|
self.append_send_output("[提示] 请手动关闭这些进程或更改端口配置后再试\n") |
|
|
|
return |
|
|
|
|
|
|
|
try: |
|
|
|
# 创建配置文件 |
|
|
|
if not self.create_kodcloud_ini(): |
|
|
|
@ -494,8 +625,21 @@ bind_port = 8089 |
|
|
|
padx=10, |
|
|
|
pady=5 |
|
|
|
) |
|
|
|
|
|
|
|
def show_send_screen(self): |
|
|
|
"""显示发送界面""" |
|
|
|
if self.current_page and self.current_page != 'send': |
|
|
|
# 检查当前页面是否有运行中的功能 |
|
|
|
if self.current_page == 'receive' and self.page_states['receive']['is_running']: |
|
|
|
self.show_confirm_dialog(self.stop_frpc_connection, self._show_send_screen) |
|
|
|
return |
|
|
|
elif self.current_page == 'cloud' and self.page_states['cloud']['is_running']: |
|
|
|
self.show_confirm_dialog(self.stop_cloud_accel, self._show_send_screen) |
|
|
|
return |
|
|
|
|
|
|
|
# 如果没有运行中的功能,直接显示发送界面 |
|
|
|
self._show_send_screen() |
|
|
|
|
|
|
|
def _show_send_screen(self): |
|
|
|
"""显示发送界面""" |
|
|
|
if self.current_page: |
|
|
|
self.save_current_page_state() |
|
|
|
@ -608,7 +752,22 @@ bind_port = 8089 |
|
|
|
# 恢复状态 |
|
|
|
self.restore_page_state('send') |
|
|
|
|
|
|
|
|
|
|
|
def show_receive_screen(self): |
|
|
|
"""显示接收界面""" |
|
|
|
if self.current_page and self.current_page != 'receive': |
|
|
|
# 检查当前页面是否有运行中的功能 |
|
|
|
if self.current_page == 'send' and self.page_states['send']['is_running']: |
|
|
|
self.show_confirm_dialog(self.stop_send_connection, self._show_receive_screen) |
|
|
|
return |
|
|
|
elif self.current_page == 'cloud' and self.page_states['cloud']['is_running']: |
|
|
|
self.show_confirm_dialog(self.stop_cloud_accel, self._show_receive_screen) |
|
|
|
return |
|
|
|
|
|
|
|
# 如果没有运行中的功能,直接显示接收界面 |
|
|
|
self._show_receive_screen() |
|
|
|
|
|
|
|
def _show_receive_screen(self): |
|
|
|
"""显示接收界面""" |
|
|
|
if self.current_page: |
|
|
|
self.save_current_page_state() |
|
|
|
@ -622,6 +781,7 @@ bind_port = 8089 |
|
|
|
back_button = self.create_styled_button(title_frame, "← 返回", self.show_welcome_screen, "#95a5a6", 8) |
|
|
|
back_button.pack(side='left') |
|
|
|
|
|
|
|
|
|
|
|
title_label = tk.Label( |
|
|
|
title_frame, |
|
|
|
text="📥 文件接收", |
|
|
|
@ -719,6 +879,7 @@ bind_port = 8089 |
|
|
|
else: |
|
|
|
# 恢复状态 |
|
|
|
self.restore_page_state('receive') |
|
|
|
|
|
|
|
def browse_receive_path(self): |
|
|
|
"""浏览选择接收文件保存路径""" |
|
|
|
folder_path = filedialog.askdirectory( |
|
|
|
@ -907,6 +1068,15 @@ bind_port = {bport} |
|
|
|
self.send_sern = sern |
|
|
|
self.bport = bport |
|
|
|
|
|
|
|
# 检查7001端口是否被占用 |
|
|
|
occupying_pids = self.get_processes_using_port(bport) |
|
|
|
if occupying_pids: |
|
|
|
self.append_send_output(f"[警告] {bport}端口被以下进程占用:\n") |
|
|
|
for pid, process_name in occupying_pids: |
|
|
|
self.append_send_output(f" - PID: {pid}, 进程: {process_name}\n") |
|
|
|
self.append_send_output("[提示] 请手动关闭这些进程或更改端口配置后再试\n") |
|
|
|
return |
|
|
|
|
|
|
|
# 创建配置文件 |
|
|
|
if not self.create_send_ini(token, sk, sern, bport): |
|
|
|
return |
|
|
|
@ -939,6 +1109,91 @@ bind_port = {bport} |
|
|
|
self.page_states['send']['is_running'] = True |
|
|
|
self.page_states['send']['key_entry_text'] = key |
|
|
|
self.page_states['send']['file_path'] = self.file_path_var.get() |
|
|
|
|
|
|
|
def get_processes_using_port(self, port): |
|
|
|
"""获取占用指定端口的进程信息""" |
|
|
|
try: |
|
|
|
if os.name == 'nt': # Windows系统 |
|
|
|
return self._get_processes_windows(port) |
|
|
|
else: # Linux/Mac系统 |
|
|
|
return self._get_processes_linux(port) |
|
|
|
except Exception as e: |
|
|
|
self.append_send_output(f"[错误] 获取端口信息时出错: {e}\n") |
|
|
|
return [] |
|
|
|
|
|
|
|
def _get_processes_windows(self, port): |
|
|
|
"""Windows系统下获取占用端口的进程信息""" |
|
|
|
processes = [] |
|
|
|
try: |
|
|
|
# 方法1: 使用netstat命令 |
|
|
|
result = subprocess.run( |
|
|
|
['netstat', '-ano', '-p', 'tcp'], |
|
|
|
capture_output=True, text=True, encoding='gbk' |
|
|
|
) |
|
|
|
|
|
|
|
lines = result.stdout.split('\n') |
|
|
|
for line in lines: |
|
|
|
if f':{port}' in line and 'LISTENING' in line: |
|
|
|
parts = line.split() |
|
|
|
if len(parts) >= 5: |
|
|
|
pid = parts[-1].strip() |
|
|
|
process_name = self._get_process_name_windows(pid) |
|
|
|
processes.append((pid, process_name)) |
|
|
|
|
|
|
|
# 方法2: 使用PowerShell备用 |
|
|
|
if not processes: |
|
|
|
processes = self._get_processes_windows_ps(port) |
|
|
|
|
|
|
|
except Exception as e: |
|
|
|
self.append_send_output(f"[错误] Windows端口检测失败: {e}\n") |
|
|
|
|
|
|
|
return processes |
|
|
|
|
|
|
|
def _get_processes_windows_ps(self, port): |
|
|
|
"""Windows使用PowerShell获取进程信息""" |
|
|
|
processes = [] |
|
|
|
try: |
|
|
|
ps_command = f"Get-NetTCPConnection -LocalPort {port} | Select-Object OwningProcess, @{{Name='ProcessName'; Expression={{ (Get-Process -Id $_.OwningProcess).Name }} }}" |
|
|
|
result = subprocess.run( |
|
|
|
['powershell', '-Command', ps_command], |
|
|
|
capture_output=True, text=True, timeout=10 |
|
|
|
) |
|
|
|
|
|
|
|
if result.returncode == 0: |
|
|
|
lines = result.stdout.strip().split('\n') |
|
|
|
for line in lines: |
|
|
|
if 'OwningProcess' in line and 'ProcessName' in line: |
|
|
|
continue # 跳过标题行 |
|
|
|
parts = line.split() |
|
|
|
if len(parts) >= 2: |
|
|
|
pid = parts[0].strip() |
|
|
|
process_name = parts[1].strip() if len(parts) > 1 else "未知进程" |
|
|
|
processes.append((pid, process_name)) |
|
|
|
|
|
|
|
except Exception as e: |
|
|
|
self.append_send_output(f"[错误] PowerShell检测失败: {e}\n") |
|
|
|
|
|
|
|
return processes |
|
|
|
|
|
|
|
def _get_process_name_windows(self, pid): |
|
|
|
"""Windows下根据PID获取进程名称""" |
|
|
|
try: |
|
|
|
result = subprocess.run( |
|
|
|
['tasklist', '/fi', f'pid eq {pid}', '/fo', 'csv', '/nh'], |
|
|
|
capture_output=True, text=True, encoding='gbk' |
|
|
|
) |
|
|
|
|
|
|
|
if result.returncode == 0 and result.stdout.strip(): |
|
|
|
# CSV格式: "进程名","PID","会话名","会话#","内存使用" |
|
|
|
parts = result.stdout.strip().split('","') |
|
|
|
if len(parts) >= 1: |
|
|
|
process_name = parts[0].replace('"', '') |
|
|
|
return process_name |
|
|
|
except: |
|
|
|
pass |
|
|
|
return "未知进程" |
|
|
|
|
|
|
|
|
|
|
|
def start_file_send(self): |
|
|
|
"""开始发送文件""" |
|
|
|
if not self.file_path_var.get(): |
|
|
|
@ -1167,6 +1422,15 @@ local_port = {bport} |
|
|
|
self.current_sern = sern |
|
|
|
self.bport = bport |
|
|
|
|
|
|
|
# 检查6000端口是否被占用 |
|
|
|
occupying_pids = self.get_processes_using_port(bport) |
|
|
|
if occupying_pids: |
|
|
|
self.append_send_output(f"[警告] {bport}端口被以下进程占用:\n") |
|
|
|
for pid, process_name in occupying_pids: |
|
|
|
self.append_send_output(f" - PID: {pid}, 进程: {process_name}\n") |
|
|
|
self.append_send_output("[提示] 请手动关闭这些进程或更改端口配置后再试\n") |
|
|
|
return |
|
|
|
|
|
|
|
# 获取保存路径并显示 |
|
|
|
save_path = self.receive_path_var.get() |
|
|
|
self.append_output(f"📁 保存路径: {save_path}\n") |
|
|
|
|