mirror of
https://github.com/snltty/linker.git
synced 2025-12-24 12:38:04 +08:00
update
This commit is contained in:
@@ -3,3 +3,10 @@ import { sendWebsocketMsg } from './request'
|
||||
export const updateRelayConnect = (machineName) => {
|
||||
return sendWebsocketMsg('relay/Connect', machineName);
|
||||
}
|
||||
|
||||
export const getRelayTypes = () => {
|
||||
return sendWebsocketMsg('relay/gettypes');
|
||||
}
|
||||
export const updateRelaySetServers = (servers) => {
|
||||
return sendWebsocketMsg('relay/SetServers', servers);
|
||||
}
|
||||
@@ -3,3 +3,10 @@ import { sendWebsocketMsg } from './request'
|
||||
export const updateTunnelConnect = (machineName) => {
|
||||
return sendWebsocketMsg('tunnel/Connect', machineName);
|
||||
}
|
||||
|
||||
export const getTunnelTypes = () => {
|
||||
return sendWebsocketMsg('tunnel/gettypes');
|
||||
}
|
||||
export const updateTunnelSetServers = (servers) => {
|
||||
return sendWebsocketMsg('tunnel/SetServers', servers);
|
||||
}
|
||||
@@ -84,6 +84,10 @@ a.a-line {
|
||||
padding-left: .6rem;
|
||||
}
|
||||
|
||||
.pdl-10 {
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
.pdt-10 {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
154
cmonitor.web.client/src/components/status/RelayServers.vue
Normal file
154
cmonitor.web.client/src/components/status/RelayServers.vue
Normal file
@@ -0,0 +1,154 @@
|
||||
<template>
|
||||
<div>将按顺序使用主机,直到其中一个成功中继,秘钥用以确定服务器是否允许你进行中继</div>
|
||||
<el-table :data="state.list" border size="small" width="100%" height="300" @cell-dblclick="handleCellClick">
|
||||
<el-table-column prop="Name" label="名称">
|
||||
<template #default="scope">
|
||||
<template v-if="scope.row.NameEditing">
|
||||
<el-input autofocus size="small" v-model="scope.row.Name"
|
||||
@blur="handleEditBlur(scope.row, 'Name')"></el-input>
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ scope.row.Name }}
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="Type" label="类别" >
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.Type" placeholder="Select" size="small" @change="handleEditBlur(scope.row, 'Type')">
|
||||
<el-option v-for="item in state.types" :key="item.Value" :label="item.Name" :value="item.Value"/>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="Host" label="地址" width="120">
|
||||
<template #default="scope">
|
||||
<template v-if="scope.row.HostEditing">
|
||||
<el-input autofocus size="small" v-model="scope.row.Host" @blur="handleEditBlur(scope.row, 'Host')"></el-input>
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ scope.row.Host }}
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="SecretKey" label="秘钥" >
|
||||
<template #default="scope">
|
||||
<template v-if="scope.row.SecretKeyEditing">
|
||||
<el-input type="password" show-password size="small" v-model="scope.row.SecretKey" @blur="handleEditBlur(scope.row, 'SecretKey')"></el-input>
|
||||
</template>
|
||||
<template v-else></template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column property="Disabled" label="禁用" width="60">
|
||||
<template #default="scope">
|
||||
<el-switch v-model="scope.row.Disabled" @change="handleEditBlur(scope.row, 'Disabled')" inline-prompt active-text="是" inactive-text="否" style="--el-switch-on-color: red; --el-switch-off-color: #ddd" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="Sort" label="调序" width="104" fixed="right">
|
||||
<template #default="scope">
|
||||
<div>
|
||||
<el-button size="small" @click="handleSort(scope.$index,-1)">
|
||||
<el-icon><Top /></el-icon>
|
||||
</el-button>
|
||||
<el-button size="small" @click="handleSort(scope.$index,1)">
|
||||
<el-icon><Bottom /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="Oper" label="操作" width="104" fixed="right">
|
||||
<template #default="scope">
|
||||
<div>
|
||||
<el-popconfirm title="删除不可逆,是否确认?" @confirm="handleDel(scope.$index)">
|
||||
<template #reference>
|
||||
<el-button type="danger" size="small">
|
||||
<el-icon><Delete /></el-icon>
|
||||
</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
<el-button type="primary" size="small" @click="handleAdd(scope.$index)">
|
||||
<el-icon><Plus /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
<script>
|
||||
import { updateRelaySetServers,getRelayTypes } from '@/apis/relay';
|
||||
import { injectGlobalData } from '@/provide';
|
||||
import { computed, onMounted, reactive } from 'vue'
|
||||
export default {
|
||||
props:{
|
||||
data:{
|
||||
type:Array,
|
||||
default:[]
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const globalData = injectGlobalData();
|
||||
const state = reactive({
|
||||
list:props.data.sort((a,b)=>a.Disabled - b.Disabled),
|
||||
types:[]
|
||||
});
|
||||
|
||||
const _getRelayTypes = ()=>{
|
||||
getRelayTypes().then((res)=>{
|
||||
state.types = res;
|
||||
});
|
||||
}
|
||||
|
||||
const handleCellClick = (row, column) => {
|
||||
handleEdit(row, column.property);
|
||||
}
|
||||
const handleEdit = (row, p) => {
|
||||
state.list.forEach(c => {
|
||||
c[`NameEditing`] = false;
|
||||
c[`TypeEditing`] = false;
|
||||
c[`HostEditing`] = false;
|
||||
c[`SecretKeyEditing`] = false;
|
||||
})
|
||||
row[`${p}Editing`] = true;
|
||||
}
|
||||
const handleEditBlur = (row, p) => {
|
||||
row[`${p}Editing`] = false;
|
||||
handleSave();
|
||||
}
|
||||
|
||||
const handleDel = (index)=>{
|
||||
state.list.splice(index,1);
|
||||
handleSave();
|
||||
}
|
||||
const handleAdd = (index)=>{
|
||||
if(state.list.filter(c=>c.Host == '' || c.Name == '').length > 0){
|
||||
return;
|
||||
}
|
||||
state.list.splice(index+1,0,{Name:'',Host:'',Type:0,SecretKey:'snltty',Disabled:false});
|
||||
handleSave();
|
||||
}
|
||||
|
||||
const handleSort = (index,oper)=>{
|
||||
const current = state.list[index];
|
||||
const outher = state.list[index+oper];
|
||||
|
||||
if(current && outher){
|
||||
state.list[index+oper] = current;
|
||||
state.list[index] = outher;
|
||||
}
|
||||
handleSave(state.list);
|
||||
}
|
||||
|
||||
const handleSave = ()=>{
|
||||
state.list = state.list.slice().sort((a,b)=>a.Disabled - b.Disabled);
|
||||
updateRelaySetServers(state.list);
|
||||
}
|
||||
|
||||
onMounted(()=>{
|
||||
_getRelayTypes();
|
||||
});
|
||||
|
||||
return {state,handleCellClick,handleEditBlur,handleDel,handleAdd,handleSort}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="stylus" scoped>
|
||||
|
||||
</style>
|
||||
@@ -3,7 +3,7 @@
|
||||
<a href="javascript:;" @click="handleConfig">服务器 {{state.server}}</a>
|
||||
<span class="num">{{state.serverLength}}</span>
|
||||
</div>
|
||||
<el-dialog v-model="state.show" title="登入设置" width="600">
|
||||
<el-dialog v-model="state.show" title="登入设置" width="700">
|
||||
<div>
|
||||
<el-form :model="state.form" :rules="state.rules" label-width="6rem">
|
||||
<el-form-item label="" label-width="0">
|
||||
@@ -18,16 +18,16 @@
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item label="服务器" prop="servers">
|
||||
<el-form-item label-width="0">
|
||||
<el-tabs type="border-card" style="width:100%" v-model="state.tab">
|
||||
<el-tab-pane label="登入服务器" name="login">
|
||||
<Servers :data="state.servers"></Servers>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="中继服务器" name="relay">
|
||||
<Servers :data="state.relayServers"></Servers>
|
||||
<RelayServers :data="state.relayServers"></RelayServers>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="打洞服务器" name="hole">
|
||||
<Servers :data="state.holeServers"></Servers>
|
||||
<el-tab-pane label="公网端口服务器" name="hole">
|
||||
<TunnelServers :data="state.holeServers"></TunnelServers>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-form-item>
|
||||
@@ -49,8 +49,10 @@ import { injectGlobalData } from '@/provide';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { computed, reactive } from 'vue';
|
||||
import Servers from './Servers.vue'
|
||||
import RelayServers from './RelayServers.vue'
|
||||
import TunnelServers from './TunnelServers.vue'
|
||||
export default {
|
||||
components:{Servers},
|
||||
components:{Servers,RelayServers,TunnelServers},
|
||||
setup(props) {
|
||||
|
||||
const globalData = injectGlobalData();
|
||||
|
||||
@@ -1,29 +1,55 @@
|
||||
<template>
|
||||
<el-table :data="state.list" border size="small" width="100%" height="300">
|
||||
<el-table-column prop="Name" label="名称"></el-table-column>
|
||||
<el-table-column prop="Host" label="地址" ></el-table-column>
|
||||
<div>使用其中一条作为主机</div>
|
||||
<el-table :data="state.list" border size="small" width="100%" height="300" @cell-dblclick="handleCellClick">
|
||||
<el-table-column prop="Name" label="名称">
|
||||
<template #default="scope">
|
||||
<template v-if="scope.row.NameEditing">
|
||||
<el-input autofocus size="small" v-model="scope.row.Name"
|
||||
@blur="handleEditBlur(scope.row, 'Name')"></el-input>
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ scope.row.Name }}
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="Host" label="地址" >
|
||||
<template #default="scope">
|
||||
<template v-if="scope.row.HostEditing">
|
||||
<el-input autofocus size="small" v-model="scope.row.Host"
|
||||
@blur="handleEditBlur(scope.row, 'Host')"></el-input>
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ scope.row.Host }}
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="Oper" label="操作" width="150">
|
||||
<template #default="scope">
|
||||
<div>
|
||||
<el-popconfirm title="删除不可逆,是否确认?" @confirm="handleDel(scope.$index)">
|
||||
<template #reference>
|
||||
<el-button type="danger" size="small">
|
||||
<el-icon><Delete /></el-icon>
|
||||
</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
<el-button type="primary" size="small" @click="handleAdd(scope.$index)">
|
||||
<el-icon><Plus /></el-icon>
|
||||
</el-button>
|
||||
<template v-if="state.server != scope.row.Host">
|
||||
<el-button size="small" @click="handleUse(scope.$index)">
|
||||
<el-icon><Select /></el-icon>
|
||||
</el-button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-dialog v-model="state.showAdd" title="添加服务器" width="300" >
|
||||
<div>
|
||||
<el-form :model="state.formAdd" :rules="state.rulesAdd" label-width="6rem">
|
||||
<el-form-item label="名称" prop="name">
|
||||
<el-input v-model="state.formAdd.name" maxlength="12" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item label="地址" prop="host">
|
||||
<el-input v-model="state.formAdd.host" placeholder="ip/域名:端口" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer t-c">
|
||||
<el-button @click="state.showAdd = false" :loading="state.loading">取消</el-button>
|
||||
<el-button type="primary" @click="handleSaveAdd" :loading="state.loading">确定保存</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script>
|
||||
import { reactive } from 'vue'
|
||||
import { updateConfigSetServers } from '@/apis/signin';
|
||||
import { injectGlobalData } from '@/provide';
|
||||
import { computed, reactive } from 'vue'
|
||||
export default {
|
||||
props:{
|
||||
data:{
|
||||
@@ -32,44 +58,49 @@ export default {
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const globalData = injectGlobalData();
|
||||
const state = reactive({
|
||||
list:props.data,
|
||||
|
||||
showAdd:false,
|
||||
formAdd:{
|
||||
name:'',
|
||||
host:''
|
||||
},
|
||||
rulesAdd:{
|
||||
name:[
|
||||
{ required: true, message: '听填写', trigger: 'blur' },
|
||||
],
|
||||
host:[
|
||||
{ required: true, message: '听填写', trigger: 'blur' },
|
||||
]
|
||||
},
|
||||
server:computed(()=>globalData.value.config.Client.Server)
|
||||
});
|
||||
|
||||
const handleDel = (item)=>{
|
||||
const servers = state.list.filter(c=>c.Host != item.Host || c.Name != item.Name);
|
||||
const handleCellClick = (row, column) => {
|
||||
handleEdit(row, column.property);
|
||||
}
|
||||
const handleAdd = ()=>{
|
||||
state.showAdd = true;
|
||||
state.formAdd.name = '';
|
||||
state.formAdd.host = '';
|
||||
const handleEdit = (row, p) => {
|
||||
state.list.forEach(c => {
|
||||
c[`NameEditing`] = false;
|
||||
c[`HostEditing`] = false;
|
||||
})
|
||||
row[`${p}Editing`] = true;
|
||||
}
|
||||
const handleSaveAdd = ()=>{
|
||||
const servers = state.list || [];
|
||||
const name = state.formAdd.name.replace(/^\s|\s$/g,'');
|
||||
const host = state.formAdd.host.replace(/^\s|\s$/g,'');
|
||||
if(servers.filter(c=>c.Host == host).length > 0 || servers.filter(c=>c.Name == name).length > 0){
|
||||
ElMessage.error('已存在差不多相同的记录!');
|
||||
return;
|
||||
}
|
||||
servers.push({Name:name,Host:host});
|
||||
const handleEditBlur = (row, p) => {
|
||||
row[`${p}Editing`] = false;
|
||||
handleSave();
|
||||
}
|
||||
|
||||
return {state,handleDel,handleAdd,handleSaveAdd}
|
||||
const handleDel = (index)=>{
|
||||
state.list.splice(index,1);
|
||||
handleSave();
|
||||
}
|
||||
const handleAdd = (index)=>{
|
||||
if(state.list.filter(c=>c.Host == '' || c.Name == '').length > 0){
|
||||
return;
|
||||
}
|
||||
state.list.splice(index+1,0,{Name:'',Host:''});
|
||||
handleSave();
|
||||
}
|
||||
const handleUse = (index)=>{
|
||||
const temp = state.list[index];
|
||||
state.list[index] = state.list[0];
|
||||
state.list[0] = temp;
|
||||
handleSave();
|
||||
}
|
||||
const handleSave = ()=>{
|
||||
updateConfigSetServers(state.list);
|
||||
}
|
||||
|
||||
return {state,handleCellClick,handleEditBlur,handleDel,handleAdd,handleUse}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
145
cmonitor.web.client/src/components/status/TunnelServers.vue
Normal file
145
cmonitor.web.client/src/components/status/TunnelServers.vue
Normal file
@@ -0,0 +1,145 @@
|
||||
<template>
|
||||
<div>将按顺序通过所有主机获取外网端口,如何使用,交由打洞决定,默认打洞仅使用第一个</div>
|
||||
<el-table :data="state.list" border size="small" width="100%" height="300" @cell-dblclick="handleCellClick">
|
||||
<el-table-column prop="Name" label="名称">
|
||||
<template #default="scope">
|
||||
<template v-if="scope.row.NameEditing">
|
||||
<el-input autofocus size="small" v-model="scope.row.Name"
|
||||
@blur="handleEditBlur(scope.row, 'Name')"></el-input>
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ scope.row.Name }}
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="Type" label="类别" >
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.Type" placeholder="Select" size="small" @change="handleEditBlur(scope.row, 'Type')">
|
||||
<el-option v-for="item in state.types" :key="item.Value" :label="item.Name" :value="item.Value"/>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="Host" label="地址" width="120">
|
||||
<template #default="scope">
|
||||
<template v-if="scope.row.HostEditing">
|
||||
<el-input autofocus size="small" v-model="scope.row.Host" @blur="handleEditBlur(scope.row, 'Host')"></el-input>
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ scope.row.Host }}
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column property="Disabled" label="禁用" width="60">
|
||||
<template #default="scope">
|
||||
<el-switch v-model="scope.row.Disabled" @change="handleEditBlur(scope.row, 'Disabled')" inline-prompt active-text="是" inactive-text="否" style="--el-switch-on-color: red; --el-switch-off-color: #ddd" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="Sort" label="调序" width="104" fixed="right">
|
||||
<template #default="scope">
|
||||
<div>
|
||||
<el-button size="small" @click="handleSort(scope.$index,-1)">
|
||||
<el-icon><Top /></el-icon>
|
||||
</el-button>
|
||||
<el-button size="small" @click="handleSort(scope.$index,1)">
|
||||
<el-icon><Bottom /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="Oper" label="操作" width="104" fixed="right">
|
||||
<template #default="scope">
|
||||
<div>
|
||||
<el-popconfirm title="删除不可逆,是否确认?" @confirm="handleDel(scope.$index)">
|
||||
<template #reference>
|
||||
<el-button type="danger" size="small">
|
||||
<el-icon><Delete /></el-icon>
|
||||
</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
<el-button type="primary" size="small" @click="handleAdd(scope.$index)">
|
||||
<el-icon><Plus /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
<script>
|
||||
import { updateTunnelSetServers,getTunnelTypes } from '@/apis/tunnel';
|
||||
import { injectGlobalData } from '@/provide';
|
||||
import { computed, onMounted, reactive } from 'vue'
|
||||
export default {
|
||||
props:{
|
||||
data:{
|
||||
type:Array,
|
||||
default:[]
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const globalData = injectGlobalData();
|
||||
const state = reactive({
|
||||
list:props.data.sort((a,b)=>a.Disabled - b.Disabled),
|
||||
types:[]
|
||||
});
|
||||
|
||||
const _getTunnelTypes = ()=>{
|
||||
getTunnelTypes().then((res)=>{
|
||||
state.types = res;
|
||||
});
|
||||
}
|
||||
|
||||
const handleCellClick = (row, column) => {
|
||||
handleEdit(row, column.property);
|
||||
}
|
||||
const handleEdit = (row, p) => {
|
||||
state.list.forEach(c => {
|
||||
c[`NameEditing`] = false;
|
||||
c[`TypeEditing`] = false;
|
||||
c[`HostEditing`] = false;
|
||||
})
|
||||
row[`${p}Editing`] = true;
|
||||
}
|
||||
const handleEditBlur = (row, p) => {
|
||||
row[`${p}Editing`] = false;
|
||||
handleSave();
|
||||
}
|
||||
|
||||
const handleDel = (index)=>{
|
||||
state.list.splice(index,1);
|
||||
handleSave();
|
||||
}
|
||||
const handleAdd = (index)=>{
|
||||
if(state.list.filter(c=>c.Host == '' || c.Name == '').length > 0){
|
||||
return;
|
||||
}
|
||||
state.list.splice(index+1,0,{Name:'',Host:'',Type:0,Disabled:false});
|
||||
handleSave();
|
||||
}
|
||||
|
||||
const handleSort = (index,oper)=>{
|
||||
const current = state.list[index];
|
||||
const outher = state.list[index+oper];
|
||||
|
||||
if(current && outher){
|
||||
state.list[index+oper] = current;
|
||||
state.list[index] = outher;
|
||||
}
|
||||
handleSave(state.list);
|
||||
}
|
||||
|
||||
const handleSave = ()=>{
|
||||
state.list = state.list.slice().sort((a,b)=>a.Disabled - b.Disabled);
|
||||
updateTunnelSetServers(state.list);
|
||||
}
|
||||
|
||||
onMounted(()=>{
|
||||
_getTunnelTypes();
|
||||
});
|
||||
|
||||
return {state,handleCellClick,handleEditBlur,handleDel,handleAdd,handleSort}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="stylus" scoped>
|
||||
|
||||
</style>
|
||||
@@ -15,9 +15,14 @@ import 'element-plus/theme-chalk/display.css'
|
||||
import 'element-plus/theme-chalk/dark/css-vars.css'
|
||||
|
||||
import {
|
||||
ArrowDown,
|
||||
ArrowDown, Top, Bottom, Delete, Plus, Select
|
||||
} from '@element-plus/icons-vue'
|
||||
app.component(ArrowDown.name, ArrowDown);
|
||||
app.component(Top.name, Top);
|
||||
app.component(Bottom.name, Bottom);
|
||||
app.component(Delete.name, Delete);
|
||||
app.component(Plus.name, Plus);
|
||||
app.component(Select.name, Select);
|
||||
|
||||
|
||||
app.use(ElementPlus, { size: 'default' }).use(router).mount('#app');
|
||||
|
||||
@@ -59,19 +59,18 @@
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column property="Started" label="启动状态" width="80">
|
||||
<el-table-column property="Started" label="状态" width="60">
|
||||
<template #default="scope">
|
||||
<el-switch v-model="scope.row.Started" @change="handleStartChange(scope.row)" inline-prompt
|
||||
active-text="是" inactive-text="否" />
|
||||
</template>
|
||||
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="66">
|
||||
<el-table-column label="操作" width="54">
|
||||
<template #default="scope">
|
||||
<el-popconfirm confirm-button-text="确认" cancel-button-text="取消" title="删除不可逆,是否确认?"
|
||||
@confirm="handleDel(scope.row.ID)">
|
||||
<template #reference>
|
||||
<el-button type="danger" size="small">删除</el-button>
|
||||
<el-button type="danger" size="small"><el-icon><Delete /></el-icon></el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</template>
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
<el-popconfirm v-if="scope.row.showDel" confirm-button-text="确认"
|
||||
cancel-button-text="取消" title="删除不可逆,是否确认?" @confirm="handleDel(scope.row.MachineName)">
|
||||
<template #reference>
|
||||
<el-button type="danger" size="small">删除</el-button>
|
||||
<el-button type="danger" size="small"><el-icon><Delete /></el-icon></el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</template>
|
||||
@@ -153,6 +153,8 @@ export default {
|
||||
item.Version = res.List[j].Version;
|
||||
item.LastSignIn = res.List[j].LastSignIn;
|
||||
item.Args = res.List[j].Args;
|
||||
item.showTunnel = machineName.value != res.List[j].MachineName;
|
||||
item.showForward = machineName.value != res.List[j].MachineName;
|
||||
item.showDel = machineName.value != res.List[j].MachineName && res.List[j].Connected == false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,9 +30,9 @@
|
||||
<div class="flex-1">
|
||||
<el-input v-model="state.ruleForm.LanIPs[index]" />
|
||||
</div>
|
||||
<div>
|
||||
<el-button type="danger" @click="handleDel(index)">删除</el-button>
|
||||
<el-button type="primary" @click="handleAdd(index)">添加</el-button>
|
||||
<div class="pdl-10">
|
||||
<el-button type="danger" @click="handleDel(index)"><el-icon><Delete /></el-icon></el-button>
|
||||
<el-button type="primary" @click="handleAdd(index)"><el-icon><Plus /></el-icon></el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -10,9 +10,17 @@ namespace cmonitor.config
|
||||
|
||||
public sealed partial class ConfigClientInfo
|
||||
{
|
||||
public ClientServerInfo[] Servers { get; set; } = new ClientServerInfo[] {
|
||||
private ClientServerInfo[] servers = new ClientServerInfo[] {
|
||||
new ClientServerInfo{ Name="默认", Host=new IPEndPoint(IPAddress.Loopback, 1802).ToString() }
|
||||
};
|
||||
public ClientServerInfo[] Servers
|
||||
{
|
||||
get => servers; set
|
||||
{
|
||||
servers = value;
|
||||
if (value.Length > 0) Server = value.FirstOrDefault().Host;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private string name = Dns.GetHostName().SubStr(0, 12);
|
||||
@@ -36,7 +44,7 @@ namespace cmonitor.config
|
||||
|
||||
public sealed class ClientServerInfo
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Host { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string Host { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,11 @@ namespace cmonitor.plugins.relay
|
||||
RelayTest();
|
||||
}
|
||||
|
||||
public List<RelayCompactTypeInfo> GetTypes(ApiControllerParamsInfo param)
|
||||
{
|
||||
return relayTransfer.GetTypes();
|
||||
}
|
||||
|
||||
public bool SetServers(ApiControllerParamsInfo param)
|
||||
{
|
||||
config.Data.Client.Relay.Servers = param.Content.DeJson<RelayCompactInfo[]>();
|
||||
|
||||
@@ -32,6 +32,11 @@ namespace cmonitor.plugins.relay
|
||||
Logger.Instance.Warning($"load relay transport:{string.Join(",", transports.Select(c => c.Name))}");
|
||||
}
|
||||
|
||||
public List<RelayCompactTypeInfo> GetTypes()
|
||||
{
|
||||
return transports.Select(c => new RelayCompactTypeInfo { Value = c.Type, Name = c.Type.ToString() }).Distinct(new RelayCompactTypeInfoEqualityComparer()).ToList();
|
||||
}
|
||||
|
||||
public void SetConnectedCallback(string transactionId, Action<ITunnelConnection> callback)
|
||||
{
|
||||
if (OnConnected.TryGetValue(transactionId, out List<Action<ITunnelConnection>> callbacks) == false)
|
||||
@@ -52,7 +57,7 @@ namespace cmonitor.plugins.relay
|
||||
public async Task<ITunnelConnection> ConnectAsync(string remoteMachineName, string transactionId)
|
||||
{
|
||||
IEnumerable<ITransport> _transports = transports.OrderBy(c => c.Type);
|
||||
foreach (RelayCompactInfo item in config.Data.Client.Relay.Servers.Where(c => c.Disabled == false))
|
||||
foreach (RelayCompactInfo item in config.Data.Client.Relay.Servers.Where(c => c.Disabled == false && string.IsNullOrWhiteSpace(c.Host) == false))
|
||||
{
|
||||
ITransport transport = _transports.FirstOrDefault(c => c.Type == item.Type);
|
||||
if (transport == null)
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
namespace cmonitor.config
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace cmonitor.config
|
||||
{
|
||||
public partial class ConfigClientInfo
|
||||
{
|
||||
@@ -21,10 +24,10 @@
|
||||
|
||||
public sealed class RelayCompactInfo
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public RelayCompactType Type { get; set; } = RelayCompactType.Self;
|
||||
public string SecretKey { get; set; } = "snltty";
|
||||
public string Host { get; set; }
|
||||
public string Host { get; set; } = string.Empty;
|
||||
public bool Disabled { get; set; }
|
||||
}
|
||||
|
||||
@@ -32,4 +35,23 @@
|
||||
{
|
||||
Self = 0,
|
||||
}
|
||||
|
||||
public sealed class RelayCompactTypeInfo
|
||||
{
|
||||
public RelayCompactType Value { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
public sealed class RelayCompactTypeInfoEqualityComparer : IEqualityComparer<RelayCompactTypeInfo>
|
||||
{
|
||||
public bool Equals(RelayCompactTypeInfo x, RelayCompactTypeInfo y)
|
||||
{
|
||||
return x.Value == y.Value;
|
||||
}
|
||||
|
||||
public int GetHashCode([DisallowNull] RelayCompactTypeInfo obj)
|
||||
{
|
||||
return obj.Value.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace cmonitor.plugins.relay.transport
|
||||
Socket socket = new Socket(relayInfo.Server.AddressFamily, SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
|
||||
socket.Reuse(true);
|
||||
socket.IPv6Only(relayInfo.Server.AddressFamily, false);
|
||||
await socket.ConnectAsync(relayInfo.Server).WaitAsync(TimeSpan.FromSeconds(2));
|
||||
await socket.ConnectAsync(relayInfo.Server).WaitAsync(TimeSpan.FromMilliseconds(500));
|
||||
|
||||
IConnection connection = tcpServer.BindReceive(socket);
|
||||
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
|
||||
@@ -65,7 +65,7 @@ namespace cmonitor.plugins.relay.transport
|
||||
Socket socket = new Socket(relayInfo.Server.AddressFamily, SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
|
||||
socket.Reuse(true);
|
||||
socket.IPv6Only(relayInfo.Server.AddressFamily, false);
|
||||
await socket.ConnectAsync(relayInfo.Server).WaitAsync(TimeSpan.FromSeconds(2));
|
||||
await socket.ConnectAsync(relayInfo.Server).WaitAsync(TimeSpan.FromMilliseconds(500));
|
||||
|
||||
IConnection connection = tcpServer.BindReceive(socket);
|
||||
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
|
||||
|
||||
@@ -58,17 +58,33 @@ namespace cmonitor.plugins.signin
|
||||
}
|
||||
public void Set(ApiControllerParamsInfo param)
|
||||
{
|
||||
string name = config.Data.Client.Name;
|
||||
string gid = config.Data.Client.GroupId;
|
||||
|
||||
ConfigSetInfo info = param.Content.DeJson<ConfigSetInfo>();
|
||||
config.Data.Client.Name = info.Name;
|
||||
config.Data.Client.GroupId = info.GroupId;
|
||||
config.Save();
|
||||
clientSignInTransfer.SignOut();
|
||||
_ = clientSignInTransfer.SignIn();
|
||||
|
||||
if(name != config.Data.Client.Name || gid != config.Data.Client.GroupId)
|
||||
{
|
||||
clientSignInTransfer.SignOut();
|
||||
_ = clientSignInTransfer.SignIn();
|
||||
}
|
||||
}
|
||||
public bool SetServers(ApiControllerParamsInfo param)
|
||||
{
|
||||
string server = config.Data.Client.Server;
|
||||
|
||||
config.Data.Client.Servers = param.Content.DeJson<ClientServerInfo[]>();
|
||||
config.Save();
|
||||
|
||||
if(server != config.Data.Client.Server)
|
||||
{
|
||||
clientSignInTransfer.SignOut();
|
||||
_ = clientSignInTransfer.SignIn();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using cmonitor.client.capi;
|
||||
using cmonitor.client.tunnel;
|
||||
using cmonitor.config;
|
||||
using cmonitor.plugins.tunnel.compact;
|
||||
using common.libs;
|
||||
using common.libs.api;
|
||||
using common.libs.extends;
|
||||
@@ -12,13 +13,22 @@ namespace cmonitor.plugins.tunnel
|
||||
{
|
||||
private readonly TunnelTransfer tunnelTransfer;
|
||||
private readonly Config config;
|
||||
public TunnelApiController(TunnelTransfer tunnelTransfer, Config config)
|
||||
private readonly CompactTransfer compactTransfer;
|
||||
|
||||
public TunnelApiController(TunnelTransfer tunnelTransfer, Config config, CompactTransfer compactTransfer)
|
||||
{
|
||||
this.tunnelTransfer = tunnelTransfer;
|
||||
this.config = config;
|
||||
this.compactTransfer = compactTransfer;
|
||||
|
||||
TunnelTest();
|
||||
}
|
||||
|
||||
public List<TunnelCompactTypeInfo> GetTypes(ApiControllerParamsInfo param)
|
||||
{
|
||||
return compactTransfer.GetTypes();
|
||||
}
|
||||
|
||||
public bool SetServers(ApiControllerParamsInfo param)
|
||||
{
|
||||
config.Data.Client.Tunnel.Servers = param.Content.DeJson<TunnelCompactInfo[]>();
|
||||
|
||||
@@ -49,6 +49,23 @@ namespace cmonitor.plugins.tunnel
|
||||
Logger.Instance.Warning($"load tunnel transport:{string.Join(",", transports.Select(c => c.Name))}");
|
||||
}
|
||||
|
||||
public void SetConnectedCallback(string transactionId, Action<ITunnelConnection> callback)
|
||||
{
|
||||
if (OnConnected.TryGetValue(transactionId, out List<Action<ITunnelConnection>> callbacks) == false)
|
||||
{
|
||||
callbacks = new List<Action<ITunnelConnection>>();
|
||||
OnConnected[transactionId] = callbacks;
|
||||
}
|
||||
callbacks.Add(callback);
|
||||
}
|
||||
public void RemoveConnectedCallback(string transactionId, Action<ITunnelConnection> callback)
|
||||
{
|
||||
if (OnConnected.TryGetValue(transactionId, out List<Action<ITunnelConnection>> callbacks))
|
||||
{
|
||||
callbacks.Remove(callback);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ITunnelConnection> ConnectAsync(string remoteMachineName, string transactionId)
|
||||
{
|
||||
IEnumerable<ITransport> _transports = transports.OrderBy(c => c.ProtocolType);
|
||||
@@ -187,22 +204,7 @@ namespace cmonitor.plugins.tunnel
|
||||
}
|
||||
|
||||
|
||||
public void SetConnectedCallback(string transactionId, Action<ITunnelConnection> callback)
|
||||
{
|
||||
if (OnConnected.TryGetValue(transactionId, out List<Action<ITunnelConnection>> callbacks) == false)
|
||||
{
|
||||
callbacks = new List<Action<ITunnelConnection>>();
|
||||
OnConnected[transactionId] = callbacks;
|
||||
}
|
||||
callbacks.Add(callback);
|
||||
}
|
||||
public void RemoveConnectedCallback(string transactionId, Action<ITunnelConnection> callback)
|
||||
{
|
||||
if (OnConnected.TryGetValue(transactionId, out List<Action<ITunnelConnection>> callbacks))
|
||||
{
|
||||
callbacks.Remove(callback);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void OnConnecting(TunnelTransportInfo tunnelTransportInfo)
|
||||
{
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace cmonitor.plugins.tunnel.compact
|
||||
Socket socket = new Socket(server.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||
socket.Reuse(true);
|
||||
socket.IPv6Only(server.AddressFamily, false);
|
||||
await socket.ConnectAsync(server).WaitAsync(TimeSpan.FromSeconds(2));
|
||||
await socket.ConnectAsync(server).WaitAsync(TimeSpan.FromMilliseconds(500));
|
||||
|
||||
IConnection connection = tcpServer.BindReceive(socket);
|
||||
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap { Connection = connection, MessengerId = (ushort)TunnelMessengerIds.ExternalIP });
|
||||
@@ -53,7 +53,7 @@ namespace cmonitor.plugins.tunnel.compact
|
||||
try
|
||||
{
|
||||
await udpClient.SendAsync(new byte[1] { 0 }, server);
|
||||
UdpReceiveResult result = await udpClient.ReceiveAsync().WaitAsync(TimeSpan.FromSeconds(500));
|
||||
UdpReceiveResult result = await udpClient.ReceiveAsync().WaitAsync(TimeSpan.FromMilliseconds(500));
|
||||
if (result.Buffer.Length == 0)
|
||||
{
|
||||
return null;
|
||||
|
||||
@@ -28,6 +28,12 @@ namespace cmonitor.plugins.tunnel.compact
|
||||
Logger.Instance.Warning($"load tunnel compacts:{string.Join(",", compacts.Select(c => c.Name))}");
|
||||
}
|
||||
|
||||
public List<TunnelCompactTypeInfo> GetTypes()
|
||||
{
|
||||
return compacts.Select(c => new TunnelCompactTypeInfo { Value = c.Type, Name = c.Type.ToString() }).Distinct(new TunnelCompactTypeInfoEqualityComparer()).ToList();
|
||||
}
|
||||
|
||||
|
||||
public async Task<TunnelCompactIPEndPoint[]> GetExternalIPAsync(TunnelProtocolType protocolType)
|
||||
{
|
||||
TunnelCompactIPEndPoint[] endpoints = new TunnelCompactIPEndPoint[config.Data.Client.Tunnel.Servers.Length];
|
||||
@@ -35,7 +41,7 @@ namespace cmonitor.plugins.tunnel.compact
|
||||
for (int i = 0; i < config.Data.Client.Tunnel.Servers.Length; i++)
|
||||
{
|
||||
TunnelCompactInfo item = config.Data.Client.Tunnel.Servers[i];
|
||||
if (item.Disabled) continue;
|
||||
if (item.Disabled || string.IsNullOrWhiteSpace(item.Host)) continue;
|
||||
ICompact compact = compacts.FirstOrDefault(c => c.Type == item.Type);
|
||||
if (compact == null) continue;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Net;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Net;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace cmonitor.config
|
||||
@@ -20,9 +21,9 @@ namespace cmonitor.config
|
||||
|
||||
public sealed class TunnelCompactInfo
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public TunnelCompactType Type { get; set; }
|
||||
public string Host { get; set; }
|
||||
public string Host { get; set; } = string.Empty;
|
||||
public bool Disabled { get; set; }
|
||||
}
|
||||
|
||||
@@ -30,4 +31,23 @@ namespace cmonitor.config
|
||||
{
|
||||
Self = 0
|
||||
}
|
||||
|
||||
public sealed class TunnelCompactTypeInfo
|
||||
{
|
||||
public TunnelCompactType Value { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
public sealed class TunnelCompactTypeInfoEqualityComparer : IEqualityComparer<TunnelCompactTypeInfo>
|
||||
{
|
||||
public bool Equals(TunnelCompactTypeInfo x, TunnelCompactTypeInfo y)
|
||||
{
|
||||
return x.Value == y.Value;
|
||||
}
|
||||
|
||||
public int GetHashCode([DisallowNull] TunnelCompactTypeInfo obj)
|
||||
{
|
||||
return obj.Value.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ using cmonitor.plugins.tuntap.vea;
|
||||
using cmonitor.server;
|
||||
using common.libs;
|
||||
using MemoryPack;
|
||||
using SharpDX;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Net;
|
||||
@@ -64,11 +63,7 @@ namespace cmonitor.plugins.tuntap
|
||||
OnChange();
|
||||
try
|
||||
{
|
||||
bool result = await tuntapVea.Run(tuntapProxy.LocalEndpoint.Port);
|
||||
if (result)
|
||||
{
|
||||
await tuntapVea.SetIp(config.Data.Client.Tuntap.IP);
|
||||
}
|
||||
bool result = await tuntapVea.Run(tuntapProxy.LocalEndpoint.Port, config.Data.Client.Tuntap.IP);
|
||||
config.Data.Client.Tuntap.Running = Status == TuntapStatus.Running;
|
||||
config.Save();
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace cmonitor.plugins.tuntap.vea
|
||||
{
|
||||
public bool Running { get; }
|
||||
|
||||
public Task<bool> Run(int proxyPort);
|
||||
public Task<bool> Run(int proxyPort,IPAddress ip);
|
||||
public Task<bool> SetIp(IPAddress ip);
|
||||
public void Kill();
|
||||
|
||||
|
||||
@@ -19,10 +19,10 @@ namespace cmonitor.plugins.tuntap.vea
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<bool> Run(int proxyPort)
|
||||
public async Task<bool> Run(int proxyPort, IPAddress ip)
|
||||
{
|
||||
CommandHelper.Linux(string.Empty, new string[] { $"ip tuntap add mode tun dev {veaName}" });
|
||||
|
||||
await SetIp(ip);
|
||||
string str = CommandHelper.Linux(string.Empty, new string[] { $"ifconfig" });
|
||||
if (str.Contains(veaName) == false)
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace cmonitor.plugins.tuntap.vea
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<bool> Run(int proxyPort)
|
||||
public async Task<bool> Run(int proxyPort, IPAddress ip)
|
||||
{
|
||||
interfaceOsx = GetOsxInterfaceNum();
|
||||
try
|
||||
@@ -42,6 +42,8 @@ namespace cmonitor.plugins.tuntap.vea
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
|
||||
await SetIp(ip);
|
||||
|
||||
return string.IsNullOrWhiteSpace(interfaceOsx) == false;
|
||||
}
|
||||
public async Task<bool> SetIp(IPAddress ip)
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace cmonitor.plugins.tuntap.vea
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<bool> Run(int proxyPort)
|
||||
public async Task<bool> Run(int proxyPort, IPAddress ip)
|
||||
{
|
||||
string command = $" -device {veaName} -proxy socks5://127.0.0.1:{proxyPort} -loglevel silent";
|
||||
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
@@ -52,7 +52,7 @@ namespace cmonitor.plugins.tuntap.vea
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
await SetIp(ip);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user