111
All checks were successful
Build Multi-Platform Binaries / build-frontend (push) Successful in 33s
Build Multi-Platform Binaries / build-binaries (amd64, darwin, server, false) (push) Successful in 2m8s
Build Multi-Platform Binaries / build-binaries (amd64, linux, client, true) (push) Successful in 37s
Build Multi-Platform Binaries / build-binaries (amd64, linux, server, true) (push) Successful in 59s
Build Multi-Platform Binaries / build-binaries (amd64, windows, client, true) (push) Successful in 53s
Build Multi-Platform Binaries / build-binaries (amd64, windows, server, true) (push) Successful in 1m0s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, client, true) (push) Successful in 1m14s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, server, true) (push) Successful in 1m15s
Build Multi-Platform Binaries / build-binaries (arm64, darwin, server, false) (push) Successful in 51s
Build Multi-Platform Binaries / build-binaries (arm64, linux, client, true) (push) Successful in 37s
Build Multi-Platform Binaries / build-binaries (arm64, linux, server, true) (push) Successful in 59s
Build Multi-Platform Binaries / build-binaries (arm64, windows, server, false) (push) Successful in 1m19s
All checks were successful
Build Multi-Platform Binaries / build-frontend (push) Successful in 33s
Build Multi-Platform Binaries / build-binaries (amd64, darwin, server, false) (push) Successful in 2m8s
Build Multi-Platform Binaries / build-binaries (amd64, linux, client, true) (push) Successful in 37s
Build Multi-Platform Binaries / build-binaries (amd64, linux, server, true) (push) Successful in 59s
Build Multi-Platform Binaries / build-binaries (amd64, windows, client, true) (push) Successful in 53s
Build Multi-Platform Binaries / build-binaries (amd64, windows, server, true) (push) Successful in 1m0s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, client, true) (push) Successful in 1m14s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, server, true) (push) Successful in 1m15s
Build Multi-Platform Binaries / build-binaries (arm64, darwin, server, false) (push) Successful in 51s
Build Multi-Platform Binaries / build-binaries (arm64, linux, client, true) (push) Successful in 37s
Build Multi-Platform Binaries / build-binaries (arm64, linux, server, true) (push) Successful in 59s
Build Multi-Platform Binaries / build-binaries (arm64, windows, server, false) (push) Successful in 1m19s
This commit is contained in:
@@ -261,6 +261,26 @@ func (s *Server) unregisterClient(cs *ClientSession) {
|
|||||||
delete(s.clients, cs.ID)
|
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 启动代理监听
|
// startProxyListeners 启动代理监听
|
||||||
func (s *Server) startProxyListeners(cs *ClientSession) {
|
func (s *Server) startProxyListeners(cs *ClientSession) {
|
||||||
for _, rule := range cs.Rules {
|
for _, rule := range cs.Rules {
|
||||||
@@ -500,6 +520,18 @@ func (s *Server) PushConfigToClient(clientID string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 停止旧的监听器
|
||||||
|
s.stopProxyListeners(cs)
|
||||||
|
|
||||||
|
// 更新规则
|
||||||
|
cs.mu.Lock()
|
||||||
|
cs.Rules = rules
|
||||||
|
cs.mu.Unlock()
|
||||||
|
|
||||||
|
// 启动新的监听器
|
||||||
|
s.startProxyListeners(cs)
|
||||||
|
|
||||||
|
// 发送配置到客户端
|
||||||
return s.sendProxyConfig(cs.Session, rules)
|
return s.sendProxyConfig(cs.Session, rules)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,9 +29,12 @@ const nickname = ref('')
|
|||||||
const rules = ref<ProxyRule[]>([])
|
const rules = ref<ProxyRule[]>([])
|
||||||
const clientPlugins = ref<ClientPlugin[]>([])
|
const clientPlugins = ref<ClientPlugin[]>([])
|
||||||
const editing = ref(false)
|
const editing = ref(false)
|
||||||
const editNickname = ref('')
|
|
||||||
const editRules = ref<ProxyRule[]>([])
|
const editRules = ref<ProxyRule[]>([])
|
||||||
|
|
||||||
|
// 重命名相关
|
||||||
|
const showRenameModal = ref(false)
|
||||||
|
const renameValue = ref('')
|
||||||
|
|
||||||
// 内置类型
|
// 内置类型
|
||||||
const builtinTypes = [
|
const builtinTypes = [
|
||||||
{ label: 'TCP', value: 'tcp' },
|
{ label: 'TCP', value: 'tcp' },
|
||||||
@@ -129,8 +132,29 @@ onMounted(() => {
|
|||||||
loadPlugins()
|
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 = () => {
|
const startEdit = () => {
|
||||||
editNickname.value = nickname.value
|
|
||||||
editRules.value = rules.value.map(rule => ({
|
editRules.value = rules.value.map(rule => ({
|
||||||
...rule,
|
...rule,
|
||||||
type: rule.type || 'tcp',
|
type: rule.type || 'tcp',
|
||||||
@@ -155,7 +179,7 @@ const removeRule = (index: number) => {
|
|||||||
|
|
||||||
const saveEdit = async () => {
|
const saveEdit = async () => {
|
||||||
try {
|
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
|
editing.value = false
|
||||||
message.success('保存成功')
|
message.success('保存成功')
|
||||||
loadClient()
|
loadClient()
|
||||||
@@ -218,6 +242,7 @@ const installPlugins = async () => {
|
|||||||
await installPluginsToClient(clientId, selectedPlugins.value)
|
await installPluginsToClient(clientId, selectedPlugins.value)
|
||||||
message.success(`已推送 ${selectedPlugins.value.length} 个插件到客户端`)
|
message.success(`已推送 ${selectedPlugins.value.length} 个插件到客户端`)
|
||||||
showInstallModal.value = false
|
showInstallModal.value = false
|
||||||
|
await loadClient() // 刷新客户端数据
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
message.error(e.response?.data || '安装失败')
|
message.error(e.response?.data || '安装失败')
|
||||||
}
|
}
|
||||||
@@ -289,7 +314,10 @@ const savePluginConfig = async () => {
|
|||||||
<template #icon><n-icon><ArrowBackOutline /></n-icon></template>
|
<template #icon><n-icon><ArrowBackOutline /></n-icon></template>
|
||||||
返回
|
返回
|
||||||
</n-button>
|
</n-button>
|
||||||
<h2 style="margin: 0;">{{ nickname || clientId }}</h2>
|
<h2 style="margin: 0; cursor: pointer;" @click="openRenameModal" title="点击重命名">
|
||||||
|
{{ nickname || clientId }}
|
||||||
|
<n-icon size="16" style="margin-left: 4px; opacity: 0.5;"><CreateOutline /></n-icon>
|
||||||
|
</h2>
|
||||||
<span v-if="nickname" style="color: #999; font-size: 12px;">{{ clientId }}</span>
|
<span v-if="nickname" style="color: #999; font-size: 12px;">{{ clientId }}</span>
|
||||||
<n-tag :type="online ? 'success' : 'default'">
|
<n-tag :type="online ? 'success' : 'default'">
|
||||||
{{ online ? '在线' : '离线' }}
|
{{ online ? '在线' : '离线' }}
|
||||||
@@ -379,9 +407,6 @@ const savePluginConfig = async () => {
|
|||||||
<!-- 编辑模式 -->
|
<!-- 编辑模式 -->
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<n-space vertical :size="12">
|
<n-space vertical :size="12">
|
||||||
<n-form-item label="昵称" :show-feedback="false">
|
|
||||||
<n-input v-model:value="editNickname" placeholder="给客户端起个名字(可选)" style="max-width: 300px;" />
|
|
||||||
</n-form-item>
|
|
||||||
<n-card v-for="(rule, i) in editRules" :key="i" size="small">
|
<n-card v-for="(rule, i) in editRules" :key="i" size="small">
|
||||||
<n-space align="center" wrap>
|
<n-space align="center" wrap>
|
||||||
<n-form-item label="启用" :show-feedback="false">
|
<n-form-item label="启用" :show-feedback="false">
|
||||||
@@ -546,5 +571,18 @@ const savePluginConfig = async () => {
|
|||||||
</n-space>
|
</n-space>
|
||||||
</template>
|
</template>
|
||||||
</n-modal>
|
</n-modal>
|
||||||
|
|
||||||
|
<!-- 重命名模态框 -->
|
||||||
|
<n-modal v-model:show="showRenameModal" preset="card" title="重命名客户端" style="width: 400px;">
|
||||||
|
<n-form-item label="昵称" :show-feedback="false">
|
||||||
|
<n-input v-model:value="renameValue" placeholder="给客户端起个名字(可选)" />
|
||||||
|
</n-form-item>
|
||||||
|
<template #footer>
|
||||||
|
<n-space justify="end">
|
||||||
|
<n-button @click="showRenameModal = false">取消</n-button>
|
||||||
|
<n-button type="primary" @click="saveRename">保存</n-button>
|
||||||
|
</n-space>
|
||||||
|
</template>
|
||||||
|
</n-modal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user