mirror of
https://github.com/snltty/linker.git
synced 2025-10-15 21:50:42 +08:00
sync
This commit is contained in:
@@ -42,6 +42,7 @@ namespace linker.tunnel
|
||||
}
|
||||
|
||||
var transportItems = tunnelAdapter.GetTunnelTransports();
|
||||
var names = transportItems.Select(c => c.Name);
|
||||
transportItems = transportItems.Concat(transports.Select(c => new TunnelTransportItemInfo
|
||||
{
|
||||
Label = c.Label,
|
||||
@@ -74,8 +75,7 @@ namespace linker.tunnel
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
tunnelAdapter.SetTunnelTransports(transportItems);
|
||||
tunnelAdapter.SetTunnelTransports(transportItems, names.SequenceEqual(transportItems.Select(c => c.Name)) == false);
|
||||
|
||||
LoggerHelper.Instance.Warning($"load tunnel transport:{string.Join(",", transports.Select(c => c.Name))}");
|
||||
LoggerHelper.Instance.Warning($"used tunnel transport:{string.Join(",", transportItems.Where(c => c.Disabled == false).Select(c => c.Name))}");
|
||||
@@ -136,7 +136,7 @@ namespace linker.tunnel
|
||||
|
||||
foreach (var wanPortProtocol in tunnelAdapter.GetTunnelWanPortProtocols().Where(c => c.Disabled == false && string.IsNullOrWhiteSpace(c.Host) == false))
|
||||
{
|
||||
|
||||
|
||||
//这个打洞协议不支持这个外网端口协议
|
||||
if ((transport.AllowWanPortProtocolType & wanPortProtocol.ProtocolType) != wanPortProtocol.ProtocolType)
|
||||
{
|
||||
|
@@ -26,7 +26,7 @@ namespace linker.tunnel.adapter
|
||||
/// 保存外网端口协议列表
|
||||
/// </summary>
|
||||
/// <param name="compacts"></param>
|
||||
public void SetTunnelWanPortProtocols(List<TunnelWanPortInfo> protocols);
|
||||
public void SetTunnelWanPortProtocols(List<TunnelWanPortInfo> protocols,bool updateVersion);
|
||||
|
||||
/// <summary>
|
||||
/// 获取打洞协议列表
|
||||
@@ -37,7 +37,7 @@ namespace linker.tunnel.adapter
|
||||
/// 保存打洞协议列表
|
||||
/// </summary>
|
||||
/// <param name="transports"></param>
|
||||
public void SetTunnelTransports(List<TunnelTransportItemInfo> transports);
|
||||
public void SetTunnelTransports(List<TunnelTransportItemInfo> transports, bool updateVersion);
|
||||
|
||||
/// <summary>
|
||||
/// 获取本地网络信息
|
||||
|
@@ -14,6 +14,7 @@ namespace linker.tunnel.wanport
|
||||
|
||||
public TunnelWanPortTransfer()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@@ -10,6 +10,9 @@ export const removeForwardConnection = (id) => {
|
||||
export const getForwardInfo = () => {
|
||||
return sendWebsocketMsg('forwardclient/get');
|
||||
}
|
||||
export const getForwardRemoteInfo = (data) => {
|
||||
return sendWebsocketMsg('forwardclient/getremote', data);
|
||||
}
|
||||
export const getForwardIpv4 = () => {
|
||||
return sendWebsocketMsg('forwardclient/bindips');
|
||||
}
|
||||
|
5
linker.web/src/apis/running.js
Normal file
5
linker.web/src/apis/running.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import { sendWebsocketMsg } from './request'
|
||||
|
||||
export const updateVersion = (data) => {
|
||||
return sendWebsocketMsg('RunningConfig/UpdateVersion', data);
|
||||
}
|
@@ -9,6 +9,9 @@ export const setSForwardSecretKey = (data) => {
|
||||
export const getSForwardInfo = () => {
|
||||
return sendWebsocketMsg('sforwardclient/get');
|
||||
}
|
||||
export const getSForwardRemoteInfo = (data) => {
|
||||
return sendWebsocketMsg('sforwardclient/getremote', data);
|
||||
}
|
||||
export const removeSForwardInfo = (id) => {
|
||||
return sendWebsocketMsg('sforwardclient/remove', id);
|
||||
}
|
||||
|
@@ -16,6 +16,9 @@ export const getSignInfo = () => {
|
||||
export const getSignInList = (data) => {
|
||||
return sendWebsocketMsg('signInclient/List', data);
|
||||
}
|
||||
export const getSignInIds = (data) => {
|
||||
return sendWebsocketMsg('signInclient/ids', data);
|
||||
}
|
||||
export const signInDel = (machineId) => {
|
||||
return sendWebsocketMsg('signInclient/del', machineId);
|
||||
}
|
||||
|
@@ -304,14 +304,11 @@ span.split-pad10 {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
.el-table--border,
|
||||
.el-table--group,
|
||||
.el-table-filter,
|
||||
.el-table td,
|
||||
.el-table th.is-leaf {
|
||||
border-color: var(--main-border-color);
|
||||
.el-table thead.is-group th.el-table__cell {
|
||||
background: var(--el-table-header-bg-color) !important;
|
||||
}
|
||||
|
||||
|
||||
.el-pagination.is-background .el-pager li:not(.disabled).active {
|
||||
background-color: var(--main-color);
|
||||
}
|
||||
|
@@ -20,105 +20,16 @@
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog class="options-center" title="管理接口" destroy-on-close v-model="showPort" center :show-close="false"
|
||||
:close-on-click-modal="false" align-center width="200">
|
||||
<div class="port-wrap t-c">
|
||||
<div>
|
||||
接口 : <el-input v-model="state.api" style="width:70%"></el-input>
|
||||
</div>
|
||||
<div class="pdt-10">
|
||||
秘钥 : <el-input type="password" v-model="state.psd" style="width:70%"></el-input>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button type="success" @click="handleConnect" plain>确 定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { computed, onMounted, reactive, watch } from 'vue';
|
||||
import { initWebsocket, subWebsocketState,closeWebsocket } from '../apis/request'
|
||||
import { getConfig,getSignInfo } from '../apis/signin'
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { injectGlobalData } from '../provide';
|
||||
import {Tools,StarFilled,WarnTriangleFilled} from '@element-plus/icons-vue'
|
||||
export default {
|
||||
components:{Tools,StarFilled,WarnTriangleFilled},
|
||||
setup() {
|
||||
|
||||
const globalData = injectGlobalData();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
const queryCache = JSON.parse(localStorage.getItem('api-cache') || JSON.stringify({api:`${window.location.hostname}:1803`,psd:'snltty',groupid:'snltty'}));
|
||||
const state = reactive({
|
||||
api:queryCache.api,
|
||||
psd:queryCache.psd,
|
||||
groupid:globalData.value.groupid || queryCache.groupid,
|
||||
showPort: false
|
||||
});
|
||||
const showPort = computed(() => globalData.value.connected == false && state.showPort);
|
||||
|
||||
const handleConnect = () => {
|
||||
globalData.value.groupid = state.groupid;
|
||||
queryCache.api = state.api;
|
||||
queryCache.psd = state.psd;
|
||||
queryCache.groupid = state.groupid;
|
||||
localStorage.setItem('api-cache',JSON.stringify(queryCache));
|
||||
|
||||
closeWebsocket();
|
||||
//initWebsocket(`ws://192.168.1.18:1803`,state.psd);
|
||||
initWebsocket(`ws://${state.api}`,state.psd);
|
||||
}
|
||||
|
||||
const _getConfig = ()=>{
|
||||
getConfig().then((res)=>{
|
||||
globalData.value.config.Common = res.Common;
|
||||
globalData.value.config.Client = res.Client;
|
||||
globalData.value.config.Running = res.Running;
|
||||
globalData.value.configed = true;
|
||||
setTimeout(()=>{
|
||||
_getConfig();
|
||||
},1000);
|
||||
}).catch((err)=>{
|
||||
setTimeout(()=>{
|
||||
_getConfig();
|
||||
},1000);
|
||||
});
|
||||
}
|
||||
const _getSignInfoInfo = ()=>{
|
||||
getSignInfo().then((res)=>{
|
||||
globalData.value.signin.Connected = res.Connected;
|
||||
globalData.value.signin.Connecting = res.Connecting;
|
||||
globalData.value.signin.Version = res.Version;
|
||||
setTimeout(()=>{
|
||||
_getSignInfoInfo();
|
||||
},1000);
|
||||
}).catch((err)=>{
|
||||
setTimeout(()=>{
|
||||
_getSignInfoInfo();
|
||||
},1000);
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
setTimeout(() => { state.showPort = true; }, 100);
|
||||
subWebsocketState((state) => { if (state) {
|
||||
_getConfig();
|
||||
_getSignInfoInfo();
|
||||
}});
|
||||
router.isReady().then(()=>{
|
||||
state.api = route.query.api ?`${window.location.hostname}:${route.query.api}` : state.api;
|
||||
state.psd = route.query.psd || state.psd;
|
||||
state.groupid = route.query.groupid || state.groupid;
|
||||
handleConnect();
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
state, showPort, handleConnect
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,20 +1,35 @@
|
||||
<template>
|
||||
<div class="status-api-wrap" :class="{connected:connected}">
|
||||
<el-popconfirm confirm-button-text="是" cancel-button-text="否" title="确定清楚连接信息并刷新吗?" @confirm="handleResetConnect" >
|
||||
<el-popconfirm confirm-button-text="清除" cancel-button-text="更改" title="确定你的惭怍?" @cancel="handleShow" @confirm="handleResetConnect" >
|
||||
<template #reference>
|
||||
<a href="javascript:;" >
|
||||
<el-icon size="16"><Tools /></el-icon>
|
||||
<template v-if="connected">管理接口</template>
|
||||
<template v-else>管理接口</template>
|
||||
管理接口
|
||||
</a>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
<el-dialog class="options-center" title="管理接口" destroy-on-close v-model="showPort" center :show-close="false"
|
||||
:close-on-click-modal="false" align-center width="200">
|
||||
<div class="port-wrap t-c">
|
||||
<div>
|
||||
接口 : <el-input v-model="state.api" style="width:70%"></el-input>
|
||||
</div>
|
||||
<div class="pdt-10">
|
||||
秘钥 : <el-input type="password" v-model="state.psd" style="width:70%"></el-input>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button type="success" @click="handleConnect1" plain>确 定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import {computed} from 'vue'
|
||||
import {useRoute,useRouter} from 'vue-router'
|
||||
import {injectGlobalData} from '../../provide'
|
||||
import { computed, onMounted, reactive } from 'vue';
|
||||
import { initWebsocket, subWebsocketState,closeWebsocket } from '../../apis/request'
|
||||
import { getConfig,getSignInfo } from '../../apis/signin'
|
||||
import {Tools} from '@element-plus/icons-vue'
|
||||
export default {
|
||||
components:{Tools},
|
||||
@@ -24,13 +39,87 @@ export default {
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
const defaultInfo = {api:`${window.location.hostname}:1803`,psd:'snltty'};
|
||||
const handleResetConnect = () => {
|
||||
localStorage.setItem('api-cache', '');
|
||||
router.push({name:route.name});
|
||||
window.location.reload();
|
||||
}
|
||||
const queryCache = JSON.parse(localStorage.getItem('api-cache') || JSON.stringify(defaultInfo));
|
||||
const state = reactive({
|
||||
api:queryCache.api,
|
||||
psd:queryCache.psd,
|
||||
groupid:globalData.value.groupid || queryCache.groupid,
|
||||
showPort: false
|
||||
});
|
||||
const showPort = computed(() => globalData.value.connected == false && state.showPort);
|
||||
|
||||
return {connected,handleResetConnect};
|
||||
const handleConnect = () => {
|
||||
globalData.value.groupid = state.groupid;
|
||||
queryCache.api = state.api;
|
||||
queryCache.psd = state.psd;
|
||||
queryCache.groupid = state.groupid;
|
||||
localStorage.setItem('api-cache',JSON.stringify(queryCache));
|
||||
|
||||
closeWebsocket();
|
||||
initWebsocket(`ws://${state.api}`,state.psd);
|
||||
}
|
||||
const handleConnect1 = ()=>{
|
||||
handleConnect();
|
||||
window.location.reload();
|
||||
}
|
||||
const handleShow = ()=>{
|
||||
//state.showPort = true;
|
||||
closeWebsocket();
|
||||
initWebsocket(`ws://${window.location.hostname}:12345`,state.psd);
|
||||
}
|
||||
|
||||
const _getConfig = ()=>{
|
||||
getConfig().then((res)=>{
|
||||
globalData.value.config.Common = res.Common;
|
||||
globalData.value.config.Client = res.Client;
|
||||
globalData.value.config.Running = res.Running;
|
||||
globalData.value.configed = true;
|
||||
setTimeout(()=>{
|
||||
_getConfig();
|
||||
},1000);
|
||||
}).catch((err)=>{
|
||||
setTimeout(()=>{
|
||||
_getConfig();
|
||||
},1000);
|
||||
});
|
||||
}
|
||||
const _getSignInfoInfo = ()=>{
|
||||
getSignInfo().then((res)=>{
|
||||
globalData.value.signin.Connected = res.Connected;
|
||||
globalData.value.signin.Connecting = res.Connecting;
|
||||
globalData.value.signin.Version = res.Version;
|
||||
setTimeout(()=>{
|
||||
_getSignInfoInfo();
|
||||
},1000);
|
||||
}).catch((err)=>{
|
||||
setTimeout(()=>{
|
||||
_getSignInfoInfo();
|
||||
},1000);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
setTimeout(() => { state.showPort = true; }, 100);
|
||||
subWebsocketState((state) => { if (state) {
|
||||
_getConfig();
|
||||
_getSignInfoInfo();
|
||||
}});
|
||||
router.isReady().then(()=>{
|
||||
state.api = route.query.api ?`${window.location.hostname}:${route.query.api}` : state.api;
|
||||
state.psd = route.query.psd || state.psd;
|
||||
state.groupid = route.query.groupid || state.groupid;
|
||||
handleConnect();
|
||||
});
|
||||
});
|
||||
|
||||
return { state, showPort, handleConnect1,connected,handleShow,handleResetConnect};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@@ -15,7 +15,7 @@ import 'element-plus/theme-chalk/display.css'
|
||||
import 'element-plus/theme-chalk/dark/css-vars.css'
|
||||
|
||||
import {
|
||||
ArrowDown, Top, Bottom, Delete, Plus, Select, Refresh
|
||||
ArrowDown, Top, Bottom, Delete, Plus, Select, Refresh, Search
|
||||
} from '@element-plus/icons-vue'
|
||||
app.component(ArrowDown.name, ArrowDown);
|
||||
app.component(Top.name, Top);
|
||||
@@ -24,6 +24,7 @@ app.component(Delete.name, Delete);
|
||||
app.component(Plus.name, Plus);
|
||||
app.component(Select.name, Select);
|
||||
app.component(Refresh.name, Refresh);
|
||||
app.component(Search.name, Search);
|
||||
|
||||
|
||||
app.use(ElementPlus, { size: 'default' }).use(router).mount('#app');
|
||||
|
@@ -51,16 +51,17 @@
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script>
|
||||
import { onMounted, reactive, watch,inject,computed } from 'vue';
|
||||
import { reactive, watch,computed } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { useConnections, useForwardConnections, useTuntapConnections } from './connections';
|
||||
export default {
|
||||
props: ['modelValue'],
|
||||
emits: ['change','update:modelValue'],
|
||||
setup(props, { emit }) {
|
||||
|
||||
const connections = inject('connections');
|
||||
const forwardConnections = inject('forward-connections');
|
||||
const tuntapConnections = inject('tuntap-connections');
|
||||
const connections = useConnections();
|
||||
const forwardConnections =useForwardConnections();
|
||||
const tuntapConnections = useTuntapConnections();
|
||||
const state = reactive({
|
||||
show: true,
|
||||
protocolTypes:{1:'tcp',2:'udp',4:'msquic'},
|
||||
|
@@ -3,12 +3,10 @@
|
||||
<template #header>
|
||||
<div class="flex">
|
||||
<span class="flex-1">设备</span>
|
||||
<span> <el-input size="small" v-model="name" clearable @change="handleRefresh" >
|
||||
<template #prefix>
|
||||
<el-icon><Search /></el-icon>
|
||||
</template>
|
||||
</el-input> </span>
|
||||
<el-button size="small" @click="handleRefresh"><el-icon><Refresh /></el-icon></el-button>
|
||||
<span> <el-input size="small" v-model="name" clearable @input="handleRefresh" placeholder="设备/虚拟网卡/端口转发" ></el-input> </span>
|
||||
<span>
|
||||
<el-button size="small" @click="handleRefresh"><el-icon><Search /></el-icon></el-button>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
@@ -71,7 +69,7 @@ a.green{color:green}
|
||||
.el-icon{vertical-align:middle}
|
||||
}
|
||||
.el-input{
|
||||
width:8rem;
|
||||
width:15rem;
|
||||
margin-right:.6rem
|
||||
}
|
||||
</style>
|
@@ -53,23 +53,27 @@
|
||||
</el-table-column>
|
||||
</template>
|
||||
<script>
|
||||
import { inject } from 'vue';
|
||||
import { useForward } from './forward';
|
||||
import { useSforward } from './sforward';
|
||||
|
||||
export default {
|
||||
emits: ['edit','sedit'],
|
||||
setup(props, { emit }) {
|
||||
|
||||
const forward = inject('forward')
|
||||
const sforward = inject('sforward')
|
||||
const forward = useForward()
|
||||
const sforward = useSforward()
|
||||
const handleEdit = (machineId)=>{
|
||||
emit('edit',machineId)
|
||||
}
|
||||
const handleSEdit = ()=>{
|
||||
emit('sedit')
|
||||
}
|
||||
const handleForwardRefresh = ()=>{
|
||||
emit('refresh');
|
||||
}
|
||||
|
||||
return {
|
||||
forward,sforward, handleEdit,handleSEdit
|
||||
forward,sforward, handleEdit,handleSEdit,handleForwardRefresh
|
||||
}
|
||||
}
|
||||
}
|
||||
|
154
linker.web/src/views/devices/ForwardCopy.vue
Normal file
154
linker.web/src/views/devices/ForwardCopy.vue
Normal file
@@ -0,0 +1,154 @@
|
||||
<template>
|
||||
<el-dialog v-model="state.show" @open="handleOnShowList" append-to=".app-wrap" title="复制端口转发" top="1vh" width="500">
|
||||
<div>
|
||||
<div class="t-c head">
|
||||
<span>复制</span>
|
||||
<el-select v-model="state.machineId" @change="handleMachineChange"
|
||||
filterable remote :loading="state.loading" :remote-method="handleSearch">
|
||||
<template #header>
|
||||
<div class="t-c">
|
||||
<div class="page-wrap">
|
||||
<el-pagination small background layout="prev, pager, next"
|
||||
:page-size="state.machineIds.Request.Size"
|
||||
:total="state.machineIds.Count"
|
||||
:pager-count="5"
|
||||
:current-page="state.machineIds.Request.Page" @current-change="handlePageChange" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<el-option v-for="(item, index) in state.machineIds.List" :key="index" :label="item.MachineName" :value="item.MachineId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<span>到【{{ state.toMachineName }}】的端口转发记录</span>
|
||||
</div>
|
||||
<el-table :data="state.forwards" size="small" border>
|
||||
<el-table-column property="Name" label="名称"></el-table-column>
|
||||
<el-table-column prop="BufferSize" label="缓冲区" width="60">
|
||||
<template #default="scope">
|
||||
{{ (1<<scope.row.BufferSize) }}KB
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column property="Port" label="监听端口" width="80"></el-table-column>
|
||||
<el-table-column property="TargetEP" label="目标服务" width="140"></el-table-column>
|
||||
<el-table-column label="操作" width="80">
|
||||
<template #default="scope">
|
||||
<el-checkbox v-model="scope.row.use">使用</el-checkbox>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="foot t-c">
|
||||
<el-button type="primary" @click="handleConfirm">确定复制</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script>
|
||||
import { onMounted, onUnmounted, reactive, watch } from 'vue';
|
||||
import { getForwardRemoteInfo,addForwardInfo } from '@/apis/forward'
|
||||
import { ElMessage } from 'element-plus';
|
||||
import {WarnTriangleFilled} from '@element-plus/icons-vue'
|
||||
import { injectGlobalData } from '@/provide';
|
||||
import { useForward } from './forward';
|
||||
import { getSignInIds } from '@/apis/signin';
|
||||
export default {
|
||||
props: ['modelValue'],
|
||||
emits: ['update:modelValue'],
|
||||
components:{WarnTriangleFilled},
|
||||
setup(props, { emit }) {
|
||||
|
||||
const globalData = injectGlobalData();
|
||||
const forward = useForward();
|
||||
const state = reactive({
|
||||
show: true,
|
||||
loading:false,
|
||||
machineId: '',
|
||||
toMachineId: forward.value.current,
|
||||
toMachineName: forward.value.machineName,
|
||||
machineIds:{
|
||||
Request: {
|
||||
Page: 1, Size:10, Name: ''
|
||||
},
|
||||
Count: 0,
|
||||
List: []
|
||||
},
|
||||
forwards: []
|
||||
});
|
||||
watch(() => state.show, (val) => {
|
||||
if (!val) {
|
||||
setTimeout(() => {
|
||||
emit('update:modelValue', val);
|
||||
}, 300);
|
||||
}
|
||||
});
|
||||
|
||||
const handleOnShowList = () => {
|
||||
_getMachineIds();
|
||||
}
|
||||
const _getMachineIds = ()=>{
|
||||
state.loading = true;
|
||||
getSignInIds(state.machineIds.Request).then((res)=>{
|
||||
state.loading = false;
|
||||
state.machineIds.Request = res.Request;
|
||||
state.machineIds.Count = res.Count;
|
||||
state.machineIds.List = res.List;
|
||||
if(!state.machineId && state.machineIds.List.length > 0){
|
||||
state.machineId = state.machineIds.List[0].MachineId;
|
||||
_getForwardRemoteInfo();
|
||||
}
|
||||
}).catch((e)=>{
|
||||
state.loading = false;
|
||||
});
|
||||
}
|
||||
const handlePageChange = (page)=>{
|
||||
state.machineIds.Request.Page = page;
|
||||
_getMachineIds();
|
||||
}
|
||||
const handleSearch = (name)=>{
|
||||
state.machineIds.Request.Name = name;
|
||||
_getMachineIds();
|
||||
}
|
||||
const _getForwardRemoteInfo = ()=>{
|
||||
getForwardRemoteInfo({
|
||||
MachineId: state.machineId,
|
||||
ToMachineId: state.toMachineId
|
||||
}).then((res)=>{
|
||||
res.forEach(c=>{
|
||||
c.use = true;
|
||||
});
|
||||
state.forwards = res;
|
||||
}).catch((e)=>{
|
||||
console.log(e);
|
||||
});
|
||||
}
|
||||
const handleMachineChange = ()=>{
|
||||
_getForwardRemoteInfo();
|
||||
}
|
||||
const handleConfirm = ()=>{
|
||||
const tasks = state.forwards.filter(c=>c.use)
|
||||
.map(c=>addForwardInfo({Name:c.Name,Port:c.Port,TargetEP:c.TargetEP,BufferSize:c.BufferSize,MachineId:state.toMachineId}));
|
||||
Promise.all(tasks).then(()=>{
|
||||
ElMessage.success('已操作!');
|
||||
state.show = false;
|
||||
}).catch(()=>{
|
||||
ElMessage.success('操作失败!');
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(()=>{
|
||||
_getMachineIds();
|
||||
});
|
||||
onUnmounted(()=>{
|
||||
});
|
||||
|
||||
return {
|
||||
state,handleSearch, handleOnShowList,handleMachineChange,handleConfirm,handlePageChange
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="stylus" scoped>
|
||||
.el-select{width : 12rem}
|
||||
.head{padding-bottom:1rem}
|
||||
.foot{padding-top:1rem}
|
||||
.page-wrap{display:inline-block}
|
||||
</style>
|
@@ -4,6 +4,7 @@
|
||||
<div class="t-c head">
|
||||
<el-button type="success" size="small" @click="handleAdd">添加</el-button>
|
||||
<el-button size="small" @click="handleRefresh">刷新</el-button>
|
||||
<el-button size="small" @click="handleCopy">复制转发配置</el-button>
|
||||
</div>
|
||||
<el-table :data="state.data" size="small" border height="500" @cell-dblclick="handleCellClick">
|
||||
<el-table-column property="Name" label="名称">
|
||||
@@ -96,11 +97,12 @@
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script>
|
||||
import { inject, onMounted, onUnmounted, reactive, watch } from 'vue';
|
||||
import { onMounted, onUnmounted, reactive, watch } from 'vue';
|
||||
import { getForwardInfo, removeForwardInfo, addForwardInfo ,getForwardIpv4,testTargetForwardInfo,testListenForwardInfo } from '@/apis/forward'
|
||||
import { ElMessage } from 'element-plus';
|
||||
import {WarnTriangleFilled} from '@element-plus/icons-vue'
|
||||
import { injectGlobalData } from '@/provide';
|
||||
import { useForward } from './forward';
|
||||
export default {
|
||||
props: ['data','modelValue'],
|
||||
emits: ['update:modelValue'],
|
||||
@@ -108,7 +110,7 @@ export default {
|
||||
setup(props, { emit }) {
|
||||
|
||||
const globalData = injectGlobalData();
|
||||
const forward = inject('forward');
|
||||
const forward = useForward();
|
||||
const state = reactive({
|
||||
show: true,
|
||||
machineId: forward.value.current,
|
||||
@@ -210,11 +212,16 @@ export default {
|
||||
});
|
||||
}
|
||||
|
||||
const handleCopy = ()=>{
|
||||
forward.value.showCopy = true;
|
||||
}
|
||||
|
||||
onMounted(()=>{
|
||||
_getForwardInfo();
|
||||
_getForwardIpv4();
|
||||
_testTargetForwardInfo();
|
||||
_testListenForwardInfo();
|
||||
|
||||
});
|
||||
onUnmounted(()=>{
|
||||
clearTimeout(state.timerTestTarget);
|
||||
@@ -222,7 +229,7 @@ export default {
|
||||
});
|
||||
|
||||
return {
|
||||
state, handleOnShowList, handleCellClick, handleRefresh, handleAdd, handleEdit, handleEditBlur, handleDel, handleStartChange
|
||||
state, handleOnShowList, handleCellClick, handleRefresh, handleAdd, handleEdit, handleEditBlur, handleDel, handleStartChange,handleCopy
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,14 +1,13 @@
|
||||
<template>
|
||||
<div class="home-list-wrap absolute" >
|
||||
<el-table :data="state.page.List" stripe border style="width: 100%" :height="`${state.height}px`" size="small">
|
||||
<el-table :data="devices.page.List" stripe border style="width: 100%" :height="`${state.height}px`" size="small">
|
||||
<Device @edit="handleDeviceEdit" @refresh="handlePageRefresh"></Device>
|
||||
<Tunnel @edit="handleTunnelEdit" @refresh="handleTunnelRefresh" @connections="handleTunnelConnections"></Tunnel>
|
||||
<Tuntap @edit="handleTuntapEdit" @refresh="handleTuntapRefresh"></Tuntap>
|
||||
<Forward @edit="handleForwardEdit" @sedit="handleSForwardEdit" @refresh="handleForwardRefresh"></Forward>
|
||||
<Forward @edit="_handleForwardEdit" @sedit="handleSForwardEdit"></Forward>
|
||||
<el-table-column label="操作" width="54" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-popconfirm v-if="scope.row.showDel" confirm-button-text="确认"
|
||||
cancel-button-text="取消" title="删除不可逆,是否确认?" @confirm="handleDel(scope.row.MachineId)">
|
||||
<el-popconfirm v-if="scope.row.showDel" confirm-button-text="确认" cancel-button-text="取消" title="删除不可逆,是否确认?" @confirm="handleDel(scope.row.MachineId)">
|
||||
<template #reference>
|
||||
<el-button type="danger" size="small"><el-icon><Delete /></el-icon></el-button>
|
||||
</template>
|
||||
@@ -18,28 +17,25 @@
|
||||
</el-table>
|
||||
<div class="page t-c">
|
||||
<div class="page-wrap">
|
||||
<el-pagination small background layout="total,prev, pager, next" :total="state.page.Count"
|
||||
:page-size="state.page.Request.Size" :current-page="state.page.Request.Page"
|
||||
@current-change="handlePageChange" />
|
||||
<el-pagination small background layout="total,sizes,prev,pager, next" :total="devices.page.Count"
|
||||
:page-size="devices.page.Request.Size" :current-page="devices.page.Request.Page"
|
||||
@current-change="handlePageChange" @size-change="handlePageSizeChange" :page-sizes="[10, 20, 50, 100,255]" />
|
||||
</div>
|
||||
</div>
|
||||
<DeviceEdit v-if="state.showDeviceEdit" v-model="state.showDeviceEdit" @change="handlePageChange" :data="state.deviceInfo"></DeviceEdit>
|
||||
<TunnelEdit v-if="tunnel.showEdit" v-model="tunnel.showEdit" @change="handleTunnelChange"></TunnelEdit>
|
||||
<DeviceEdit v-if="devices.showDeviceEdit" v-model="devices.showDeviceEdit" @change="handlePageChange" :data="devices.deviceInfo"></DeviceEdit>
|
||||
<TunnelEdit v-if="tunnel.showEdit" v-model="tunnel.showEdit" @change="handleTunnelRefresh"></TunnelEdit>
|
||||
<ConnectionsEdit v-if="connections.showEdit" v-model="connections.showEdit" ></ConnectionsEdit>
|
||||
<TuntapEdit v-if="tuntap.showEdit" v-model="tuntap.showEdit" @change="handleTuntapChange"></TuntapEdit>
|
||||
<ForwardEdit v-if="forward.showEdit" v-model="forward.showEdit" @change="handleForwardChange"></ForwardEdit>
|
||||
<SForwardEdit v-if="sforward.showEdit" v-model="sforward.showEdit" @change="handleSForwardChange"></SForwardEdit>
|
||||
<TuntapEdit v-if="tuntap.showEdit" v-model="tuntap.showEdit" @change="handleTuntapRefresh"></TuntapEdit>
|
||||
<ForwardEdit v-if="forward.showEdit" v-model="forward.showEdit" ></ForwardEdit>
|
||||
<ForwardCopy v-if="forward.showCopy" v-model="forward.showCopy" ></ForwardCopy>
|
||||
<SForwardEdit v-if="sforward.showEdit" v-model="sforward.showEdit" ></SForwardEdit>
|
||||
<SForwardCopy v-if="sforward.showCopy" v-model="sforward.showCopy" ></SForwardCopy>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { getSignInList, signInDel } from '@/apis/signin.js'
|
||||
import { subWebsocketState } from '@/apis/request.js'
|
||||
import { getTuntapInfo,refreshTuntap,getTuntapConnections,removeTuntapConnection } from '@/apis/tuntap'
|
||||
import { getForwardInfo ,testTargetForwardInfo,testListenForwardInfo,getForwardConnections,removeForwardConnection} from '@/apis/forward'
|
||||
import { getSForwardInfo,testLocalSForwardInfo} from '@/apis/sforward'
|
||||
import { getTunnelInfo ,refreshTunnel} from '@/apis/tunnel'
|
||||
import { injectGlobalData } from '@/provide.js'
|
||||
import { reactive, onMounted, ref, nextTick, onUnmounted, computed, provide } from 'vue'
|
||||
import { reactive, onMounted, onUnmounted, computed } from 'vue'
|
||||
import Device from './Device.vue'
|
||||
import DeviceEdit from './DeviceEdit.vue'
|
||||
import Tuntap from './Tuntap.vue'
|
||||
@@ -48,334 +44,69 @@ import Tunnel from './Tunnel.vue'
|
||||
import TunnelEdit from './TunnelEdit.vue'
|
||||
import Forward from './Forward.vue'
|
||||
import ForwardEdit from './ForwardEdit.vue'
|
||||
import ForwardCopy from './ForwardCopy.vue'
|
||||
import SForwardEdit from './SForwardEdit.vue'
|
||||
import SForwardCopy from './SForwardCopy.vue'
|
||||
import ConnectionsEdit from './ConnectionsEdit.vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { provideTuntap } from './tuntap'
|
||||
import { provideTunnel } from './tunnel'
|
||||
import { provideForward } from './forward'
|
||||
import { provideConnections } from './connections'
|
||||
import { provideSforward } from './sforward'
|
||||
import { provideDevices } from './devices'
|
||||
export default {
|
||||
components: {Device,DeviceEdit,Tunnel,TunnelEdit,ConnectionsEdit, Tuntap,TuntapEdit, Forward,ForwardEdit,SForwardEdit },
|
||||
components: {Device,DeviceEdit,Tunnel,TunnelEdit,ConnectionsEdit, Tuntap,TuntapEdit, Forward,ForwardEdit,ForwardCopy,SForwardEdit,SForwardCopy },
|
||||
setup(props) {
|
||||
|
||||
const globalData = injectGlobalData();
|
||||
const machineId = computed(() => globalData.value.config.Client.Id);
|
||||
|
||||
const state = reactive({
|
||||
timer:0,
|
||||
page: {
|
||||
Request: { Page: 1, Size: 10, GroupId: globalData.value.groupid,Name:'' },
|
||||
Count: 0,
|
||||
List: []
|
||||
},
|
||||
|
||||
showDeviceEdit:false,
|
||||
deviceInfo: null,
|
||||
|
||||
height: computed(()=>globalData.value.height-60),
|
||||
});
|
||||
|
||||
const tuntap = ref({
|
||||
timer:0,
|
||||
showEdit:false,
|
||||
current: null,
|
||||
list: {},
|
||||
hashcode: 0,
|
||||
});
|
||||
provide('tuntap',tuntap);
|
||||
const _getTuntapInfo = () => {
|
||||
if (globalData.value.connected) {
|
||||
getTuntapInfo(tuntap.value.hashcode.toString()).then((res) => {
|
||||
tuntap.value.hashcode = res.HashCode;
|
||||
if (res.List) {
|
||||
for (let j in res.List) {
|
||||
res.List[j].running = res.List[j].Status == 2;
|
||||
res.List[j].loading = res.List[j].Status == 1;
|
||||
}
|
||||
tuntap.value.list = res.List;
|
||||
}
|
||||
tuntap.value.timer = setTimeout(_getTuntapInfo, 200);
|
||||
}).catch(() => {
|
||||
tuntap.value.timer = setTimeout(_getTuntapInfo, 200);
|
||||
});
|
||||
} else {
|
||||
tuntap.value.timer = setTimeout(_getTuntapInfo, 1000);
|
||||
}
|
||||
}
|
||||
const handleTuntapEdit = (_tuntap)=>{
|
||||
tuntap.value.current = _tuntap;
|
||||
tuntap.value.showEdit = true;
|
||||
const {devices, machineId, _getSignList, _getSignList1,
|
||||
handleDeviceEdit, handlePageChange, handlePageSizeChange, handleDel,clearDevicesTimeout} = provideDevices();
|
||||
|
||||
}
|
||||
const handleTuntapChange = (page) => {
|
||||
if(page){
|
||||
state.page.Request.Page = page;
|
||||
}
|
||||
_getSignList();
|
||||
}
|
||||
const handleTuntapRefresh = ()=>{
|
||||
refreshTuntap();
|
||||
ElMessage.success('刷新成功');
|
||||
}
|
||||
const {tuntap,_getTuntapInfo,handleTuntapEdit,handleTuntapRefresh,clearTuntapTimeout,getTuntapMachines} = provideTuntap();
|
||||
const {tunnel,_getTunnelInfo,handleTunnelEdit,handleTunnelRefresh,clearTunnelTimeout} = provideTunnel();
|
||||
const {forward,_getForwardInfo,handleForwardEdit,_testTargetForwardInfo,_testListenForwardInfo,clearForwardTimeout,getForwardMachines} = provideForward();
|
||||
const {sforward,_getSForwardInfo,handleSForwardEdit,_testLocalSForwardInfo,clearSForwardTimeout,getSForwardMachines} = provideSforward();
|
||||
const {connections,
|
||||
forwardConnections,_getForwardConnections,
|
||||
tuntapConnections,_getTuntapConnections,
|
||||
handleTunnelConnections,clearConnectionsTimeout
|
||||
} = provideConnections();
|
||||
|
||||
|
||||
const tunnel = ref({
|
||||
timer:0,
|
||||
showEdit:false,
|
||||
current: null,
|
||||
list: {},
|
||||
hashcode: 0,
|
||||
});
|
||||
provide('tunnel',tunnel);
|
||||
const _getTunnelInfo = () => {
|
||||
if (globalData.value.connected) {
|
||||
getTunnelInfo(tunnel.value.hashcode.toString()).then((res) => {
|
||||
tunnel.value.hashcode = res.HashCode;
|
||||
if (res.List) {
|
||||
tunnel.value.list = res.List;
|
||||
}
|
||||
tunnel.value.timer = setTimeout(_getTunnelInfo, 1000);
|
||||
}).catch(() => {
|
||||
tunnel.value.timer = setTimeout(_getTunnelInfo, 1000);
|
||||
});
|
||||
} else {
|
||||
tunnel.value.timer = setTimeout(_getTunnelInfo, 1000);
|
||||
}
|
||||
}
|
||||
const handleTunnelEdit = (_tunnel)=>{
|
||||
tunnel.value.current = _tunnel;
|
||||
tunnel.value.showEdit = true;
|
||||
}
|
||||
const handleTunnelChange = () => {
|
||||
_getSignList();
|
||||
}
|
||||
const handleTunnelRefresh = ()=>{
|
||||
refreshTunnel();
|
||||
ElMessage.success('刷新成功');
|
||||
const _handleForwardEdit = (machineId) => {
|
||||
handleForwardEdit(machineId,devices.page.List.filter(c => c.MachineId == machineId)[0].MachineName);
|
||||
}
|
||||
|
||||
const connections = ref({
|
||||
showEdit:false,
|
||||
speedCache: {},
|
||||
current:''
|
||||
});
|
||||
provide('connections',connections);
|
||||
|
||||
const forwardConnections = ref({
|
||||
timer:0,
|
||||
list: {},
|
||||
});
|
||||
provide('forward-connections',forwardConnections);
|
||||
const _getForwardConnections = ()=>{
|
||||
if (globalData.value.connected) {
|
||||
getForwardConnections().then((res)=>{
|
||||
parseConnections(res,removeForwardConnection);
|
||||
forwardConnections.value.list = res;
|
||||
forwardConnections.value.timer = setTimeout(_getForwardConnections, 1000);
|
||||
}).catch((e)=>{
|
||||
forwardConnections.value.timer = setTimeout(_getForwardConnections, 1000);
|
||||
})
|
||||
}else {
|
||||
forwardConnections.value.timer = setTimeout(_getForwardConnections, 1000);
|
||||
}
|
||||
}
|
||||
const tuntapConnections = ref({
|
||||
timer:0,
|
||||
list: {},
|
||||
});
|
||||
provide('tuntap-connections',tuntapConnections);
|
||||
const _getTuntapConnections = ()=>{
|
||||
if (globalData.value.connected) {
|
||||
getTuntapConnections().then((res)=>{
|
||||
parseConnections(res,removeTuntapConnection);
|
||||
tuntapConnections.value.list = res;
|
||||
tuntapConnections.value.timer = setTimeout(_getTuntapConnections, 1000);
|
||||
}).catch((e)=>{
|
||||
tuntapConnections.value.timer = setTimeout(_getTuntapConnections, 1000);
|
||||
})
|
||||
}else {
|
||||
tuntapConnections.value.timer = setTimeout(_getTuntapConnections, 1000);
|
||||
}
|
||||
}
|
||||
const parseConnections = (_connections,removeFunc)=>{
|
||||
const caches = connections.value.speedCache;
|
||||
for(let machineId in _connections){
|
||||
const connection = _connections[machineId];
|
||||
connection.removeFunc = removeFunc;
|
||||
|
||||
const key = `${connection.RemoteMachineId}-${connection.TransactionId}`;
|
||||
const cache = caches[key] || {SendBytes:0,ReceiveBytes:0};
|
||||
|
||||
connection.SendBytesText = parseSpeed(connection.SendBytes - cache.SendBytes);
|
||||
connection.ReceiveBytesText = parseSpeed(connection.ReceiveBytes - cache.ReceiveBytes);
|
||||
|
||||
cache.SendBytes = connection.SendBytes;
|
||||
cache.ReceiveBytes = connection.ReceiveBytes;
|
||||
caches[key] = cache;
|
||||
}
|
||||
}
|
||||
const parseSpeed = (num)=>{
|
||||
let index = 0;
|
||||
while(num >= 1024){
|
||||
num/=1024;
|
||||
index++;
|
||||
}
|
||||
return `${num.toFixed(2)}${['B/s','KB/s','MB/s','GB/s','TB/s'][index]}`;
|
||||
}
|
||||
const handleTunnelConnections = (machineId)=>{
|
||||
connections.value.current = machineId;
|
||||
connections.value.showEdit = true;
|
||||
}
|
||||
|
||||
const forward = ref({
|
||||
timer:0,
|
||||
showEdit:false,
|
||||
current: null,
|
||||
list: {}
|
||||
});
|
||||
provide('forward',forward);
|
||||
const _getForwardInfo = () => {
|
||||
if (globalData.value.connected) {
|
||||
getForwardInfo().then((res) => {
|
||||
forward.value.list = res;
|
||||
|
||||
forward.value.timer = setTimeout(_getForwardInfo, 1000);
|
||||
}).catch(() => {
|
||||
forward.value.timer = setTimeout(_getForwardInfo, 1000);
|
||||
});
|
||||
}else {
|
||||
forward.value.timer = setTimeout(_getForwardInfo, 1000);
|
||||
}
|
||||
}
|
||||
const handleForwardEdit = (machineId)=>{
|
||||
forward.value.current = machineId;
|
||||
forward.value.machineName =state.page.List.filter(c=>c.MachineId == machineId)[0].MachineName ;
|
||||
forward.value.showEdit = true;
|
||||
}
|
||||
const handleForwardChange = () => {
|
||||
_getSignList();
|
||||
}
|
||||
const handleForwardRefresh = ()=>{
|
||||
_getSignList();
|
||||
ElMessage.success('刷新成功');
|
||||
}
|
||||
|
||||
|
||||
const sforward = ref({
|
||||
timer:0,
|
||||
showEdit:false,
|
||||
list: []
|
||||
});
|
||||
provide('sforward',sforward);
|
||||
const _getSForwardInfo = () => {
|
||||
if (globalData.value.connected) {
|
||||
getSForwardInfo().then((res) => {
|
||||
sforward.value.list = res;
|
||||
sforward.value.timer = setTimeout(_getSForwardInfo, 1000);
|
||||
}).catch(() => {
|
||||
sforward.value.timer = setTimeout(_getSForwardInfo, 1000);
|
||||
});
|
||||
}else {
|
||||
sforward.value.timer = setTimeout(_getSForwardInfo, 1000);
|
||||
}
|
||||
}
|
||||
const handleSForwardEdit = ()=>{
|
||||
sforward.value.showEdit = true;
|
||||
}
|
||||
const handleSForwardChange = () => {
|
||||
_getSignList();
|
||||
}
|
||||
|
||||
|
||||
|
||||
const _getSignList = () => {
|
||||
state.page.Request.GroupId = globalData.value.groupid;
|
||||
getSignInList(state.page.Request).then((res) => {
|
||||
state.page.Request = res.Request;
|
||||
state.page.Count = res.Count;
|
||||
for (let j in res.List) {
|
||||
res.List[j].showTunnel = machineId.value != res.List[j].MachineId;
|
||||
res.List[j].showForward = machineId.value != res.List[j].MachineId;
|
||||
res.List[j].showSForward = machineId.value == res.List[j].MachineId;
|
||||
res.List[j].showDel = machineId.value != res.List[j].MachineId && res.List[j].Connected == false;
|
||||
res.List[j].isSelf = machineId.value == res.List[j].MachineId;
|
||||
}
|
||||
state.page.List = res.List.sort((a,b)=>b.Connected - a.Connected);
|
||||
}).catch((err) => { });
|
||||
}
|
||||
const _getSignList1 = () => {
|
||||
if (globalData.value.connected) {
|
||||
state.page.Request.GroupId = globalData.value.groupid;
|
||||
getSignInList(state.page.Request).then((res) => {
|
||||
for (let j in res.List) {
|
||||
const item = state.page.List.filter(c=>c.MachineId == res.List[j].MachineId)[0];
|
||||
if(item){
|
||||
item.Connected = res.List[j].Connected;
|
||||
item.Version = res.List[j].Version;
|
||||
item.LastSignIn = res.List[j].LastSignIn;
|
||||
item.Args = res.List[j].Args;
|
||||
item.showTunnel = machineId.value != res.List[j].MachineId;
|
||||
item.showForward = machineId.value != res.List[j].MachineId;
|
||||
item.showSForward = machineId.value == res.List[j].MachineId;
|
||||
item.showDel = machineId.value != res.List[j].MachineId && res.List[j].Connected == false;
|
||||
item.isSelf = machineId.value == res.List[j].MachineId;
|
||||
}
|
||||
}
|
||||
state.timer = setTimeout(_getSignList1, 5000);
|
||||
}).catch((err) => {
|
||||
state.timer = setTimeout(_getSignList1, 5000);
|
||||
});
|
||||
}else{
|
||||
state.timer = setTimeout(_getSignList1, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
const handleDeviceEdit = (row)=>{
|
||||
state.deviceInfo = row;
|
||||
state.showDeviceEdit = true;
|
||||
}
|
||||
const handlePageRefresh = (name)=>{
|
||||
state.page.Request.Name = name;
|
||||
handlePageChange();
|
||||
refreshTunnel();
|
||||
refreshTuntap();
|
||||
ElMessage.success('刷新成功');
|
||||
}
|
||||
const handlePageChange = (page) => {
|
||||
if(page){
|
||||
state.page.Request.Page = page;
|
||||
_getSignList();
|
||||
devices.page.Request.Name = name || '';
|
||||
if(devices.page.Request.Name){
|
||||
devices.page.Request.Ids = getTuntapMachines(devices.page.Request.Name)
|
||||
.concat(getForwardMachines(devices.page.Request.Name))
|
||||
.concat(getSForwardMachines(devices.page.Request.Name))
|
||||
.reduce((arr,id)=>{
|
||||
if(arr.indexOf(id) == -1){
|
||||
arr.push(id);
|
||||
}
|
||||
return arr;
|
||||
},[]);
|
||||
}else{
|
||||
devices.page.Request.Ids = [];
|
||||
}
|
||||
handlePageChange();
|
||||
handleTunnelRefresh();
|
||||
handleTuntapRefresh();
|
||||
ElMessage.success({message:'刷新成功',grouping:true});
|
||||
}
|
||||
const handleDel = (name) => {
|
||||
signInDel(name).then(() => {
|
||||
_getSignList();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const timerState = reactive({
|
||||
timerTestTarget:0,
|
||||
timerTestListen:0,
|
||||
timerTestLocal:0,
|
||||
})
|
||||
const _testTargetForwardInfo = ()=>{
|
||||
testTargetForwardInfo(forward.value.current).then((res)=>{
|
||||
timerState.timerTestTarget = setTimeout(_testTargetForwardInfo,5000);
|
||||
}).catch(()=>{
|
||||
timerState.timerTestTarget = setTimeout(_testTargetForwardInfo,5000);
|
||||
});
|
||||
}
|
||||
const _testListenForwardInfo = ()=>{
|
||||
testListenForwardInfo(forward.value.current).then((res)=>{
|
||||
timerState.timerTestListen = setTimeout(_testListenForwardInfo,5000);
|
||||
}).catch(()=>{
|
||||
timerState.timerTestListen = setTimeout(_testListenForwardInfo,5000);
|
||||
});
|
||||
}
|
||||
const _testLocalSForwardInfo = ()=>{
|
||||
testLocalSForwardInfo().then((res)=>{
|
||||
timerState.timerTestLocal = setTimeout(_testLocalSForwardInfo,5000);
|
||||
}).catch(()=>{
|
||||
timerState.timerTestLocal = setTimeout(_testLocalSForwardInfo,5000);
|
||||
});
|
||||
const handlePageSearch = ()=>{
|
||||
handlePageChange();
|
||||
handleTunnelRefresh();
|
||||
handleTuntapRefresh();
|
||||
ElMessage.success({message:'刷新成功',grouping:true});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
@@ -399,23 +130,21 @@ export default {
|
||||
_testLocalSForwardInfo();
|
||||
});
|
||||
onUnmounted(() => {
|
||||
clearTimeout( state.timer);
|
||||
clearTimeout(tuntap.value.timer);
|
||||
clearTimeout(tunnel.value.timer);
|
||||
clearTimeout(forward.value.timer);
|
||||
clearTimeout(sforward.value.timer);
|
||||
|
||||
clearTimeout(timerState.timerTestTarget);
|
||||
clearTimeout(timerState.timerTestListen);
|
||||
clearTimeout(timerState.timerTestLocal);
|
||||
clearDevicesTimeout();
|
||||
clearConnectionsTimeout();
|
||||
clearTuntapTimeout();
|
||||
clearTunnelTimeout();
|
||||
clearForwardTimeout();
|
||||
clearSForwardTimeout();
|
||||
});
|
||||
|
||||
return {
|
||||
machineId, state,
|
||||
handleDeviceEdit,handlePageRefresh, handlePageChange, handleDel,
|
||||
tuntap, handleTuntapEdit, handleTuntapChange, handleTuntapRefresh,
|
||||
tunnel,connections, handleTunnelEdit, handleTunnelChange, handleTunnelRefresh,handleTunnelConnections,
|
||||
forward,sforward, handleForwardEdit,handleForwardChange,handleForwardRefresh,handleSForwardEdit,handleSForwardChange
|
||||
state,devices, machineId,
|
||||
handleDeviceEdit,handlePageRefresh,handlePageSearch, handlePageChange,handlePageSizeChange, handleDel,
|
||||
tuntap, handleTuntapEdit, handleTuntapRefresh,
|
||||
tunnel,connections, handleTunnelEdit, handleTunnelRefresh,handleTunnelConnections,
|
||||
forward,_handleForwardEdit,
|
||||
sforward,handleSForwardEdit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
146
linker.web/src/views/devices/SForwardCopy.vue
Normal file
146
linker.web/src/views/devices/SForwardCopy.vue
Normal file
@@ -0,0 +1,146 @@
|
||||
<template>
|
||||
<el-dialog v-model="state.show" @open="handleOnShowList" append-to=".app-wrap" title="复制服务器代理穿透" top="1vh" width="500">
|
||||
<div>
|
||||
<div class="t-c head">
|
||||
<span>复制</span>
|
||||
<el-select v-model="state.machineId" @change="handleMachineChange"
|
||||
filterable remote :loading="state.loading" :remote-method="handleSearch">
|
||||
<template #header>
|
||||
<div class="t-c">
|
||||
<div class="page-wrap">
|
||||
<el-pagination small background layout="prev, pager, next"
|
||||
:page-size="state.machineIds.Request.Size"
|
||||
:total="state.machineIds.Count"
|
||||
:pager-count="5"
|
||||
:current-page="state.machineIds.Request.Page" @current-change="handlePageChange" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<el-option v-for="(item, index) in state.machineIds.List" :key="index" :label="item.MachineName" :value="item.MachineId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<span>的服务器代理穿透记录</span>
|
||||
</div>
|
||||
<el-table :data="state.forwards" size="small" border>
|
||||
<el-table-column property="Name" label="名称"></el-table-column>
|
||||
<el-table-column property="Domain" label="域名/端口">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.Domain || scope.row.RemotePort }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column property="LocalEP" label="本机服务" width="140"></el-table-column>
|
||||
<el-table-column label="操作" width="80">
|
||||
<template #default="scope">
|
||||
<el-checkbox v-model="scope.row.use">使用</el-checkbox>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="foot t-c">
|
||||
<el-button type="primary" @click="handleConfirm">确定复制</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script>
|
||||
import { onMounted, onUnmounted, reactive, watch } from 'vue';
|
||||
import { getSForwardRemoteInfo,addSForwardInfo } from '@/apis/sforward'
|
||||
import { ElMessage } from 'element-plus';
|
||||
import {WarnTriangleFilled} from '@element-plus/icons-vue'
|
||||
import { injectGlobalData } from '@/provide';
|
||||
import { getSignInIds } from '@/apis/signin';
|
||||
export default {
|
||||
props: ['modelValue'],
|
||||
emits: ['update:modelValue'],
|
||||
components:{WarnTriangleFilled},
|
||||
setup(props, { emit }) {
|
||||
|
||||
const globalData = injectGlobalData();
|
||||
const state = reactive({
|
||||
show: true,
|
||||
loading:false,
|
||||
machineId: '',
|
||||
machineIds:{
|
||||
Request: {
|
||||
Page: 1, Size:10, Name: ''
|
||||
},
|
||||
Count: 0,
|
||||
List: []
|
||||
},
|
||||
forwards: []
|
||||
});
|
||||
watch(() => state.show, (val) => {
|
||||
if (!val) {
|
||||
setTimeout(() => {
|
||||
emit('update:modelValue', val);
|
||||
}, 300);
|
||||
}
|
||||
});
|
||||
|
||||
const handleOnShowList = () => {
|
||||
_getMachineIds();
|
||||
}
|
||||
const _getMachineIds = ()=>{
|
||||
state.loading = true;
|
||||
getSignInIds(state.machineIds.Request).then((res)=>{
|
||||
state.loading = false;
|
||||
state.machineIds.Request = res.Request;
|
||||
state.machineIds.Count = res.Count;
|
||||
state.machineIds.List = res.List;
|
||||
if(!state.machineId && state.machineIds.List.length > 0){
|
||||
state.machineId = state.machineIds.List[0].MachineId;
|
||||
_getForwardRemoteInfo();
|
||||
}
|
||||
}).catch((e)=>{
|
||||
state.loading = false;
|
||||
});
|
||||
}
|
||||
const handlePageChange = (page)=>{
|
||||
state.machineIds.Request.Page = page;
|
||||
_getMachineIds();
|
||||
}
|
||||
const handleSearch = (name)=>{
|
||||
state.machineIds.Request.Name = name;
|
||||
_getMachineIds();
|
||||
}
|
||||
const _getForwardRemoteInfo = ()=>{
|
||||
getSForwardRemoteInfo(state.machineId).then((res)=>{
|
||||
res.forEach(c=>{
|
||||
c.use = true;
|
||||
});
|
||||
state.forwards = res;
|
||||
}).catch((e)=>{
|
||||
console.log(e);
|
||||
});
|
||||
}
|
||||
const handleMachineChange = ()=>{
|
||||
_getForwardRemoteInfo();
|
||||
}
|
||||
const handleConfirm = ()=>{
|
||||
const tasks = state.forwards.filter(c=>c.use)
|
||||
.map(c=>addSForwardInfo({Name:c.Name,Domain:c.Domain,RemotePort:c.RemotePort,LocalEP:c.LocalEP}));
|
||||
Promise.all(tasks).then(()=>{
|
||||
ElMessage.success('已操作!');
|
||||
state.show = false;
|
||||
}).catch(()=>{
|
||||
ElMessage.success('操作失败!');
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(()=>{
|
||||
_getMachineIds();
|
||||
});
|
||||
onUnmounted(()=>{
|
||||
});
|
||||
|
||||
return {
|
||||
state,handleSearch, handleOnShowList,handleMachineChange,handleConfirm,handlePageChange
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="stylus" scoped>
|
||||
.el-select{width : 12rem}
|
||||
.head{padding-bottom:1rem}
|
||||
.foot{padding-top:1rem}
|
||||
.page-wrap{display:inline-block}
|
||||
</style>
|
@@ -1,9 +1,10 @@
|
||||
<template>
|
||||
<el-dialog v-model="state.show" @open="handleOnShowList" append-to=".app-wrap" title="服务器端口转发到本机" top="1vh" width="700">
|
||||
<el-dialog v-model="state.show" @open="handleOnShowList" append-to=".app-wrap" title="服务器代理穿透" top="1vh" width="700">
|
||||
<div>
|
||||
<div class="t-c head">
|
||||
<el-button type="success" size="small" @click="handleAdd">添加</el-button>
|
||||
<el-button size="small" @click="handleRefresh">刷新</el-button>
|
||||
<el-button size="small" @click="handleCopy">复制穿透配置</el-button>
|
||||
</div>
|
||||
<el-table :data="state.data" size="small" border height="500" @cell-dblclick="handleCellClick">
|
||||
<el-table-column property="Name" label="名称">
|
||||
@@ -85,11 +86,12 @@
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script>
|
||||
import { inject, onMounted, onUnmounted, reactive, watch } from 'vue';
|
||||
import { onMounted, onUnmounted, reactive, watch } from 'vue';
|
||||
import { getSForwardInfo, removeSForwardInfo, addSForwardInfo,testLocalSForwardInfo } from '@/apis/sforward'
|
||||
import { ElMessage } from 'element-plus';
|
||||
import {WarnTriangleFilled} from '@element-plus/icons-vue'
|
||||
import { injectGlobalData } from '@/provide';
|
||||
import { useSforward } from './sforward';
|
||||
export default {
|
||||
props: ['data','modelValue'],
|
||||
emits: ['update:modelValue'],
|
||||
@@ -97,7 +99,7 @@ export default {
|
||||
setup(props, { emit }) {
|
||||
|
||||
const globalData = injectGlobalData();
|
||||
const sforward = inject('sforward');
|
||||
const sforward = useSforward();
|
||||
const state = reactive({
|
||||
bufferSize:globalData.value.bufferSize,
|
||||
show: true,
|
||||
@@ -197,6 +199,9 @@ export default {
|
||||
ElMessage.error(err);
|
||||
});
|
||||
}
|
||||
const handleCopy = ()=>{
|
||||
sforward.value.showCopy = true;
|
||||
}
|
||||
|
||||
onMounted(()=>{
|
||||
_getSForwardInfo();
|
||||
@@ -207,7 +212,7 @@ export default {
|
||||
})
|
||||
|
||||
return {
|
||||
state, handleOnShowList, handleCellClick, handleRefresh, handleAdd, handleEdit, handleEditBlur, handleDel, handleStartChange
|
||||
state, handleOnShowList, handleCellClick, handleRefresh, handleAdd, handleEdit, handleEditBlur, handleDel, handleStartChange,handleCopy
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,11 +1,5 @@
|
||||
<template>
|
||||
<el-table-column prop="tuntap" label="隧道" width="90">
|
||||
<template #header>
|
||||
<div class="flex">
|
||||
<span class="flex-1">隧道</span>
|
||||
<el-button size="small" @click="handleTunnelRefresh"><el-icon><Refresh /></el-icon></el-button>
|
||||
</div>
|
||||
</template>
|
||||
<el-table-column prop="tunnel" label="隧道" width="90">
|
||||
<template #default="scope">
|
||||
<div v-if="tunnel.list[scope.row.MachineId]">
|
||||
<p>
|
||||
@@ -23,16 +17,17 @@
|
||||
</el-table-column>
|
||||
</template>
|
||||
<script>
|
||||
import { computed, inject, reactive } from 'vue';
|
||||
import { useTunnel } from './tunnel';
|
||||
import { useConnections,useForwardConnections,useTuntapConnections } from './connections';
|
||||
|
||||
export default {
|
||||
emits: ['edit','refresh'],
|
||||
setup(props, { emit }) {
|
||||
|
||||
const tunnel = inject('tunnel');
|
||||
|
||||
const forwardConnections = inject('forward-connections');
|
||||
const tuntapConnections = inject('tuntap-connections');
|
||||
const tunnel = useTunnel();
|
||||
const connections = useConnections();
|
||||
const forwardConnections =useForwardConnections();
|
||||
const tuntapConnections = useTuntapConnections();
|
||||
|
||||
const connectionCount = (machineId)=>{
|
||||
return [
|
||||
|
@@ -36,14 +36,15 @@
|
||||
<script>
|
||||
import {setTunnelRouteLevel } from '@/apis/tunnel';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { inject, reactive, ref, watch } from 'vue';
|
||||
import { reactive, ref, watch } from 'vue';
|
||||
import { useTunnel } from './tunnel';
|
||||
|
||||
export default {
|
||||
props: ['modelValue'],
|
||||
emits: ['change','update:modelValue'],
|
||||
setup(props, { emit }) {
|
||||
|
||||
const tunnel = inject('tunnel');
|
||||
const tunnel = useTunnel();
|
||||
const ruleFormRef = ref(null);
|
||||
const state = reactive({
|
||||
show: true,
|
||||
|
@@ -1,11 +1,5 @@
|
||||
<template>
|
||||
<el-table-column prop="tuntap" label="虚拟网卡" width="150">
|
||||
<template #header>
|
||||
<div class="flex">
|
||||
<span class="flex-1">虚拟网卡</span>
|
||||
<el-button size="small" @click="handleRuntapRefresh"><el-icon><Refresh /></el-icon></el-button>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div v-if="tuntap.list[scope.row.MachineId]">
|
||||
<div class="flex">
|
||||
@@ -40,13 +34,13 @@
|
||||
<script>
|
||||
import { stopTuntap, runTuntap } from '@/apis/tuntap';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { inject, reactive } from 'vue';
|
||||
import { useTuntap } from './tuntap';
|
||||
|
||||
export default {
|
||||
emits: ['edit','refresh'],
|
||||
setup(props, { emit }) {
|
||||
|
||||
const tuntap = inject('tuntap');
|
||||
const tuntap = useTuntap();
|
||||
const handleTuntap = (tuntap) => {
|
||||
const fn = tuntap.running ? stopTuntap (tuntap.MachineId) : runTuntap(tuntap.MachineId);
|
||||
fn.then(() => {
|
||||
@@ -58,12 +52,12 @@ export default {
|
||||
const handleTuntapIP = (tuntap) => {
|
||||
emit('edit',tuntap);
|
||||
}
|
||||
const handleRuntapRefresh = ()=>{
|
||||
const handleTuntapRefresh = ()=>{
|
||||
emit('refresh');
|
||||
}
|
||||
|
||||
return {
|
||||
tuntap, handleTuntap, handleTuntapIP,handleRuntapRefresh
|
||||
tuntap, handleTuntap, handleTuntapIP,handleTuntapRefresh
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,4 +66,7 @@ export default {
|
||||
.green{color:green;}
|
||||
.error{color:red;}
|
||||
.el-switch.is-disabled{opacity :1;}
|
||||
.el-input{
|
||||
width:8rem;
|
||||
}
|
||||
</style>
|
@@ -37,7 +37,8 @@
|
||||
import {updateTuntap } from '@/apis/tuntap';
|
||||
import { injectGlobalData } from '@/provide';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { inject, reactive, ref, watch } from 'vue';
|
||||
import { reactive, ref, watch } from 'vue';
|
||||
import { useTuntap } from './tuntap';
|
||||
|
||||
export default {
|
||||
props: ['modelValue'],
|
||||
@@ -45,8 +46,7 @@ export default {
|
||||
setup(props, { emit }) {
|
||||
|
||||
const globalData = injectGlobalData();
|
||||
|
||||
const tuntap = inject('tuntap');
|
||||
const tuntap = useTuntap();
|
||||
const ruleFormRef = ref(null);
|
||||
const state = reactive({
|
||||
show: true,
|
||||
|
102
linker.web/src/views/devices/connections.js
Normal file
102
linker.web/src/views/devices/connections.js
Normal file
@@ -0,0 +1,102 @@
|
||||
import { getForwardConnections } from "@/apis/forward";
|
||||
import { getTuntapConnections } from "@/apis/tuntap";
|
||||
import { injectGlobalData } from "@/provide";
|
||||
import { inject, provide, ref } from "vue";
|
||||
|
||||
const connectionsSymbol = Symbol();
|
||||
const forwardConnectionsSymbol = Symbol();
|
||||
const tuntapConnectionsSymbol = Symbol();
|
||||
export const provideConnections = () => {
|
||||
const globalData = injectGlobalData();
|
||||
const connections = ref({
|
||||
showEdit: false,
|
||||
speedCache: {},
|
||||
current: ''
|
||||
});
|
||||
provide(connectionsSymbol, connections);
|
||||
|
||||
const forwardConnections = ref({
|
||||
timer: 0,
|
||||
list: {},
|
||||
});
|
||||
provide(forwardConnectionsSymbol, forwardConnections);
|
||||
const _getForwardConnections = () => {
|
||||
if (globalData.value.connected) {
|
||||
getForwardConnections().then((res) => {
|
||||
parseConnections(res, removeForwardConnection);
|
||||
forwardConnections.value.list = res;
|
||||
forwardConnections.value.timer = setTimeout(_getForwardConnections, 1000);
|
||||
}).catch((e) => {
|
||||
forwardConnections.value.timer = setTimeout(_getForwardConnections, 1000);
|
||||
})
|
||||
} else {
|
||||
forwardConnections.value.timer = setTimeout(_getForwardConnections, 1000);
|
||||
}
|
||||
}
|
||||
const tuntapConnections = ref({
|
||||
timer: 0,
|
||||
list: {},
|
||||
});
|
||||
provide(tuntapConnectionsSymbol, tuntapConnections);
|
||||
const _getTuntapConnections = () => {
|
||||
if (globalData.value.connected) {
|
||||
getTuntapConnections().then((res) => {
|
||||
parseConnections(res, removeTuntapConnection);
|
||||
tuntapConnections.value.list = res;
|
||||
tuntapConnections.value.timer = setTimeout(_getTuntapConnections, 1000);
|
||||
}).catch((e) => {
|
||||
tuntapConnections.value.timer = setTimeout(_getTuntapConnections, 1000);
|
||||
})
|
||||
} else {
|
||||
tuntapConnections.value.timer = setTimeout(_getTuntapConnections, 1000);
|
||||
}
|
||||
}
|
||||
const parseConnections = (_connections, removeFunc) => {
|
||||
const caches = connections.value.speedCache;
|
||||
for (let machineId in _connections) {
|
||||
const connection = _connections[machineId];
|
||||
connection.removeFunc = removeFunc;
|
||||
|
||||
const key = `${connection.RemoteMachineId}-${connection.TransactionId}`;
|
||||
const cache = caches[key] || { SendBytes: 0, ReceiveBytes: 0 };
|
||||
|
||||
connection.SendBytesText = parseSpeed(connection.SendBytes - cache.SendBytes);
|
||||
connection.ReceiveBytesText = parseSpeed(connection.ReceiveBytes - cache.ReceiveBytes);
|
||||
|
||||
cache.SendBytes = connection.SendBytes;
|
||||
cache.ReceiveBytes = connection.ReceiveBytes;
|
||||
caches[key] = cache;
|
||||
}
|
||||
}
|
||||
const parseSpeed = (num) => {
|
||||
let index = 0;
|
||||
while (num >= 1024) {
|
||||
num /= 1024;
|
||||
index++;
|
||||
}
|
||||
return `${num.toFixed(2)}${['B/s', 'KB/s', 'MB/s', 'GB/s', 'TB/s'][index]}`;
|
||||
}
|
||||
const handleTunnelConnections = (machineId) => {
|
||||
connections.value.current = machineId;
|
||||
connections.value.showEdit = true;
|
||||
}
|
||||
const clearConnectionsTimeout = () => {
|
||||
clearTimeout(forwardConnections.value.timer);
|
||||
clearTimeout(tuntapConnections.value.timer);
|
||||
}
|
||||
return {
|
||||
connections,
|
||||
forwardConnections, _getForwardConnections,
|
||||
tuntapConnections, _getTuntapConnections,
|
||||
handleTunnelConnections, clearConnectionsTimeout
|
||||
}
|
||||
}
|
||||
export const useConnections = () => {
|
||||
return inject(connectionsSymbol);
|
||||
}
|
||||
export const useForwardConnections = () => {
|
||||
return inject(forwardConnectionsSymbol);
|
||||
}
|
||||
export const useTuntapConnections = () => {
|
||||
return inject(tuntapConnectionsSymbol);
|
||||
}
|
95
linker.web/src/views/devices/devices.js
Normal file
95
linker.web/src/views/devices/devices.js
Normal file
@@ -0,0 +1,95 @@
|
||||
import { getSignInList, signInDel } from "@/apis/signin";
|
||||
import { injectGlobalData } from "@/provide";
|
||||
import { computed, reactive } from "vue";
|
||||
|
||||
export const provideDevices = () => {
|
||||
|
||||
const globalData = injectGlobalData();
|
||||
const machineId = computed(() => globalData.value.config.Client.Id);
|
||||
const devices = reactive({
|
||||
timer: 0,
|
||||
page: {
|
||||
Request: {
|
||||
Page: 1, Size: +(localStorage.getItem('ps') || '10'),
|
||||
GroupId: globalData.value.groupid, Name: '', Ids: []
|
||||
},
|
||||
Count: 0,
|
||||
List: []
|
||||
},
|
||||
|
||||
showDeviceEdit: false,
|
||||
deviceInfo: null
|
||||
});
|
||||
const _getSignList = () => {
|
||||
devices.page.Request.GroupId = globalData.value.groupid;
|
||||
getSignInList(devices.page.Request).then((res) => {
|
||||
devices.page.Request = res.Request;
|
||||
devices.page.Count = res.Count;
|
||||
for (let j in res.List) {
|
||||
res.List[j].showTunnel = machineId.value != res.List[j].MachineId;
|
||||
res.List[j].showForward = machineId.value != res.List[j].MachineId;
|
||||
res.List[j].showSForward = machineId.value == res.List[j].MachineId;
|
||||
res.List[j].showDel = machineId.value != res.List[j].MachineId && res.List[j].Connected == false;
|
||||
res.List[j].isSelf = machineId.value == res.List[j].MachineId;
|
||||
}
|
||||
devices.page.List = res.List.sort((a, b) => b.Connected - a.Connected);
|
||||
}).catch((err) => { });
|
||||
}
|
||||
const _getSignList1 = () => {
|
||||
if (globalData.value.connected) {
|
||||
devices.page.Request.GroupId = globalData.value.groupid;
|
||||
getSignInList(devices.page.Request).then((res) => {
|
||||
for (let j in res.List) {
|
||||
const item = devices.page.List.filter(c => c.MachineId == res.List[j].MachineId)[0];
|
||||
if (item) {
|
||||
item.Connected = res.List[j].Connected;
|
||||
item.Version = res.List[j].Version;
|
||||
item.LastSignIn = res.List[j].LastSignIn;
|
||||
item.Args = res.List[j].Args;
|
||||
item.showTunnel = machineId.value != res.List[j].MachineId;
|
||||
item.showForward = machineId.value != res.List[j].MachineId;
|
||||
item.showSForward = machineId.value == res.List[j].MachineId;
|
||||
item.showDel = machineId.value != res.List[j].MachineId && res.List[j].Connected == false;
|
||||
item.isSelf = machineId.value == res.List[j].MachineId;
|
||||
}
|
||||
}
|
||||
devices.timer = setTimeout(_getSignList1, 5000);
|
||||
}).catch((err) => {
|
||||
devices.timer = setTimeout(_getSignList1, 5000);
|
||||
});
|
||||
} else {
|
||||
devices.timer = setTimeout(_getSignList1, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
const handleDeviceEdit = (row) => {
|
||||
devices.deviceInfo = row;
|
||||
devices.showDeviceEdit = true;
|
||||
}
|
||||
const handlePageChange = (page) => {
|
||||
if (page) {
|
||||
devices.page.Request.Page = page;
|
||||
}
|
||||
_getSignList();
|
||||
}
|
||||
const handlePageSizeChange = (size) => {
|
||||
if (size) {
|
||||
devices.page.Request.Size = size;
|
||||
localStorage.setItem('ps', size);
|
||||
}
|
||||
_getSignList();
|
||||
}
|
||||
const handleDel = (name) => {
|
||||
signInDel(name).then(() => {
|
||||
_getSignList();
|
||||
});
|
||||
}
|
||||
const clearDevicesTimeout = () => {
|
||||
clearTimeout(devices.timer);
|
||||
devices.timer = 0;
|
||||
}
|
||||
|
||||
return {
|
||||
devices, machineId, _getSignList, _getSignList1, handleDeviceEdit, handlePageChange, handlePageSizeChange, handleDel, clearDevicesTimeout
|
||||
}
|
||||
}
|
69
linker.web/src/views/devices/forward.js
Normal file
69
linker.web/src/views/devices/forward.js
Normal file
@@ -0,0 +1,69 @@
|
||||
import { getForwardInfo, testListenForwardInfo, testTargetForwardInfo } from "@/apis/forward";
|
||||
import { injectGlobalData } from "@/provide";
|
||||
import { inject, provide, ref } from "vue";
|
||||
|
||||
const forwardSymbol = Symbol();
|
||||
export const provideForward = () => {
|
||||
const globalData = injectGlobalData();
|
||||
const forward = ref({
|
||||
timer: 0,
|
||||
showEdit: false,
|
||||
showCopy: false,
|
||||
current: null,
|
||||
list: {},
|
||||
testTimer: 0,
|
||||
testTargetTimer: 0,
|
||||
});
|
||||
provide(forwardSymbol, forward);
|
||||
const _getForwardInfo = () => {
|
||||
if (globalData.value.connected) {
|
||||
getForwardInfo().then((res) => {
|
||||
forward.value.list = res;
|
||||
forward.value.timer = setTimeout(_getForwardInfo, 1000);
|
||||
}).catch(() => {
|
||||
forward.value.timer = setTimeout(_getForwardInfo, 1000);
|
||||
});
|
||||
} else {
|
||||
forward.value.timer = setTimeout(_getForwardInfo, 1000);
|
||||
}
|
||||
}
|
||||
const handleForwardEdit = (machineId, machineName) => {
|
||||
forward.value.current = machineId;
|
||||
forward.value.machineName = machineName;
|
||||
forward.value.showEdit = true;
|
||||
}
|
||||
const _testTargetForwardInfo = () => {
|
||||
clearTimeout(forward.value.testTargetTimer)
|
||||
testTargetForwardInfo(forward.value.current).then((res) => {
|
||||
forward.value.testTargetTimer = setTimeout(_testTargetForwardInfo, 5000);
|
||||
}).catch(() => {
|
||||
forward.value.testTargetTimer = setTimeout(_testTargetForwardInfo, 5000);
|
||||
});
|
||||
}
|
||||
const _testListenForwardInfo = () => {
|
||||
clearTimeout(forward.value.testTimer)
|
||||
testListenForwardInfo(forward.value.current).then((res) => {
|
||||
forward.value.testTimer = setTimeout(_testListenForwardInfo, 5000);
|
||||
}).catch(() => {
|
||||
forward.value.testTimer = setTimeout(_testListenForwardInfo, 5000);
|
||||
});
|
||||
}
|
||||
const clearForwardTimeout = () => {
|
||||
clearTimeout(forward.value.timer);
|
||||
clearTimeout(forward.value.testTimer);
|
||||
clearTimeout(forward.value.testTargetTimer);
|
||||
}
|
||||
|
||||
const getForwardMachines = (name) => {
|
||||
return Object.values(forward.value.list)
|
||||
.filter(c => (c.Name || '').indexOf(name) >= 0 || (c.BindIPAddress || '').indexOf(name) >= 0 || (c.Port.toString()).indexOf(name) >= 0 || (c.TargetEP || '').indexOf(name) >= 0)
|
||||
.map(c => c.MachineId);
|
||||
}
|
||||
|
||||
return {
|
||||
forward, _getForwardInfo, handleForwardEdit, _testTargetForwardInfo, _testListenForwardInfo, clearForwardTimeout, getForwardMachines
|
||||
}
|
||||
}
|
||||
export const useForward = () => {
|
||||
return inject(forwardSymbol);
|
||||
}
|
61
linker.web/src/views/devices/sforward.js
Normal file
61
linker.web/src/views/devices/sforward.js
Normal file
@@ -0,0 +1,61 @@
|
||||
|
||||
import { getSForwardInfo, testLocalSForwardInfo } from '@/apis/sforward';
|
||||
import { injectGlobalData } from '@/provide';
|
||||
import { ref, provide, inject, computed } from 'vue';
|
||||
|
||||
const sforwardSymbol = Symbol();
|
||||
export const provideSforward = () => {
|
||||
const globalData = injectGlobalData();
|
||||
const machineId = computed(() => globalData.value.config.Client.Id);
|
||||
const sforward = ref({
|
||||
timer: 0,
|
||||
showEdit: false,
|
||||
showCopy: false,
|
||||
list: [],
|
||||
testTimer: 0
|
||||
});
|
||||
provide(sforwardSymbol, sforward);
|
||||
const _getSForwardInfo = () => {
|
||||
if (globalData.value.connected) {
|
||||
getSForwardInfo().then((res) => {
|
||||
sforward.value.list = res;
|
||||
sforward.value.timer = setTimeout(_getSForwardInfo, 1000);
|
||||
}).catch(() => {
|
||||
sforward.value.timer = setTimeout(_getSForwardInfo, 1000);
|
||||
});
|
||||
} else {
|
||||
sforward.value.timer = setTimeout(_getSForwardInfo, 1000);
|
||||
}
|
||||
}
|
||||
const handleSForwardEdit = () => {
|
||||
sforward.value.showEdit = true;
|
||||
}
|
||||
const _testLocalSForwardInfo = () => {
|
||||
clearTimeout(sforward.value.testTimer)
|
||||
testLocalSForwardInfo().then((res) => {
|
||||
sforward.value.testTimer = setTimeout(_testLocalSForwardInfo, 5000);
|
||||
}).catch(() => {
|
||||
sforward.value.testTimer = setTimeout(_testLocalSForwardInfo, 5000);
|
||||
});
|
||||
}
|
||||
const clearSForwardTimeout = () => {
|
||||
clearTimeout(sforward.value.timer);
|
||||
clearTimeout(sforward.value.testTimer);
|
||||
}
|
||||
const getSForwardMachines = (name) => {
|
||||
const sfs = sforward.value.list
|
||||
.filter(c => (c.Name || '').indexOf(name) >= 0 || (c.Domain || '').indexOf(name) >= 0 || (c.RemotePort.toString()).indexOf(name) >= 0 || c.LocalEP.indexOf(name) >= 0);
|
||||
|
||||
if (sfs.length > 0) {
|
||||
return [machineId.value];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
return {
|
||||
sforward, _getSForwardInfo, handleSForwardEdit, _testLocalSForwardInfo, clearSForwardTimeout, getSForwardMachines
|
||||
}
|
||||
|
||||
}
|
||||
export const useSforward = () => {
|
||||
return inject(sforwardSymbol);
|
||||
}
|
49
linker.web/src/views/devices/tunnel.js
Normal file
49
linker.web/src/views/devices/tunnel.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import { getTunnelInfo, refreshTunnel } from "@/apis/tunnel";
|
||||
import { injectGlobalData } from "@/provide";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { inject, provide, ref } from "vue";
|
||||
|
||||
const tunnelSymbol = Symbol();
|
||||
export const provideTunnel = () => {
|
||||
const globalData = injectGlobalData();
|
||||
const tunnel = ref({
|
||||
timer: 0,
|
||||
showEdit: false,
|
||||
current: null,
|
||||
list: {},
|
||||
hashcode: 0,
|
||||
});
|
||||
provide(tunnelSymbol, tunnel);
|
||||
const _getTunnelInfo = () => {
|
||||
if (globalData.value.connected) {
|
||||
getTunnelInfo(tunnel.value.hashcode.toString()).then((res) => {
|
||||
tunnel.value.hashcode = res.HashCode;
|
||||
if (res.List) {
|
||||
tunnel.value.list = res.List;
|
||||
}
|
||||
tunnel.value.timer = setTimeout(_getTunnelInfo, 1000);
|
||||
}).catch(() => {
|
||||
tunnel.value.timer = setTimeout(_getTunnelInfo, 1000);
|
||||
});
|
||||
} else {
|
||||
tunnel.value.timer = setTimeout(_getTunnelInfo, 1000);
|
||||
}
|
||||
}
|
||||
const handleTunnelEdit = (_tunnel) => {
|
||||
tunnel.value.current = _tunnel;
|
||||
tunnel.value.showEdit = true;
|
||||
}
|
||||
const handleTunnelRefresh = () => {
|
||||
refreshTunnel();
|
||||
ElMessage.success({ message: '刷新成功', grouping: true });
|
||||
}
|
||||
const clearTunnelTimeout = () => {
|
||||
clearTimeout(tunnel.value.timer);
|
||||
}
|
||||
return {
|
||||
tunnel, _getTunnelInfo, handleTunnelEdit, handleTunnelRefresh, clearTunnelTimeout
|
||||
}
|
||||
}
|
||||
export const useTunnel = () => {
|
||||
return inject(tunnelSymbol);
|
||||
}
|
62
linker.web/src/views/devices/tuntap.js
Normal file
62
linker.web/src/views/devices/tuntap.js
Normal file
@@ -0,0 +1,62 @@
|
||||
import { injectGlobalData } from "@/provide";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { inject, provide, ref } from "vue"
|
||||
import { getTuntapInfo, refreshTuntap } from "@/apis/tuntap";
|
||||
|
||||
const tuntapSymbol = Symbol();
|
||||
export const provideTuntap = () => {
|
||||
const globalData = injectGlobalData();
|
||||
const tuntap = ref({
|
||||
timer: 0,
|
||||
showEdit: false,
|
||||
current: null,
|
||||
list: {},
|
||||
hashcode: 0
|
||||
});
|
||||
provide(tuntapSymbol, tuntap);
|
||||
const _getTuntapInfo = () => {
|
||||
clearTimeout(tuntap.value.timer);
|
||||
if (globalData.value.connected) {
|
||||
getTuntapInfo(tuntap.value.hashcode.toString()).then((res) => {
|
||||
tuntap.value.hashcode = res.HashCode;
|
||||
if (res.List) {
|
||||
for (let j in res.List) {
|
||||
res.List[j].running = res.List[j].Status == 2;
|
||||
res.List[j].loading = res.List[j].Status == 1;
|
||||
}
|
||||
tuntap.value.list = res.List;
|
||||
}
|
||||
tuntap.value.timer = setTimeout(_getTuntapInfo, 200);
|
||||
}).catch(() => {
|
||||
tuntap.value.timer = setTimeout(_getTuntapInfo, 200);
|
||||
});
|
||||
} else {
|
||||
tuntap.value.timer = setTimeout(_getTuntapInfo, 1000);
|
||||
}
|
||||
}
|
||||
const handleTuntapEdit = (_tuntap) => {
|
||||
tuntap.value.current = _tuntap;
|
||||
tuntap.value.showEdit = true;
|
||||
|
||||
}
|
||||
const handleTuntapRefresh = () => {
|
||||
refreshTuntap();
|
||||
ElMessage.success({ message: '刷新成功', grouping: true });
|
||||
}
|
||||
const clearTuntapTimeout = () => {
|
||||
clearTimeout(tuntap.value.timer);
|
||||
tuntap.value.timer = 0;
|
||||
}
|
||||
const getTuntapMachines = (name) => {
|
||||
return Object.values(tuntap.value.list)
|
||||
.filter(c => c.IP.indexOf(name) >= 0 || (c.LanIPs.filter(d => d.indexOf(name) >= 0).length > 0))
|
||||
.map(c => c.MachineId);
|
||||
}
|
||||
return {
|
||||
tuntap, _getTuntapInfo, handleTuntapEdit, handleTuntapRefresh, clearTuntapTimeout, getTuntapMachines
|
||||
}
|
||||
}
|
||||
|
||||
export const useTuntap = () => {
|
||||
return inject(tuntapSymbol);
|
||||
}
|
@@ -1,4 +1,5 @@
|
||||
<template>
|
||||
<Version ckey="excludeIPConfig"/>
|
||||
<el-table :data="state.list" border size="small" width="100%" :height="`${state.height}px`" @cell-dblclick="handleCellClick">
|
||||
<el-table-column prop="IPAddress" label="IP">
|
||||
<template #default="scope">
|
||||
@@ -43,16 +44,18 @@ import { setTunnelExcludeIPs } from '@/apis/tunnel';
|
||||
import { injectGlobalData } from '@/provide';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { computed, inject, onMounted, reactive } from 'vue'
|
||||
import Version from './Version.vue';
|
||||
export default {
|
||||
label:'打洞排除IP',
|
||||
name:'excludeIP',
|
||||
order:3,
|
||||
components:{Version},
|
||||
setup(props) {
|
||||
const globalData = injectGlobalData();
|
||||
const state = reactive({
|
||||
list:((globalData.value.config.Running.Tunnel || {ExcludeIPs:[]}).ExcludeIPs || [{IPAddress:'0.0.0.0',Mask:32}]),
|
||||
types:[],
|
||||
height: computed(()=>globalData.value.height-92)
|
||||
height: computed(()=>globalData.value.height-127)
|
||||
});
|
||||
|
||||
const handleCellClick = (row, column) => {
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<template>
|
||||
<Version ckey="relayServers"/>
|
||||
<el-table :data="state.list" border size="small" width="100%" :height="`${state.height}px`" @cell-dblclick="handleCellClick">
|
||||
<el-table-column prop="Name" label="名称" width="100">
|
||||
<template #default="scope">
|
||||
@@ -81,16 +82,18 @@ import { setRelayServers,getRelayTypes } from '@/apis/relay';
|
||||
import { injectGlobalData } from '@/provide';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { computed, inject, onMounted, reactive } from 'vue'
|
||||
import Version from './Version.vue';
|
||||
export default {
|
||||
label:'中继服务器',
|
||||
name:'relayServers',
|
||||
order:4,
|
||||
components:{Version},
|
||||
setup(props) {
|
||||
const globalData = injectGlobalData();
|
||||
const state = reactive({
|
||||
list:((globalData.value.config.Running.Relay || {Servers:[]}).Servers || []).sort((a,b)=>a.Disabled - b.Disabled),
|
||||
types:[],
|
||||
height: computed(()=>globalData.value.height-92)
|
||||
height: computed(()=>globalData.value.height-127)
|
||||
});
|
||||
|
||||
const _getRelayTypes = ()=>{
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<template>
|
||||
<Version ckey="sforwardKey"/>
|
||||
<div style="width: 30rem;padding: 5rem 0; margin: 0 auto;">
|
||||
<p class="t-c">
|
||||
服务器代理穿透密钥
|
||||
@@ -13,10 +14,12 @@ import { getSForwardSecretKey,setSForwardSecretKey } from '@/apis/sforward';
|
||||
import { injectGlobalData } from '@/provide';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { computed, inject, onMounted, reactive } from 'vue'
|
||||
import Version from './Version.vue';
|
||||
export default {
|
||||
label:'服务器代理穿透',
|
||||
name:'sforward',
|
||||
order:5,
|
||||
components:{Version},
|
||||
setup(props) {
|
||||
const globalData = injectGlobalData();
|
||||
const state = reactive({
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<template>
|
||||
<Version ckey="signServers"/>
|
||||
<el-table :data="state.list" border size="small" width="100%" :height="`${state.height}px`" @cell-dblclick="handleCellClick">
|
||||
<el-table-column prop="Name" label="名称">
|
||||
<template #default="scope">
|
||||
@@ -50,16 +51,18 @@ import { setSignInServers } from '@/apis/signin';
|
||||
import { injectGlobalData } from '@/provide';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { computed, inject, reactive } from 'vue'
|
||||
import Version from './Version.vue';
|
||||
export default {
|
||||
label:'信标服务器',
|
||||
name:'signInServers',
|
||||
order:0,
|
||||
components:{Version},
|
||||
setup(props) {
|
||||
const globalData = injectGlobalData();
|
||||
const state = reactive({
|
||||
list:globalData.value.config.Running.Client.Servers || [],
|
||||
server:computed(()=>globalData.value.config.Client.Server),
|
||||
height: computed(()=>globalData.value.height-92),
|
||||
height: computed(()=>globalData.value.height-127),
|
||||
});
|
||||
|
||||
const handleCellClick = (row, column) => {
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<template>
|
||||
<Version ckey="tunnelTransports"/>
|
||||
<el-table :data="state.list" border size="small" width="100%" :height="`${state.height}px`" >
|
||||
<el-table-column prop="Name" label="名称" width="120"></el-table-column>
|
||||
<el-table-column prop="Label" label="说明"></el-table-column>
|
||||
@@ -44,15 +45,17 @@ import { getTunnelTransports,setTunnelTransports } from '@/apis/tunnel';
|
||||
import { injectGlobalData } from '@/provide';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { computed, inject, onMounted, reactive } from 'vue'
|
||||
import Version from './Version.vue';
|
||||
export default {
|
||||
label:'打洞协议',
|
||||
name:'transports',
|
||||
order:2,
|
||||
components:{Version},
|
||||
setup(props) {
|
||||
const globalData = injectGlobalData();
|
||||
const state = reactive({
|
||||
list:[],
|
||||
height: computed(()=>globalData.value.height-92),
|
||||
height: computed(()=>globalData.value.height-127),
|
||||
bufferSize:globalData.value.bufferSize
|
||||
});
|
||||
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<template>
|
||||
<Version ckey="tunnelWanPortProtocols"/>
|
||||
<el-table :data="state.list" border size="small" width="100%" :height="`${state.height}px`" @cell-dblclick="handleCellClick">
|
||||
<el-table-column prop="Name" label="名称">
|
||||
<template #default="scope">
|
||||
@@ -78,17 +79,19 @@ import { setTunnelServers,getTunnelTypes } from '@/apis/tunnel';
|
||||
import { injectGlobalData } from '@/provide';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { computed, inject, onMounted, reactive } from 'vue'
|
||||
import Version from './Version.vue';
|
||||
export default {
|
||||
label:'外网端口服务器',
|
||||
name:'tunnelServers',
|
||||
order:1,
|
||||
components:{Version},
|
||||
setup(props) {
|
||||
const globalData = injectGlobalData();
|
||||
const list = ((globalData.value.config.Running.Tunnel || {Servers:[]}).Servers || []).sort((a,b)=>a.Disabled - b.Disabled);
|
||||
const state = reactive({
|
||||
list:list,
|
||||
types:[],
|
||||
height: computed(()=>globalData.value.height-92)
|
||||
height: computed(()=>globalData.value.height-127)
|
||||
});
|
||||
|
||||
const _getTunnelTypes = ()=>{
|
||||
|
50
linker.web/src/views/settings/Version.vue
Normal file
50
linker.web/src/views/settings/Version.vue
Normal file
@@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<div class="running-version-wrap">
|
||||
<span>配置版本 : {{version}}</span>
|
||||
<el-button size="small" @click=handleEdit>手动修改版本</el-button>
|
||||
<span>高版本一端自动同步到低版本一端</span>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import {updateVersion} from '@/apis/running'
|
||||
import { injectGlobalData } from '@/provide';
|
||||
import { ElMessageBox } from 'element-plus';
|
||||
import { computed } from 'vue'
|
||||
export default {
|
||||
props:['ckey'],
|
||||
setup(props) {
|
||||
const globalData = injectGlobalData();
|
||||
const version = computed(()=>globalData.value.config.Running.Versions[props.ckey]);
|
||||
|
||||
|
||||
const handleEdit = () => {
|
||||
ElMessageBox.prompt('输入你要修改到的版本', '修改版本', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
inputValue:version.value,
|
||||
inputPattern:/\d+/,
|
||||
inputErrorMessage: 'Invalid Number',
|
||||
}).then(({ value }) => {
|
||||
value = +value;
|
||||
if(isNaN(value)) return ;
|
||||
updateVersion({key:props.ckey,version:value});
|
||||
}).catch(()=>{
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
version,handleEdit
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="stylus" scoped>
|
||||
.running-version-wrap{
|
||||
span{
|
||||
vertical-align:middle
|
||||
}
|
||||
padding:0 0 1rem 0;
|
||||
line-height:2.4rem
|
||||
}
|
||||
</style>
|
@@ -176,6 +176,7 @@ namespace linker.client
|
||||
public async Task UpdateServers(ClientServerInfo[] servers)
|
||||
{
|
||||
await SetServers(servers);
|
||||
runningConfigTransfer.IncrementVersion(configKey);
|
||||
SyncServers();
|
||||
}
|
||||
private void SetServers(Memory<byte> data)
|
||||
|
@@ -5,6 +5,7 @@ using System.Reflection;
|
||||
using linker.client.args;
|
||||
using linker.client.config;
|
||||
using linker.config;
|
||||
using linker.client.config.messenger;
|
||||
|
||||
namespace linker.client
|
||||
{
|
||||
@@ -23,6 +24,8 @@ namespace linker.client
|
||||
{
|
||||
serviceCollection.AddSingleton<RunningConfig>();
|
||||
serviceCollection.AddSingleton<RunningConfigTransfer>();
|
||||
serviceCollection.AddSingleton<ConfigClientMessenger>();
|
||||
serviceCollection.AddSingleton<RunningConfigApiController>();
|
||||
|
||||
serviceCollection.AddSingleton<SignInArgsTransfer>();
|
||||
|
||||
@@ -43,7 +46,7 @@ namespace linker.client
|
||||
|
||||
public void AddServer(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
|
||||
{
|
||||
|
||||
serviceCollection.AddSingleton<ConfigServerMessenger>();
|
||||
}
|
||||
public void UseServer(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
|
||||
{
|
||||
|
28
linker/client/config/RunningConfigApiController.cs
Normal file
28
linker/client/config/RunningConfigApiController.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using linker.libs.api;
|
||||
using linker.client.capi;
|
||||
using linker.libs.extends;
|
||||
|
||||
namespace linker.client.config
|
||||
{
|
||||
public sealed class RunningConfigApiController : IApiClientController
|
||||
{
|
||||
private readonly RunningConfigTransfer runningConfigTransfer;
|
||||
|
||||
public RunningConfigApiController(RunningConfigTransfer runningConfigTransfer)
|
||||
{
|
||||
this.runningConfigTransfer = runningConfigTransfer;
|
||||
}
|
||||
|
||||
public void UpdateVersion(ApiControllerParamsInfo param)
|
||||
{
|
||||
UpdateVersionInfo info = param.Content.DeJson<UpdateVersionInfo>();
|
||||
runningConfigTransfer.UpdateVersion(info.Key, info.Version);
|
||||
}
|
||||
|
||||
public sealed class UpdateVersionInfo
|
||||
{
|
||||
public string Key { get; set; }
|
||||
public ulong Version { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
@@ -2,7 +2,6 @@
|
||||
using linker.libs;
|
||||
using linker.server;
|
||||
using MemoryPack;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace linker.client.config
|
||||
@@ -45,7 +44,7 @@ namespace linker.client.config
|
||||
|
||||
public Memory<byte> InputConfig(ConfigVersionInfo info)
|
||||
{
|
||||
CheckVersion(info.Key, out ulong version);
|
||||
ulong version = GetVersion(info.Key);
|
||||
|
||||
if (setters.TryGetValue(info.Key, out Action<Memory<byte>> setter) && info.Version > version)
|
||||
{
|
||||
@@ -54,7 +53,12 @@ namespace linker.client.config
|
||||
}
|
||||
else if (getters.TryGetValue(info.Key, out Func<Memory<byte>> getter) && version > info.Version)
|
||||
{
|
||||
return getter();
|
||||
return MemoryPackSerializer.Serialize(new ConfigVersionInfo
|
||||
{
|
||||
Data = getter(),
|
||||
Key = info.Key,
|
||||
Version = version
|
||||
});
|
||||
}
|
||||
|
||||
return Helper.EmptyArray;
|
||||
@@ -64,8 +68,7 @@ namespace linker.client.config
|
||||
private object syncLockObj = new();
|
||||
public void Sync(string key, Memory<byte> data)
|
||||
{
|
||||
CheckVersion(key, out ulong version);
|
||||
|
||||
ulong version = GetVersion(key);
|
||||
sender.SendReply(new MessageRequestWrap
|
||||
{
|
||||
Connection = clientSignInState.Connection,
|
||||
@@ -93,31 +96,25 @@ namespace linker.client.config
|
||||
});
|
||||
}
|
||||
|
||||
private void CheckVersion(string key, out ulong version)
|
||||
{
|
||||
if (runningConfig.Data.Versions.TryGetValue(key, out version) == false)
|
||||
{
|
||||
version = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
version++;
|
||||
}
|
||||
runningConfig.Data.Versions[key] = version;
|
||||
runningConfig.Data.Update();
|
||||
}
|
||||
private ulong GetVersion(string key)
|
||||
{
|
||||
if (runningConfig.Data.Versions.TryGetValue(key, out ulong version) == false)
|
||||
{
|
||||
return 0;
|
||||
version = 1;
|
||||
runningConfig.Data.Versions[key] = version;
|
||||
runningConfig.Data.Update();
|
||||
}
|
||||
return version;
|
||||
}
|
||||
private void UpdateVersion(string key, ulong version)
|
||||
public void UpdateVersion(string key, ulong version)
|
||||
{
|
||||
runningConfig.Data.Versions[key] = version;
|
||||
runningConfig.Data.Update();
|
||||
}
|
||||
public void IncrementVersion(string key)
|
||||
{
|
||||
ulong version = GetVersion(key);
|
||||
UpdateVersion(key, version + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -7,6 +7,10 @@ using linker.libs;
|
||||
using linker.plugins.forward.proxy;
|
||||
using linker.tunnel.connection;
|
||||
using System.Collections.Concurrent;
|
||||
using linker.plugins.forward.messenger;
|
||||
using linker.server;
|
||||
using linker.client;
|
||||
using MemoryPack;
|
||||
|
||||
namespace linker.plugins.forward
|
||||
{
|
||||
@@ -14,11 +18,15 @@ namespace linker.plugins.forward
|
||||
{
|
||||
private readonly ForwardTransfer forwardTransfer;
|
||||
private readonly ForwardProxy forwardProxy;
|
||||
private readonly MessengerSender messengerSender;
|
||||
private readonly ClientSignInState clientSignInState;
|
||||
|
||||
public ForwardClientApiController(ForwardTransfer forwardTransfer, ForwardProxy forwardProxy)
|
||||
public ForwardClientApiController(ForwardTransfer forwardTransfer, ForwardProxy forwardProxy, MessengerSender messengerSender, ClientSignInState clientSignInState)
|
||||
{
|
||||
this.forwardTransfer = forwardTransfer;
|
||||
this.forwardProxy = forwardProxy;
|
||||
this.messengerSender = messengerSender;
|
||||
this.clientSignInState = clientSignInState;
|
||||
}
|
||||
|
||||
public ConcurrentDictionary<string, ITunnelConnection> Connections(ApiControllerParamsInfo param)
|
||||
@@ -51,6 +59,21 @@ namespace linker.plugins.forward
|
||||
{
|
||||
return forwardTransfer.Get();
|
||||
}
|
||||
public async Task<List<ForwardRemoteInfo>> GetRemote(ApiControllerParamsInfo param)
|
||||
{
|
||||
GetForwardInfo request = param.Content.DeJson<GetForwardInfo>();
|
||||
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
|
||||
{
|
||||
Connection = clientSignInState.Connection,
|
||||
MessengerId = (ushort)ForwardMessengerIds.GetForward,
|
||||
Payload = MemoryPackSerializer.Serialize(request)
|
||||
}).ConfigureAwait(false);
|
||||
if (resp.Code == MessageResponeCodes.OK)
|
||||
{
|
||||
return MemoryPackSerializer.Deserialize<List<ForwardRemoteInfo>>(resp.Data.Span);
|
||||
}
|
||||
return new List<ForwardRemoteInfo>();
|
||||
}
|
||||
|
||||
public IPAddress[] BindIPs(ApiControllerParamsInfo param)
|
||||
{
|
||||
@@ -62,7 +85,6 @@ namespace linker.plugins.forward
|
||||
ForwardInfo info = param.Content.DeJson<ForwardInfo>();
|
||||
return forwardTransfer.Add(info);
|
||||
}
|
||||
|
||||
public bool Remove(ApiControllerParamsInfo param)
|
||||
{
|
||||
if (uint.TryParse(param.Content, out uint id))
|
||||
|
@@ -40,4 +40,10 @@ namespace linker.client.config
|
||||
public List<IPEndPoint> EndPoints { get; set; }
|
||||
}
|
||||
|
||||
[MemoryPackable]
|
||||
public sealed partial class GetForwardInfo
|
||||
{
|
||||
public string MachineId { get; set; }
|
||||
public string ToMachineId { get; set; }
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,9 @@
|
||||
using linker.client.config;
|
||||
using linker.plugins.signin.messenger;
|
||||
using linker.server;
|
||||
using LiteDB;
|
||||
using MemoryPack;
|
||||
using System.Net;
|
||||
|
||||
namespace linker.plugins.forward.messenger
|
||||
{
|
||||
@@ -45,6 +47,34 @@ namespace linker.plugins.forward.messenger
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[MessengerId((ushort)ForwardMessengerIds.GetForward)]
|
||||
public void GetForward(IConnection connection)
|
||||
{
|
||||
GetForwardInfo info = MemoryPackSerializer.Deserialize<GetForwardInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
||||
if (signCaching.TryGet(info.MachineId, out SignCacheInfo cache) && signCaching.TryGet(connection.Id, out SignCacheInfo cache1) && cache1.GroupId == cache.GroupId)
|
||||
{
|
||||
uint requestid = connection.ReceiveRequestWrap.RequestId;
|
||||
sender.SendReply(new MessageRequestWrap
|
||||
{
|
||||
Connection = cache.Connection,
|
||||
MessengerId = (ushort)ForwardMessengerIds.Get,
|
||||
Payload = connection.ReceiveRequestWrap.Payload
|
||||
}).ContinueWith(async (result) =>
|
||||
{
|
||||
if (result.Result.Code == MessageResponeCodes.OK)
|
||||
{
|
||||
await sender.ReplyOnly(new MessageResponseWrap
|
||||
{
|
||||
Connection = connection,
|
||||
Code = MessageResponeCodes.OK,
|
||||
Payload = result.Result.Data,
|
||||
RequestId = requestid
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ForwardClientMessenger : IMessenger
|
||||
@@ -75,7 +105,31 @@ namespace linker.plugins.forward.messenger
|
||||
}).ConfigureAwait(false);
|
||||
});
|
||||
}
|
||||
|
||||
[MessengerId((ushort)ForwardMessengerIds.Get)]
|
||||
public void Get(IConnection connection)
|
||||
{
|
||||
GetForwardInfo info = MemoryPackSerializer.Deserialize<GetForwardInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
||||
if (forwardTransfer.Get().TryGetValue(info.ToMachineId, out List<ForwardInfo> list))
|
||||
{
|
||||
var result = list.Select(c => new ForwardRemoteInfo { BufferSize = c.BufferSize, Name = c.Name, Port = c.Port, TargetEP = c.TargetEP }).ToList();
|
||||
connection.Write(MemoryPackSerializer.Serialize(result));
|
||||
return;
|
||||
}
|
||||
connection.Write(MemoryPackSerializer.Serialize(new List<ForwardRemoteInfo>()));
|
||||
}
|
||||
}
|
||||
|
||||
[MemoryPackable]
|
||||
public sealed partial class ForwardRemoteInfo
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Port { get; set; }
|
||||
|
||||
[MemoryPackAllowSerialize]
|
||||
public IPEndPoint TargetEP { get; set; }
|
||||
|
||||
public byte BufferSize { get; set; } = 3;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -7,6 +7,9 @@
|
||||
TestForward = 2401,
|
||||
Test = 2402,
|
||||
|
||||
GetForward = 2403,
|
||||
Get = 2404,
|
||||
|
||||
Max = 2499
|
||||
}
|
||||
}
|
||||
|
@@ -85,6 +85,7 @@ namespace linker.plugins.relay
|
||||
{
|
||||
running.Data.Relay.Servers = servers;
|
||||
running.Data.Update();
|
||||
runningConfigTransfer.IncrementVersion(configKey);
|
||||
SyncServers();
|
||||
}
|
||||
private void SetServers(Memory<byte> data)
|
||||
|
@@ -2,24 +2,22 @@
|
||||
using linker.libs.extends;
|
||||
using linker.client.capi;
|
||||
using linker.client.config;
|
||||
using linker.server;
|
||||
using linker.client;
|
||||
using linker.plugins.sforward.messenger;
|
||||
using linker.server;
|
||||
using MemoryPack;
|
||||
using linker.plugins.sforward.messenger;
|
||||
|
||||
namespace linker.plugins.sforward
|
||||
{
|
||||
public sealed class SForwardClientApiController : IApiClientController
|
||||
{
|
||||
private readonly SForwardTransfer forwardTransfer;
|
||||
private readonly RunningConfig runningConfig;
|
||||
private readonly MessengerSender messengerSender;
|
||||
private readonly ClientSignInState clientSignInState;
|
||||
|
||||
public SForwardClientApiController(SForwardTransfer forwardTransfer, RunningConfig runningConfig, MessengerSender messengerSender, ClientSignInState clientSignInState)
|
||||
public SForwardClientApiController(SForwardTransfer forwardTransfer, MessengerSender messengerSender, ClientSignInState clientSignInState)
|
||||
{
|
||||
this.forwardTransfer = forwardTransfer;
|
||||
this.runningConfig = runningConfig;
|
||||
this.messengerSender = messengerSender;
|
||||
this.clientSignInState = clientSignInState;
|
||||
}
|
||||
@@ -38,6 +36,20 @@ namespace linker.plugins.sforward
|
||||
{
|
||||
return forwardTransfer.Get();
|
||||
}
|
||||
public async Task<List<SForwardRemoteInfo>> GetRemote(ApiControllerParamsInfo param)
|
||||
{
|
||||
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
|
||||
{
|
||||
Connection = clientSignInState.Connection,
|
||||
MessengerId = (ushort)SForwardMessengerIds.GetForward,
|
||||
Payload = MemoryPackSerializer.Serialize(param.Content)
|
||||
}).ConfigureAwait(false);
|
||||
if (resp.Code == MessageResponeCodes.OK)
|
||||
{
|
||||
return MemoryPackSerializer.Deserialize<List<SForwardRemoteInfo>>(resp.Data.Span);
|
||||
}
|
||||
return new List<SForwardRemoteInfo>();
|
||||
}
|
||||
|
||||
public bool Add(ApiControllerParamsInfo param)
|
||||
{
|
||||
|
@@ -46,6 +46,7 @@ namespace linker.plugins.sforward
|
||||
{
|
||||
running.Data.SForwardSecretKey = key;
|
||||
running.Data.Update();
|
||||
runningConfigTransfer.IncrementVersion(configKey);
|
||||
SyncKey();
|
||||
}
|
||||
private void SetSecretKey(Memory<byte> data)
|
||||
@@ -237,7 +238,6 @@ namespace linker.plugins.sforward
|
||||
Start();
|
||||
running.Data.SForwards.Remove(old);
|
||||
running.Data.Update();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@@ -6,6 +6,9 @@ using linker.server;
|
||||
using MemoryPack;
|
||||
using linker.plugins.sforward.proxy;
|
||||
using linker.config;
|
||||
using LiteDB;
|
||||
using System.Net;
|
||||
using linker.plugins.forward.messenger;
|
||||
|
||||
namespace linker.plugins.sforward.messenger
|
||||
{
|
||||
@@ -151,6 +154,34 @@ namespace linker.plugins.sforward.messenger
|
||||
}
|
||||
}
|
||||
|
||||
[MessengerId((ushort)SForwardMessengerIds.GetForward)]
|
||||
public void GetForward(IConnection connection)
|
||||
{
|
||||
string machineId = MemoryPackSerializer.Deserialize<string>(connection.ReceiveRequestWrap.Payload.Span);
|
||||
if (signCaching.TryGet(machineId, out SignCacheInfo cache) && signCaching.TryGet(connection.Id, out SignCacheInfo cache1) && cache1.GroupId == cache.GroupId)
|
||||
{
|
||||
uint requestid = connection.ReceiveRequestWrap.RequestId;
|
||||
sender.SendReply(new MessageRequestWrap
|
||||
{
|
||||
Connection = cache.Connection,
|
||||
MessengerId = (ushort)SForwardMessengerIds.Get,
|
||||
Payload = connection.ReceiveRequestWrap.Payload
|
||||
}).ContinueWith(async (result) =>
|
||||
{
|
||||
if (result.Result.Code == MessageResponeCodes.OK)
|
||||
{
|
||||
await sender.ReplyOnly(new MessageResponseWrap
|
||||
{
|
||||
Connection = connection,
|
||||
Code = MessageResponeCodes.OK,
|
||||
Payload = result.Result.Data,
|
||||
RequestId = requestid
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> WebConnect(string host, int port, ulong id)
|
||||
{
|
||||
if (sForwardServerCahing.TryGet(host, out string machineId) && signCaching.TryGet(machineId, out SignCacheInfo sign) && sign.Connected)
|
||||
@@ -159,7 +190,7 @@ namespace linker.plugins.sforward.messenger
|
||||
{
|
||||
Connection = sign.Connection,
|
||||
MessengerId = (ushort)SForwardMessengerIds.Proxy,
|
||||
Payload = MemoryPackSerializer.Serialize(new SForwardProxyInfo { Domain = host, RemotePort = port, Id = id, BufferSize= configWrap.Data.Server.SForward.BufferSize })
|
||||
Payload = MemoryPackSerializer.Serialize(new SForwardProxyInfo { Domain = host, RemotePort = port, Id = id, BufferSize = configWrap.Data.Server.SForward.BufferSize })
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
return false;
|
||||
@@ -196,11 +227,13 @@ namespace linker.plugins.sforward.messenger
|
||||
{
|
||||
private readonly SForwardProxy proxy;
|
||||
private readonly RunningConfig runningConfig;
|
||||
private readonly SForwardTransfer sForwardTransfer;
|
||||
|
||||
public SForwardClientMessenger(SForwardProxy proxy, RunningConfig runningConfig)
|
||||
public SForwardClientMessenger(SForwardProxy proxy, RunningConfig runningConfig, SForwardTransfer sForwardTransfer)
|
||||
{
|
||||
this.proxy = proxy;
|
||||
this.runningConfig = runningConfig;
|
||||
this.sForwardTransfer = sForwardTransfer;
|
||||
}
|
||||
|
||||
[MessengerId((ushort)SForwardMessengerIds.Proxy)]
|
||||
@@ -213,7 +246,7 @@ namespace linker.plugins.sforward.messenger
|
||||
SForwardInfo sForwardInfo = runningConfig.Data.SForwards.FirstOrDefault(c => c.Domain == sForwardProxyInfo.Domain);
|
||||
if (sForwardInfo != null)
|
||||
{
|
||||
_ = proxy.OnConnectTcp(sForwardProxyInfo.BufferSize,sForwardProxyInfo.Id, new System.Net.IPEndPoint(connection.Address.Address, sForwardProxyInfo.RemotePort), sForwardInfo.LocalEP);
|
||||
_ = proxy.OnConnectTcp(sForwardProxyInfo.BufferSize, sForwardProxyInfo.Id, new System.Net.IPEndPoint(connection.Address.Address, sForwardProxyInfo.RemotePort), sForwardInfo.LocalEP);
|
||||
}
|
||||
}
|
||||
else if (sForwardProxyInfo.RemotePort > 0)
|
||||
@@ -225,6 +258,7 @@ namespace linker.plugins.sforward.messenger
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MessengerId((ushort)SForwardMessengerIds.ProxyUdp)]
|
||||
public void ProxyUdp(IConnection connection)
|
||||
{
|
||||
@@ -238,5 +272,33 @@ namespace linker.plugins.sforward.messenger
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MessengerId((ushort)SForwardMessengerIds.Get)]
|
||||
public void Get(IConnection connection)
|
||||
{
|
||||
List<SForwardRemoteInfo> result = sForwardTransfer.Get().Select(c => new SForwardRemoteInfo
|
||||
{
|
||||
BufferSize = c.BufferSize,
|
||||
Domain = c.Domain,
|
||||
LocalEP = c.LocalEP,
|
||||
Name = c.Name,
|
||||
RemotePort = c.RemotePort,
|
||||
}).ToList();
|
||||
connection.Write(MemoryPackSerializer.Serialize(result));
|
||||
}
|
||||
}
|
||||
|
||||
[MemoryPackable]
|
||||
public sealed partial class SForwardRemoteInfo
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Domain { get; set; }
|
||||
public int RemotePort { get; set; }
|
||||
|
||||
public byte BufferSize { get; set; } = 3;
|
||||
|
||||
[MemoryPackAllowSerialize]
|
||||
public IPEndPoint LocalEP { get; set; }
|
||||
}
|
||||
}
|
||||
|
@@ -10,6 +10,9 @@
|
||||
Proxy = 2303,
|
||||
ProxyUdp = 2304,
|
||||
|
||||
GetForward = 2305,
|
||||
Get = 2306,
|
||||
|
||||
Max = 2399
|
||||
}
|
||||
}
|
||||
|
@@ -74,6 +74,21 @@ namespace linker.plugins.signin
|
||||
}
|
||||
return new SignInListResponseInfo { };
|
||||
}
|
||||
public async Task<SignInIdsResponseInfo> Ids(ApiControllerParamsInfo param)
|
||||
{
|
||||
SignInIdsRequestInfo request = param.Content.DeJson<SignInIdsRequestInfo>();
|
||||
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
|
||||
{
|
||||
Connection = clientSignInState.Connection,
|
||||
MessengerId = (ushort)SignInMessengerIds.Ids,
|
||||
Payload = MemoryPackSerializer.Serialize(request)
|
||||
}).ConfigureAwait(false);
|
||||
if (resp.Code == MessageResponeCodes.OK)
|
||||
{
|
||||
return MemoryPackSerializer.Deserialize<SignInIdsResponseInfo>(resp.Data.Span);
|
||||
}
|
||||
return new SignInIdsResponseInfo { };
|
||||
}
|
||||
|
||||
public async Task<bool> SetName(ApiControllerParamsInfo param)
|
||||
{
|
||||
|
@@ -8,11 +8,9 @@ namespace linker.plugins.signin.messenger
|
||||
{
|
||||
public sealed class SignInClientMessenger : IMessenger
|
||||
{
|
||||
private readonly ConfigWrap config;
|
||||
private readonly ClientSignInTransfer clientSignInTransfer;
|
||||
public SignInClientMessenger(ConfigWrap config, ClientSignInTransfer clientSignInTransfer)
|
||||
{
|
||||
this.config = config;
|
||||
this.clientSignInTransfer = clientSignInTransfer;
|
||||
}
|
||||
|
||||
@@ -58,13 +56,12 @@ namespace linker.plugins.signin.messenger
|
||||
public void List(IConnection connection)
|
||||
{
|
||||
SignInListRequestInfo request = MemoryPackSerializer.Deserialize<SignInListRequestInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
||||
|
||||
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache))
|
||||
{
|
||||
IEnumerable<SignCacheInfo> list = signCaching.Get(cache.GroupId).OrderByDescending(c => c.MachineName).OrderByDescending(c => c.LastSignIn).OrderByDescending(c => c.Version).ToList();
|
||||
if (string.IsNullOrWhiteSpace(request.Name) == false)
|
||||
{
|
||||
list = list.Where(c => c.MachineName.Contains(request.Name));
|
||||
list = list.Where(c => c.Version.Contains(request.Name) || c.IP.ToString().Contains(request.Name) || c.MachineName.Contains(request.Name) || request.Ids.Contains(c.MachineId));
|
||||
}
|
||||
int count = list.Count();
|
||||
list = list.Skip((request.Page - 1) * request.Size).Take(request.Size);
|
||||
@@ -109,6 +106,31 @@ namespace linker.plugins.signin.messenger
|
||||
connection.Write(MemoryPackSerializer.Serialize(config.Data.Version));
|
||||
}
|
||||
|
||||
|
||||
[MessengerId((ushort)SignInMessengerIds.Ids)]
|
||||
public void Ids(IConnection connection)
|
||||
{
|
||||
SignInIdsRequestInfo request = MemoryPackSerializer.Deserialize<SignInIdsRequestInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
||||
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache))
|
||||
{
|
||||
IEnumerable<SignCacheInfo> list = signCaching.Get(cache.GroupId).OrderByDescending(c => c.MachineName).OrderByDescending(c => c.LastSignIn).OrderByDescending(c => c.Version).ToList();
|
||||
if (string.IsNullOrWhiteSpace(request.Name) == false)
|
||||
{
|
||||
list = list.Where(c => c.MachineName.Contains(request.Name));
|
||||
}
|
||||
int count = list.Count();
|
||||
list = list.Skip((request.Page - 1) * request.Size).Take(request.Size);
|
||||
|
||||
SignInIdsResponseInfo response = new SignInIdsResponseInfo
|
||||
{
|
||||
Request = request,
|
||||
Count = count,
|
||||
List = list.Select(c => new SignInIdsResponseItemInfo { MachineId = c.MachineId, MachineName = c.MachineName }).ToList()
|
||||
};
|
||||
|
||||
connection.Write(MemoryPackSerializer.Serialize(response));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MemoryPackable]
|
||||
@@ -130,6 +152,10 @@ namespace linker.plugins.signin.messenger
|
||||
/// 按名称搜索
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
/// <summary>
|
||||
/// 按id获取
|
||||
/// </summary>
|
||||
public string[] Ids { get; set; }
|
||||
}
|
||||
|
||||
[MemoryPackable]
|
||||
@@ -139,4 +165,37 @@ namespace linker.plugins.signin.messenger
|
||||
public int Count { get; set; }
|
||||
public List<SignCacheInfo> List { get; set; } = new List<SignCacheInfo>();
|
||||
}
|
||||
|
||||
|
||||
[MemoryPackable]
|
||||
public sealed partial class SignInIdsRequestInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 当前页
|
||||
/// </summary>
|
||||
public int Page { get; set; } = 1;
|
||||
/// <summary>
|
||||
/// 每页大小
|
||||
/// </summary>
|
||||
public int Size { get; set; } = 10;
|
||||
/// <summary>
|
||||
/// 按名称搜索
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
[MemoryPackable]
|
||||
public sealed partial class SignInIdsResponseInfo
|
||||
{
|
||||
public SignInIdsRequestInfo Request { get; set; } = new SignInIdsRequestInfo();
|
||||
public int Count { get; set; }
|
||||
public List<SignInIdsResponseItemInfo> List { get; set; } = new List<SignInIdsResponseItemInfo>();
|
||||
}
|
||||
|
||||
[MemoryPackable]
|
||||
public sealed partial class SignInIdsResponseItemInfo
|
||||
{
|
||||
public string MachineId { get; set; }
|
||||
public string MachineName { get; set; }
|
||||
}
|
||||
}
|
||||
|
@@ -11,6 +11,8 @@
|
||||
|
||||
Version = 7,
|
||||
|
||||
Ids = 8,
|
||||
|
||||
None = 99
|
||||
}
|
||||
}
|
||||
|
@@ -68,10 +68,12 @@ namespace linker.plugins.tunnel
|
||||
{
|
||||
return running.Data.Tunnel.Servers;
|
||||
}
|
||||
public void SetTunnelWanPortProtocols(List<TunnelWanPortInfo> compacts)
|
||||
public void SetTunnelWanPortProtocols(List<TunnelWanPortInfo> compacts, bool updateVersion)
|
||||
{
|
||||
running.Data.Tunnel.Servers = compacts;
|
||||
running.Data.Update();
|
||||
if (updateVersion)
|
||||
runningConfigTransfer.IncrementVersion(wanPortConfigKey);
|
||||
SyncWanPort();
|
||||
}
|
||||
private void SetTunnelWanPortProtocols(Memory<byte> data)
|
||||
@@ -84,10 +86,12 @@ namespace linker.plugins.tunnel
|
||||
{
|
||||
return running.Data.Tunnel.Transports;
|
||||
}
|
||||
public void SetTunnelTransports(List<TunnelTransportItemInfo> transports)
|
||||
public void SetTunnelTransports(List<TunnelTransportItemInfo> transports, bool updateVersion)
|
||||
{
|
||||
running.Data.Tunnel.Transports = transports;
|
||||
running.Data.Update();
|
||||
if (updateVersion)
|
||||
runningConfigTransfer.IncrementVersion(transportConfigKey);
|
||||
SyncTransport();
|
||||
}
|
||||
private void SetTunnelTransports(Memory<byte> data)
|
||||
|
@@ -81,7 +81,7 @@ namespace linker.plugins.tunnel
|
||||
public bool SetServers(ApiControllerParamsInfo param)
|
||||
{
|
||||
List<TunnelWanPortInfo> info = param.Content.DeJson<List<TunnelWanPortInfo>>();
|
||||
tunnelMessengerAdapter.SetTunnelWanPortProtocols(info);
|
||||
tunnelMessengerAdapter.SetTunnelWanPortProtocols(info,true);
|
||||
return true;
|
||||
|
||||
}
|
||||
@@ -127,7 +127,7 @@ namespace linker.plugins.tunnel
|
||||
public bool SetTransports(ApiControllerParamsInfo param)
|
||||
{
|
||||
List<TunnelTransportItemInfo> info = param.Content.DeJson<List<TunnelTransportItemInfo>>();
|
||||
tunnelMessengerAdapter.SetTunnelTransports(info);
|
||||
tunnelMessengerAdapter.SetTunnelTransports(info, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -3,6 +3,7 @@ using linker.client.config;
|
||||
using linker.config;
|
||||
using linker.plugins.tunnel.messenger;
|
||||
using linker.server;
|
||||
using linker.tunnel.adapter;
|
||||
using linker.tunnel.wanport;
|
||||
using MemoryPack;
|
||||
using System.Collections.Concurrent;
|
||||
@@ -16,6 +17,7 @@ namespace linker.plugins.tunnel
|
||||
private readonly ClientSignInState clientSignInState;
|
||||
private readonly MessengerSender messengerSender;
|
||||
private readonly RunningConfigTransfer runningConfigTransfer;
|
||||
private readonly ITunnelAdapter tunnelAdapter;
|
||||
|
||||
private string exipConfigKey = "excludeIPConfig";
|
||||
|
||||
@@ -24,13 +26,14 @@ namespace linker.plugins.tunnel
|
||||
private ConcurrentDictionary<string, TunnelTransportRouteLevelInfo> configs = new ConcurrentDictionary<string, TunnelTransportRouteLevelInfo>();
|
||||
public ConcurrentDictionary<string, TunnelTransportRouteLevelInfo> Config => configs;
|
||||
|
||||
public TunnelConfigTransfer(ConfigWrap config, RunningConfig running, ClientSignInState clientSignInState, MessengerSender messengerSender, RunningConfigTransfer runningConfigTransfer)
|
||||
public TunnelConfigTransfer(ConfigWrap config, RunningConfig running, ClientSignInState clientSignInState, MessengerSender messengerSender, RunningConfigTransfer runningConfigTransfer, ITunnelAdapter tunnelAdapter)
|
||||
{
|
||||
this.config = config;
|
||||
this.running = running;
|
||||
this.clientSignInState = clientSignInState;
|
||||
this.messengerSender = messengerSender;
|
||||
this.runningConfigTransfer = runningConfigTransfer;
|
||||
this.tunnelAdapter = tunnelAdapter;
|
||||
|
||||
clientSignInState.NetworkEnabledHandle += (times) =>
|
||||
{
|
||||
@@ -48,9 +51,11 @@ namespace linker.plugins.tunnel
|
||||
}
|
||||
private void InitConfig()
|
||||
{
|
||||
if (running.Data.Tunnel.Servers.FirstOrDefault(c => c.Type == TunnelWanPortType.Linker && c.ProtocolType == TunnelWanPortProtocolType.Udp) == null)
|
||||
bool updateVersion = false;
|
||||
List<TunnelWanPortInfo> server = running.Data.Tunnel.Servers;
|
||||
if (server.FirstOrDefault(c => c.Type == TunnelWanPortType.Linker && c.ProtocolType == TunnelWanPortProtocolType.Udp) == null)
|
||||
{
|
||||
running.Data.Tunnel.Servers.Add(new TunnelWanPortInfo
|
||||
server.Add(new TunnelWanPortInfo
|
||||
{
|
||||
Name = "Linker Udp",
|
||||
Type = TunnelWanPortType.Linker,
|
||||
@@ -58,10 +63,11 @@ namespace linker.plugins.tunnel
|
||||
Disabled = false,
|
||||
Host = running.Data.Client.Servers.FirstOrDefault().Host,
|
||||
});
|
||||
updateVersion = true;
|
||||
}
|
||||
if (running.Data.Tunnel.Servers.FirstOrDefault(c => c.Type == TunnelWanPortType.Linker && c.ProtocolType == TunnelWanPortProtocolType.Tcp) == null)
|
||||
if (server.FirstOrDefault(c => c.Type == TunnelWanPortType.Linker && c.ProtocolType == TunnelWanPortProtocolType.Tcp) == null)
|
||||
{
|
||||
running.Data.Tunnel.Servers.Add(new TunnelWanPortInfo
|
||||
server.Add(new TunnelWanPortInfo
|
||||
{
|
||||
Name = "Linker Tcp",
|
||||
Type = TunnelWanPortType.Linker,
|
||||
@@ -69,7 +75,9 @@ namespace linker.plugins.tunnel
|
||||
Disabled = false,
|
||||
Host = running.Data.Client.Servers.FirstOrDefault().Host,
|
||||
});
|
||||
updateVersion = true;
|
||||
}
|
||||
tunnelAdapter.SetTunnelWanPortProtocols(server, updateVersion);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -147,6 +155,7 @@ namespace linker.plugins.tunnel
|
||||
{
|
||||
running.Data.Tunnel.ExcludeIPs = ips;
|
||||
running.Data.Update();
|
||||
runningConfigTransfer.IncrementVersion(exipConfigKey);
|
||||
SyncExcludeIP();
|
||||
}
|
||||
private void SettExcludeIPs(Memory<byte> data)
|
||||
|
@@ -6,8 +6,6 @@ using linker.tunnel.adapter;
|
||||
using linker.tunnel.transport;
|
||||
using linker.libs;
|
||||
using MemoryPack;
|
||||
using linker.tunnel.wanport;
|
||||
using linker.client.config;
|
||||
|
||||
namespace linker.plugins.tunnel.messenger
|
||||
{
|
||||
@@ -15,13 +13,11 @@ namespace linker.plugins.tunnel.messenger
|
||||
{
|
||||
private readonly TunnelTransfer tunnel;
|
||||
private readonly TunnelConfigTransfer tunnelConfigTransfer;
|
||||
private readonly ITunnelAdapter tunnelMessengerAdapter;
|
||||
|
||||
public TunnelClientMessenger(TunnelTransfer tunnel, TunnelConfigTransfer tunnelConfigTransfer, ITunnelAdapter tunnelMessengerAdapter)
|
||||
public TunnelClientMessenger(TunnelTransfer tunnel, TunnelConfigTransfer tunnelConfigTransfer)
|
||||
{
|
||||
this.tunnel = tunnel;
|
||||
this.tunnelConfigTransfer = tunnelConfigTransfer;
|
||||
this.tunnelMessengerAdapter = tunnelMessengerAdapter;
|
||||
}
|
||||
|
||||
[MessengerId((ushort)TunnelMessengerIds.Begin)]
|
||||
|
Reference in New Issue
Block a user