diff --git a/internal/server/tunnel/server.go b/internal/server/tunnel/server.go index a68e519..6d081f2 100644 --- a/internal/server/tunnel/server.go +++ b/internal/server/tunnel/server.go @@ -261,6 +261,26 @@ func (s *Server) unregisterClient(cs *ClientSession) { delete(s.clients, cs.ID) } +// stopProxyListeners 停止代理监听 +func (s *Server) stopProxyListeners(cs *ClientSession) { + cs.mu.Lock() + defer cs.mu.Unlock() + + // 关闭 TCP 监听器 + for port, ln := range cs.Listeners { + ln.Close() + s.portManager.Release(port) + } + cs.Listeners = make(map[int]net.Listener) + + // 关闭 UDP 连接 + for port, conn := range cs.UDPConns { + conn.Close() + s.portManager.Release(port) + } + cs.UDPConns = make(map[int]*net.UDPConn) +} + // startProxyListeners 启动代理监听 func (s *Server) startProxyListeners(cs *ClientSession) { for _, rule := range cs.Rules { @@ -500,6 +520,18 @@ func (s *Server) PushConfigToClient(clientID string) error { return err } + // 停止旧的监听器 + s.stopProxyListeners(cs) + + // 更新规则 + cs.mu.Lock() + cs.Rules = rules + cs.mu.Unlock() + + // 启动新的监听器 + s.startProxyListeners(cs) + + // 发送配置到客户端 return s.sendProxyConfig(cs.Session, rules) } diff --git a/web/src/views/ClientView.vue b/web/src/views/ClientView.vue index ef2dcef..85dc32c 100644 --- a/web/src/views/ClientView.vue +++ b/web/src/views/ClientView.vue @@ -29,9 +29,12 @@ const nickname = ref('') const rules = ref([]) const clientPlugins = ref([]) const editing = ref(false) -const editNickname = ref('') const editRules = ref([]) +// 重命名相关 +const showRenameModal = ref(false) +const renameValue = ref('') + // 内置类型 const builtinTypes = [ { label: 'TCP', value: 'tcp' }, @@ -129,8 +132,29 @@ onMounted(() => { loadPlugins() }) +// 打开重命名弹窗 +const openRenameModal = () => { + renameValue.value = nickname.value + showRenameModal.value = true +} + +// 保存重命名 +const saveRename = async () => { + try { + await updateClient(clientId, { + id: clientId, + nickname: renameValue.value, + rules: rules.value + }) + nickname.value = renameValue.value + showRenameModal.value = false + message.success('重命名成功') + } catch (e) { + message.error('重命名失败') + } +} + const startEdit = () => { - editNickname.value = nickname.value editRules.value = rules.value.map(rule => ({ ...rule, type: rule.type || 'tcp', @@ -155,7 +179,7 @@ const removeRule = (index: number) => { const saveEdit = async () => { try { - await updateClient(clientId, { id: clientId, nickname: editNickname.value, rules: editRules.value }) + await updateClient(clientId, { id: clientId, nickname: nickname.value, rules: editRules.value }) editing.value = false message.success('保存成功') loadClient() @@ -218,6 +242,7 @@ const installPlugins = async () => { await installPluginsToClient(clientId, selectedPlugins.value) message.success(`已推送 ${selectedPlugins.value.length} 个插件到客户端`) showInstallModal.value = false + await loadClient() // 刷新客户端数据 } catch (e: any) { message.error(e.response?.data || '安装失败') } @@ -289,7 +314,10 @@ const savePluginConfig = async () => { 返回 -

{{ nickname || clientId }}

+

+ {{ nickname || clientId }} + +

{{ clientId }} {{ online ? '在线' : '离线' }} @@ -379,9 +407,6 @@ const savePluginConfig = async () => { + + + + + + + +