This commit is contained in:
snltty
2024-07-14 14:45:23 +08:00
parent aa65b16892
commit cfa6d18010
63 changed files with 1088 additions and 504 deletions

1
linker.doc.web Submodule

Submodule linker.doc.web added at 1207b6c05a

View File

@@ -119,7 +119,6 @@ namespace linker.tunnel
public async Task<ITunnelConnection> ConnectAsync(string remoteMachineId, string transactionId)
{
if (connectingDic.TryAdd(remoteMachineId, true) == false) return null;
if (IsBackground(remoteMachineId, transactionId)) return null;
try
{
@@ -394,15 +393,23 @@ namespace linker.tunnel
private ConcurrentDictionary<string, bool> backgroundDic = new ConcurrentDictionary<string, bool>();
public void StartBackground(string remoteMachineId, string transactionId)
/// <summary>
/// 开始后台打洞
/// </summary>
/// <param name="remoteMachineId"></param>
/// <param name="transactionId"></param>
public void StartBackground(string remoteMachineId, string transactionId,int times = 10)
{
if (IsBackground(remoteMachineId, transactionId)) return;
AddBackground(remoteMachineId, transactionId);
if (AddBackground(remoteMachineId, transactionId) == false)
{
LoggerHelper.Instance.Error($"tunnel background {remoteMachineId}@{transactionId} already exists");
return;
}
Task.Run(async () =>
{
try
{
for (int i = 0; i < 10; i++)
for (int i = 0; i < times; i++)
{
await Task.Delay(3000);
@@ -423,9 +430,9 @@ namespace linker.tunnel
});
}
private void AddBackground(string remoteMachineId, string transactionId)
private bool AddBackground(string remoteMachineId, string transactionId)
{
backgroundDic.TryAdd(GetBackgroundKey(remoteMachineId, transactionId), true);
return backgroundDic.TryAdd(GetBackgroundKey(remoteMachineId, transactionId), true);
}
private void RemoveBackground(string remoteMachineId, string transactionId)
{

View File

@@ -115,16 +115,41 @@ namespace linker.tunnel.transport
public sealed partial class TunnelTransportItemInfo
{
/// <summary>
/// 协议名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 协议描述
/// </summary>
public string Label { get; set; }
/// <summary>
/// 协议
/// </summary>
public string ProtocolType { get; set; }
/// <summary>
/// 是否禁用
/// </summary>
public bool Disabled { get; set; } = false;
/// <summary>
/// 是否反向打洞
/// </summary>
public bool Reverse { get; set; } = true;
/// <summary>
/// 是否允许修改反向打洞状态
/// </summary>
public bool DisableReverse { get; set; } = false;
/// <summary>
/// 是否开启ssl
/// </summary>
public bool SSL { get; set; } = true;
/// <summary>
/// 是否允许修改ssl配置
/// </summary>
public bool DisableSSL { get; set; } = false;
/// <summary>
/// 缓冲区大小
/// </summary>
public byte BufferSize { get; set; } = 4;
}
public sealed class TunnelTransportItemInfoEqualityComparer : IEqualityComparer<TunnelTransportItemInfo>
@@ -171,9 +196,13 @@ namespace linker.tunnel.transport
/// 需要加密
/// </summary>
public bool SSL { get; set; }
/// <summary>
/// 缓冲区
/// </summary>
public byte BufferSize { get; set; } = 3;
/// <summary>
/// 目标ip列表
/// </summary>
public List<IPEndPoint> RemoteEndPoints { get; set; }
}

View File

@@ -0,0 +1,9 @@
import { sendWebsocketMsg } from './request'
export const getConfig = () => {
return sendWebsocketMsg('configclient/get');
}
export const install = (data) => {
return sendWebsocketMsg('configclient/install', data);
}

View File

@@ -1,8 +1,6 @@
import { sendWebsocketMsg } from './request'
export const getConfig = () => {
return sendWebsocketMsg('signInclient/config');
}
export const setSignIn = (data) => {
return sendWebsocketMsg('signInclient/set', data);
}
@@ -26,6 +24,3 @@ export const signInDel = (machineId) => {
export const setSignInName = (data) => {
return sendWebsocketMsg('signInclient/setname', data);
}
export const install = (data) => {
return sendWebsocketMsg('signInclient/install', data);
}

View File

@@ -0,0 +1,133 @@
<template>
<div>
<el-form ref="formDom" :model="state.form" :rules="state.rules" label-width="8rem">
<el-form-item label="" label-width="0">
<div class="t-c w-100">
<p>端口为0则不监听</p>
<p>相同分组名之间的客户端相互可见</p>
</div>
</el-form-item>
<el-form-item label="" label-width="0">
<el-row>
<el-col :span="12">
<el-form-item label="机器名" prop="name">
<el-input v-model="state.form.name" maxlength="12" show-word-limit />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="分组名" prop="groupid">
<el-input v-model="state.form.groupid" maxlength="36" show-word-limit />
</el-form-item>
</el-col>
</el-row>
</el-form-item>
<el-form-item label="" label-width="0">
<el-row>
<el-col :span="12">
<el-form-item label="接口端口" prop="api">
<el-input v-model="state.form.api" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="网页端口" prop="web">
<el-input v-model="state.form.web" />
</el-form-item>
</el-col>
</el-row>
</el-form-item>
<el-form-item label="" label-width="0">
<el-form-item label="接口密码" prop="password">
<el-input type="password" v-model="state.form.password" show-password maxlength="36"
show-word-limit />
</el-form-item>
</el-form-item>
</el-form>
</div>
</template>
<script>
import { injectGlobalData } from '@/provide';
import { reactive, watch, ref, inject, onMounted } from 'vue';
export default {
setup(props) {
const step = inject('step');
const globalData = injectGlobalData();
const state = reactive({
form: {
name: globalData.value.config.Client.Name,
groupid: globalData.value.config.Client.GroupId,
api: globalData.value.config.Client.CApi.ApiPort,
web: globalData.value.config.Client.CApi.WebPort,
password: globalData.value.config.Client.CApi.ApiPassword
},
rules: {
name: [{ required: true, message: "必填", trigger: "blur" }],
groupid: [{ required: true, message: "必填", trigger: "blur" }],
password: [{ required: true, message: "必填", trigger: "blur" }],
api: [
{ required: true, message: "必填", trigger: "blur" },
{
type: "number",
min: 0,
max: 65535,
message: "数字 0-65535",
trigger: "blur",
transform(value) {
return Number(value);
},
},
],
web: [
{ required: true, message: "必填", trigger: "blur" },
{
type: "number",
min: 0,
max: 65535,
message: "数字 0-65535",
trigger: "blur",
transform(value) {
return Number(value);
},
},
],
}
});
const formDom = ref(null);
const handleValidate = () => {
return new Promise((resolve, reject) => {
formDom.value.validate((valid) => {
if (valid) {
resolve({
Client:{
name: state.form.name,
groupid: state.form.groupid,
api: +state.form.api,
web: +state.form.web,
password: state.form.password
}
});
} else {
reject();
}
})
})
}
onMounted(()=>{
if(step.value.json.Common.client == false){
step.value.step +=step.value.increment;
}
})
return { state, handleValidate, formDom };
}
}
</script>
<style lang="stylus" scoped>
.body{
padding:1rem 0 0 0;
}
.footer{
padding: 1rem 0;
}
</style>

View File

@@ -0,0 +1,52 @@
<template>
<div class="t-c">
<el-checkbox v-model="state.form.client" label="作为客户端" />
<el-checkbox v-model="state.form.server" label="作为服务端" />
</div>
</template>
<script>
import {inject, reactive} from 'vue'
import {ElMessage} from 'element-plus'
export default {
name: 'Common',
setup () {
const step = inject('step');
const state = reactive({
form: {
client: (step.value.json.Common && step.value.json.Common.client) || false,
server: (step.value.json.Common && step.value.json.Common.server) || false,
}
});
const handleValidate = (prevJson) => {
return new Promise((resolve, reject) => {
if(!state.form.client && !state.form.server){
ElMessage.error('请选择客户端或服务端');
reject();
}else{
resolve({
Common:{
client: state.form.client,
server: state.form.server,
modes:[
state.form.client ? 'client' : '',
state.form.server ? 'server' : ''
].filter(c=>!!c)
}
});
}
});
}
return {
state,handleValidate
}
}
}
</script>
<style lang="stylus" scoped>
</style>

View File

@@ -2,215 +2,94 @@
<div>
<el-dialog v-model="state.show" title="初始化配置" width="500" top="2vh">
<div>
<div class="head t-c">
<el-checkbox v-model="state.form.client" label="客户端" />
<el-checkbox v-model="state.form.server" label="服务端" />
<div class="head">
<el-steps :active="step.step" finish-status="success">
<template v-for="(item,index) in state.steps">
<el-step :title="item" />
</template>
</el-steps>
</div>
<div class="body">
<el-card shadow="never" v-if="state.form.client">
<template #header>
<div class="card-header"><span>客户端</span></div>
</template>
<div>
<el-form ref="formDom" :model="state.form" :rules="state.rules" label-width="8rem">
<el-form-item label="" label-width="0">
<el-row>
<el-col :span="12">
<el-form-item label="机器名" prop="name">
<el-input v-model="state.form.name" maxlength="12" show-word-limit />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="分组名" prop="groupid">
<el-input v-model="state.form.groupid" maxlength="36" show-word-limit />
</el-form-item>
</el-col>
</el-row>
</el-form-item>
<el-form-item label="" label-width="0">
<el-row>
<el-col :span="12">
<el-form-item label="接口端口" prop="api">
<el-input v-model="state.form.api" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="网页端口" prop="web">
<el-input v-model="state.form.web" />
</el-form-item>
</el-col>
</el-row>
</el-form-item>
<el-form-item label="" label-width="0">
<el-form-item label="接口密码" prop="password">
<el-input type="password" v-model="state.form.password" show-password maxlength="36"
show-word-limit />
</el-form-item>
</el-form-item>
</el-form>
</div>
<el-card shadow="never" v-if="step.step == 1">
<Common ref="currentDom"></Common>
</el-card>
<el-card shadow="never" v-if="state.form.server">
<template #header>
<div class="card-header"><span>服务端</span></div>
</template>
<div>
<el-form ref="formDom" :model="state.form" :rules="state.rules" label-width="10rem">
<el-form-item label="" label-width="0">
<el-row>
<el-col :span="12">
<el-form-item label="服务端口" prop="servicePort">
<el-input v-model="state.form.servicePort" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="web穿透端口" prop="sforwardPort">
<el-input v-model="state.form.sforwardPort" />
</el-form-item>
</el-col>
</el-row>
</el-form-item>
<el-form-item label="" label-width="0">
<el-row>
<el-col :span="12">
<el-form-item label="开放最小端口" prop="sforwardPort1">
<el-input v-model="state.form.sforwardPort1" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="开放最大端口" prop="sforwardPort2">
<el-input v-model="state.form.sforwardPort2" />
</el-form-item>
</el-col>
</el-row>
</el-form-item>
<el-form-item label="" label-width="0">
<el-row>
<el-col :span="12">
<el-form-item label="穿透密钥" prop="sforwardKey">
<el-input v-model="state.form.sforwardKey" maxlength="36" show-word-limit />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="中继密钥" prop="relayKey">
<el-input v-model="state.form.relayKey" maxlength="36" show-word-limit />
</el-form-item>
</el-col>
</el-row>
</el-form-item>
</el-form>
</div>
<el-card shadow="never" v-if="step.step == 2">
<Server ref="currentDom"></Server>
</el-card>
<el-card shadow="never" v-if="step.step == 3">
<Client ref="currentDom"></Client>
</el-card>
<el-card shadow="never" v-if="step.step == 4">
<div class="t-c">完成保存后请重启软件</div>
</el-card>
</div>
<div class="footer t-c">
<el-button :disabled="step.step <= 1" @click="handlePrev">上一步</el-button>
<el-button v-if="step.step < state.steps.length" type="primary" @click="handleNext">下一步</el-button>
<el-button v-else type="primary" @click="handleSave">完成</el-button>
</div>
<template #footer>
<div class="dialog-footer t-c">
<el-button @click="state.show = false" :loading="state.loading">取消</el-button>
<el-button type="primary" @click="handleSave" :loading="state.loading">确定保存</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script>
import { injectGlobalData } from '@/provide';
import { install } from '@/apis/signin';
import { reactive, computed, watch, ref } from 'vue';
import { install } from '@/apis/config';
import { reactive, watch, ref, provide } from 'vue';
import { ElMessage } from 'element-plus';
import Common from './Common.vue'
import Client from './Client.vue'
import Server from './Server.vue'
export default {
components: { Common,Client,Server },
setup(props) {
const globalData = injectGlobalData();
const state = reactive({
show: false,
form: {
client: true,
server: true,
restart: false,
name: '',
groupid: '',
api: 0,
web: 0,
password: '',
relayKey:'',
sforwardKey:'',
servicePort:1802,
sforwardPort:80,
sforwardPort1:10000,
sforwardPort2:60000,
},
rules: {
name: [{ required: true, message: "必填", trigger: "blur" }],
groupid: [{ required: true, message: "必填", trigger: "blur" }],
password: [{ required: true, message: "必填", trigger: "blur" }],
api: [
{ required: true, message: "必填", trigger: "blur" },
{
type: "number",
min: 1,
max: 65535,
message: "数字 1-65535",
trigger: "blur",
transform(value) {
return Number(value);
},
},
],
web: [
{ required: true, message: "必填", trigger: "blur" },
{
type: "number",
min: 1,
max: 65535,
message: "数字 1-65535",
trigger: "blur",
transform(value) {
return Number(value);
},
},
],
},
loading: false,
steps:['选择模式','服务端','客户端','完成']
});
watch(() => globalData.value.configed, (val) => {
if (val) {
state.show = globalData.value.connected && globalData.value.configed && !globalData.value.config.Client.GroupId;
state.form.name = globalData.value.config.Client.Name;
state.form.groupid = globalData.value.config.Client.GroupId;
state.form.api = globalData.value.config.Client.CApi.ApiPort;
state.form.web = globalData.value.config.Client.CApi.WebPort;
state.form.password = globalData.value.config.Client.CApi.ApiPassword;
state.show = globalData.value.connected && globalData.value.configed && globalData.value.config.Common.Install == false;
}
})
});
const formDom = ref(null);
const handleSave = () => {
formDom.value.validate((valid) => {
if (valid == false) {
return false;
const currentDom = ref(null);
const step = ref({
step:1,
increment:1,
json:{}
});
provide('step',step);
const handlePrev = ()=>{
step.value.step --;
step.value.increment = -1;
}
state.loading = true;
install(state.form).then(() => {
state.loading = false;
ElMessage.success('已操作!');
const handleNext = ()=>{
step.value.increment = 1;
currentDom.value.handleValidate().then((json)=>{
step.value.json = Object.assign(step.value.json,json);
step.value.step ++;
}).catch(()=>{
state.loading = false;
})
});
}
const handleSave = ()=>{
install(step.value.json).then(()=>{
ElMessage.success('保存成功');
}).catch(()=>{
ElMessage.error('保存失败');
})
}
return { state, handleSave, formDom };
return { state,currentDom,step,handlePrev,handleNext,handleSave};
}
}
</script>
<style lang="stylus" scoped>
.body{
padding:1rem 0 0 0;
}
.body{margin-top:1rem;}
.footer{
padding: 1rem 0;
margin-top:2rem
}
.el-card+.el-card{margin-top:1rem;}
</style>

View File

@@ -0,0 +1,172 @@
<template>
<div>
<el-form ref="formDom" :model="state.form" :rules="state.rules" label-width="10rem">
<el-form-item label="" label-width="0">
<div class="t-c w-100">端口为0则不监听</div>
</el-form-item>
<el-form-item label="" label-width="0">
<el-row>
<el-col :span="12">
<el-form-item label="服务端口" prop="servicePort">
<el-input v-model="state.form.servicePort" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="web穿透端口" prop="webPort">
<el-input v-model="state.form.webPort" />
</el-form-item>
</el-col>
</el-row>
</el-form-item>
<el-form-item label="" label-width="0">
<el-row>
<el-col :span="12">
<el-form-item label="开放最小端口" prop="tunnelPort1">
<el-input v-model="state.form.tunnelPort1" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="开放最大端口" prop="tunnelPort2">
<el-input v-model="state.form.tunnelPort2" />
</el-form-item>
</el-col>
</el-row>
</el-form-item>
<el-form-item label="" label-width="0">
<el-row>
<el-col :span="12">
<el-form-item label="穿透密钥" prop="sForwardSecretKey">
<el-input v-model="state.form.sForwardSecretKey" maxlength="36" show-word-limit />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="中继密钥" prop="relaySecretKey">
<el-input v-model="state.form.relaySecretKey" maxlength="36" show-word-limit />
</el-form-item>
</el-col>
</el-row>
</el-form-item>
</el-form>
</div>
</template>
<script>
import { injectGlobalData } from '@/provide';
import { reactive, watch, ref, inject, onMounted } from 'vue';
export default {
setup(props) {
const step = inject('step');
const globalData = injectGlobalData();
const state = reactive({
show: false,
form: {
relaySecretKey:globalData.value.config.Server.Relay.SecretKey,
sForwardSecretKey:globalData.value.config.Server.SForward.SecretKey,
servicePort:globalData.value.config.Server.ServicePort,
webPort:globalData.value.config.Server.SForward.WebPort,
tunnelPort1:globalData.value.config.Server.SForward.TunnelPortRange[0],
tunnelPort2:globalData.value.config.Server.SForward.TunnelPortRange[1],
},
rules: {
relaySecretKey: [{ required: true, message: "必填", trigger: "blur" }],
sForwardSecretKey: [{ required: true, message: "必填", trigger: "blur" }],
servicePort: [
{ required: true, message: "必填", trigger: "blur" },
{
type: "number",
min: 0,
max: 65535,
message: "数字 0-65535",
trigger: "blur",
transform(value) {
return Number(value);
},
},
],
webPort: [
{ required: true, message: "必填", trigger: "blur" },
{
type: "number",
min: 0,
max: 65535,
message: "数字 0-65535",
trigger: "blur",
transform(value) {
return Number(value);
},
},
],
tunnelPort1: [
{ required: true, message: "必填", trigger: "blur" },
{
type: "number",
min: 0,
max: 65535,
message: "数字 0-65535",
trigger: "blur",
transform(value) {
return Number(value);
},
},
],
tunnelPort2: [
{ required: true, message: "必填", trigger: "blur" },
{
type: "number",
min: 0,
max: 65535,
message: "数字 0-65535",
trigger: "blur",
transform(value) {
return Number(value);
},
},
],
},
});
const formDom = ref(null);
const handleValidate = () => {
return new Promise((resolve, reject) => {
formDom.value.validate((valid) => {
if (valid == false) {
reject();
}else{
resolve({
Server:{
ServicePort: +state.form.servicePort,
Relay:{
SecretKey: state.form.relaySecretKey
},
SForward:{
SecretKey: state.form.sForwardSecretKey,
WebPort: +state.form.webPort,
TunnelPortRange: [+state.form.tunnelPort1, +state.form.tunnelPort2]
}
}
});
}
});
})
}
onMounted(()=>{
if(step.value.json.Common.server == false){
step.value.step+=step.value.increment;
}
})
return { state, handleValidate, formDom };
}
}
</script>
<style lang="stylus" scoped>
.body{
padding:1rem 0 0 0;
}
.footer{
padding: 1rem 0;
}
.el-card+.el-card{margin-top:1rem;}
</style>

View File

@@ -29,7 +29,8 @@ 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 { getSignInfo } from '../../apis/signin'
import { getConfig } from '../../apis/config'
import {Tools} from '@element-plus/icons-vue'
export default {
components:{Tools},
@@ -49,16 +50,13 @@ export default {
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();
@@ -69,7 +67,6 @@ export default {
window.location.reload();
}
const handleShow = ()=>{
//state.showPort = true;
closeWebsocket();
initWebsocket(`ws://${window.location.hostname}:12345`,state.psd);
}
@@ -78,6 +75,7 @@ export default {
getConfig().then((res)=>{
globalData.value.config.Common = res.Common;
globalData.value.config.Client = res.Client;
globalData.value.config.Server = res.Server;
globalData.value.config.Running = res.Running;
globalData.value.configed = true;
setTimeout(()=>{
@@ -114,7 +112,6 @@ export default {
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();
});
});

View File

@@ -9,10 +9,9 @@ export const provideGlobalData = () => {
connected: false,
updateFlag: false,
height: 0,
config: { Common: {}, Client: {}, Running: {} },
config: { Common: {}, Client: {}, Server: {}, Running: {} },
configed: false,
signin: { Connected: false, Connecting: false, Version: 'v1.0.0.0' },
groupid: '',
bufferSize: ['1KB', '2KB', '4KB', '8KB', '16KB', '32KB', '64KB', '128KB', '256KB', '512KB', '1024KB']
});
subWebsocketState((state) => {

View File

@@ -3,7 +3,7 @@
<div>
<el-form ref="ruleFormRef" :model="state.ruleForm" :rules="state.rules" label-width="auto">
<el-form-item label="">
<div>这将会关闭程序如果以服务启动稍后会自动启动否则你需要手动重新运行</div>
<div>修改后最好能重启一次客户端</div>
</el-form-item>
<el-form-item label="设备名" prop="MachineName">
<el-input maxlength="12" show-word-limit v-model="state.ruleForm.MachineName" />

View File

@@ -10,8 +10,7 @@ export const provideDevices = () => {
timer: 0,
page: {
Request: {
Page: 1, Size: +(localStorage.getItem('ps') || '10'),
GroupId: globalData.value.groupid, Name: '', Ids: []
Page: 1, Size: +(localStorage.getItem('ps') || '10'), Name: '', Ids: []
},
Count: 0,
List: []
@@ -21,7 +20,6 @@ export const provideDevices = () => {
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;
@@ -37,7 +35,6 @@ export const provideDevices = () => {
}
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];

View File

@@ -19,7 +19,7 @@ namespace linker
Init();
//初始化配置文件
ConfigWrap config = new ConfigWrap();
FileConfig config = new FileConfig();
LoggerHelper.Instance.Warning($"current version : {config.Data.Version}");

View File

@@ -18,7 +18,7 @@ namespace linker.client
{
private readonly ClientSignInState clientSignInState;
private readonly RunningConfig runningConfig;
private readonly ConfigWrap config;
private readonly FileConfig config;
private readonly TcpServer tcpServer;
private readonly MessengerSender messengerSender;
private readonly SignInArgsTransfer signInArgsTransfer;
@@ -26,7 +26,7 @@ namespace linker.client
private string configKey = "signServers";
public ClientSignInTransfer(ClientSignInState clientSignInState, RunningConfig runningConfig, ConfigWrap config, TcpServer tcpServer, MessengerSender messengerSender, SignInArgsTransfer signInArgsTransfer, RunningConfigTransfer runningConfigTransfer)
public ClientSignInTransfer(ClientSignInState clientSignInState, RunningConfig runningConfig, FileConfig config, TcpServer tcpServer, MessengerSender messengerSender, SignInArgsTransfer signInArgsTransfer, RunningConfigTransfer runningConfigTransfer)
{
this.clientSignInState = clientSignInState;
this.runningConfig = runningConfig;
@@ -121,89 +121,6 @@ namespace linker.client
BooleanHelper.CompareExchange(ref clientSignInState.connecting, false, true);
}
}
/// <summary>
/// 登出
/// </summary>
public void SignOut()
{
if (clientSignInState.Connected)
clientSignInState.Connection.Disponse(5);
}
/// <summary>
/// 修改客户端名称
/// </summary>
/// <param name="newName"></param>
public void UpdateName(string newName)
{
string name = config.Data.Client.Name;
if (name != newName)
{
config.Data.Client.Name = newName;
config.Save();
SignOut();
_ = SignIn();
}
}
/// <summary>
/// 修改客户端名称和分组编号
/// </summary>
/// <param name="newName"></param>
/// <param name="newGroupid"></param>
public void UpdateName(string newName, string newGroupid)
{
string name = config.Data.Client.Name;
string gid = config.Data.Client.GroupId;
if (name != newName || gid != newGroupid)
{
config.Data.Client.Name = newName;
config.Data.Client.GroupId = newGroupid;
config.Save();
SignOut();
_ = SignIn();
}
}
/// <summary>
/// 修改信标服务器列表
/// </summary>
/// <param name="servers"></param>
public async Task UpdateServers(ClientServerInfo[] servers)
{
await SetServers(servers);
runningConfigTransfer.IncrementVersion(configKey);
SyncServers();
}
private void SetServers(Memory<byte> data)
{
_ = SetServers(MemoryPackSerializer.Deserialize<ClientServerInfo[]>(data.Span));
}
private async Task SetServers(ClientServerInfo[] servers)
{
string server = config.Data.Client.Server;
runningConfig.Data.Client.Servers = servers;
if (runningConfig.Data.Client.Servers.Length > 0)
{
config.Data.Client.Server = runningConfig.Data.Client.Servers.FirstOrDefault().Host;
}
runningConfig.Data.Update();
if (server != config.Data.Client.Server)
{
SignOut();
await SignIn();
}
}
private void SyncServers()
{
runningConfigTransfer.Sync(configKey, MemoryPackSerializer.Serialize(runningConfig.Data.Client.Servers));
}
/// <summary>
/// 连接到信标服务器
/// </summary>
@@ -252,7 +169,6 @@ namespace linker.client
clientSignInState.Connection?.Disponse(6);
return false;
}
/// <summary>
/// 获取服务器版本
/// </summary>
@@ -273,5 +189,87 @@ namespace linker.client
clientSignInState.Version = "v1.0.0.0";
}
}
/// <summary>
/// 登出
/// </summary>
public void SignOut()
{
if (clientSignInState.Connected)
clientSignInState.Connection.Disponse(5);
}
/// <summary>
/// 修改客户端名称
/// </summary>
/// <param name="newName"></param>
public void SetName(string newName)
{
string name = config.Data.Client.Name;
if (name != newName)
{
config.Data.Client.Name = newName;
config.Save();
SignOut();
_ = SignIn();
}
}
/// <summary>
/// 修改客户端名称和分组编号
/// </summary>
/// <param name="newName"></param>
/// <param name="newGroupid"></param>
public void Set(string newName, string newGroupid)
{
string name = config.Data.Client.Name;
string gid = config.Data.Client.GroupId;
if (name != newName || gid != newGroupid)
{
config.Data.Client.Name = newName;
config.Data.Client.GroupId = newGroupid;
config.Save();
SignOut();
_ = SignIn();
}
}
/// <summary>
/// 修改信标服务器列表
/// </summary>
/// <param name="servers"></param>
public async Task SetServers(ClientServerInfo[] servers)
{
await SetServersReSignin(servers);
runningConfigTransfer.IncrementVersion(configKey);
SyncServers();
}
private void SetServers(Memory<byte> data)
{
_ = SetServersReSignin(MemoryPackSerializer.Deserialize<ClientServerInfo[]>(data.Span));
}
private async Task SetServersReSignin(ClientServerInfo[] servers)
{
string server = config.Data.Client.Server;
runningConfig.Data.Client.Servers = servers;
if (runningConfig.Data.Client.Servers.Length > 0)
{
config.Data.Client.Server = runningConfig.Data.Client.Servers.FirstOrDefault().Host;
}
runningConfig.Data.Update();
if (server != config.Data.Client.Server)
{
SignOut();
await SignIn();
}
}
private void SyncServers()
{
runningConfigTransfer.Sync(configKey, MemoryPackSerializer.Serialize(runningConfig.Data.Client.Servers));
}
}
}

View File

@@ -20,7 +20,7 @@ namespace linker.client
public string[] Dependent => new string[] { "firewall", "signin", "serialize" };
public StartupLoadType LoadType => StartupLoadType.Normal;
public void AddClient(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddClient(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
serviceCollection.AddSingleton<RunningConfig>();
serviceCollection.AddSingleton<RunningConfigTransfer>();
@@ -34,7 +34,7 @@ namespace linker.client
}
public void UseClient(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseClient(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
LoggerHelper.Instance.Info($"start client");
@@ -44,11 +44,11 @@ namespace linker.client
}
public void AddServer(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddServer(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
serviceCollection.AddSingleton<ConfigServerMessenger>();
}
public void UseServer(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseServer(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
}
}

View File

@@ -9,7 +9,7 @@ namespace linker.client.args
{
private List<ISignInArgs> startups;
public SignInArgsTransfer(ServiceProvider serviceProvider, ConfigWrap config)
public SignInArgsTransfer(ServiceProvider serviceProvider, FileConfig config)
{
var types = ReflectionHelper.GetInterfaceSchieves(typeof(ISignInArgs));
startups = types.Select(c => serviceProvider.GetService(c) as ISignInArgs).Where(c=>c != null).ToList();

View File

@@ -67,7 +67,7 @@ namespace linker.config
}
}
#if DEBUG
private string groupid = string.Empty;//"snltty";
private string groupid = "snltty";
#else
private string groupid = string.Empty;
#endif

View File

@@ -5,6 +5,9 @@ using System.Text.Json.Serialization;
namespace linker.client.config
{
/// <summary>
/// 运行时配置
/// </summary>
public sealed class RunningConfig
{
private readonly ILiteCollection<RunningConfigInfo> liteCollection;

View File

@@ -8,17 +8,31 @@ namespace linker.client.config
{
public sealed partial class RunningConfigInfo
{
/// <summary>
/// 同步配置的版本记录
/// </summary>
public Dictionary<string, ulong> Versions { get; set; } = new Dictionary<string, ulong>();
}
[MemoryPackable]
public sealed partial class ConfigVersionInfo
{
/// <summary>
/// 配置key
/// </summary>
public string Key { get; set; }
/// <summary>
/// 配置版本
/// </summary>
public ulong Version { get; set; }
/// <summary>
/// 配置数据
/// </summary>
public Memory<byte> Data { get; set; }
}
/// <summary>
/// 配置同步
/// </summary>
public sealed class RunningConfigTransfer
{
private ConcurrentDictionary<string, Action<Memory<byte>>> setters = new ConcurrentDictionary<string, Action<Memory<byte>>>();
@@ -33,15 +47,30 @@ namespace linker.client.config
this.sender = sender;
this.clientSignInState = clientSignInState;
}
/// <summary>
/// 设置配置
/// </summary>
/// <param name="key"></param>
/// <param name="callback"></param>
public void Setter(string key, Action<Memory<byte>> callback)
{
setters.TryAdd(key, callback);
}
/// <summary>
/// 获取配置
/// </summary>
/// <param name="key"></param>
/// <param name="callback"></param>
public void Getter(string key, Func<Memory<byte>> callback)
{
getters.TryAdd(key, callback);
}
/// <summary>
/// 输入配置
/// </summary>
/// <param name="info"></param>
/// <returns></returns>
public Memory<byte> InputConfig(ConfigVersionInfo info)
{
ulong version = GetVersion(info.Key);
@@ -66,6 +95,11 @@ namespace linker.client.config
private object syncLockObj = new();
/// <summary>
/// 同步配置
/// </summary>
/// <param name="key"></param>
/// <param name="data"></param>
public void Sync(string key, Memory<byte> data)
{
ulong version = GetVersion(key);
@@ -106,11 +140,20 @@ namespace linker.client.config
}
return version;
}
/// <summary>
/// 更新版本
/// </summary>
/// <param name="key"></param>
/// <param name="version"></param>
public void UpdateVersion(string key, ulong version)
{
runningConfig.Data.Versions[key] = version;
runningConfig.Data.Update();
}
/// <summary>
/// 版本+1
/// </summary>
/// <param name="key"></param>
public void IncrementVersion(string key)
{
ulong version = GetVersion(key);

View File

@@ -1,11 +1,12 @@
using linker.libs;
using linker.libs.extends;
using LiteDB;
using System.Reflection;
using System.Text.Json.Serialization;
namespace linker.config
{
public sealed class ConfigWrap
public sealed class FileConfig
{
private SemaphoreSlim slim = new SemaphoreSlim(1);
private string configPath = "./configs/";
@@ -14,11 +15,12 @@ namespace linker.config
public ConfigInfo Data { get; private set; } = new ConfigInfo();
public ConfigWrap()
public FileConfig()
{
Init();
Load();
Save();
SaveTask();
}
private void Init()
@@ -46,7 +48,6 @@ namespace linker.config
});
}
}
private void Load()
{
slim.Wait();
@@ -78,8 +79,7 @@ namespace linker.config
}
}
public void Save()
private void Save()
{
slim.Wait();
try
@@ -106,7 +106,21 @@ namespace linker.config
}
}
private void SaveTask()
{
Task.Run(async () =>
{
while (true)
{
while (Data.Updated > 0)
{
Save();
Data.Updated--;
}
await Task.Delay(1000).ConfigureAwait(false);
}
});
}
}
public sealed class FileReadWrite
@@ -129,16 +143,29 @@ namespace linker.config
public string Version { get; set; } = $"v{Assembly.GetEntryAssembly().GetName().Version}";
[JsonIgnore]
public bool Elevated { get; set; }
[JsonIgnore, BsonIgnore]
public uint Updated { get; set; } = 1;
public void Update()
{
Updated++;
}
}
public sealed partial class ConfigCommonInfo
{
public string[] Modes { get; set; } = new string[] { "client", "server" };
#if DEBUG
private LoggerTypes loggerType { get; set; } = LoggerTypes.DEBUG;
public bool Install { get; set; } = true;
#else
private LoggerTypes loggerType { get; set; } = LoggerTypes.WARNING;
public bool Install { get; set; } = false;
#endif
[JsonIgnore]

View File

@@ -13,9 +13,9 @@ namespace linker.plugins.capi
public sealed class ApiClientServer : ApiServer, IApiClientServer
{
private readonly ServiceProvider serviceProvider;
private readonly ConfigWrap config;
private readonly FileConfig config;
public ApiClientServer(ServiceProvider serviceProvider, ConfigWrap config)
public ApiClientServer(ServiceProvider serviceProvider, FileConfig config)
{
this.serviceProvider = serviceProvider;
this.config = config;

View File

@@ -15,13 +15,13 @@ namespace linker.plugins.capi
public string[] Dependent => new string[] {};
public StartupLoadType LoadType => StartupLoadType.Normal;
public void AddClient(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddClient(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
serviceCollection.AddSingleton<IApiClientServer, ApiClientServer>();
serviceCollection.AddSingleton<IWebClientServer, WebClientServer>();
}
public void UseClient(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseClient(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
if (config.Data.Client.CApi.ApiPort > 0)
{
@@ -42,11 +42,11 @@ namespace linker.plugins.capi
}
public void AddServer(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddServer(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
}
public void UseServer(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseServer(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
}
}

View File

@@ -4,15 +4,30 @@ namespace linker.config
{
public partial class ConfigClientInfo
{
/// <summary>
/// 客户端管理接口配置
/// </summary>
public CApiConfigClientInfo CApi { get; set; } = new CApiConfigClientInfo();
}
public sealed class CApiConfigClientInfo
{
/// <summary>
/// 管理接口端口
/// </summary>
public int ApiPort { get; set; } = 1803;
/// <summary>
/// 管理接口密码
/// </summary>
public string ApiPassword { get; set; } = Helper.GlobalString;
/// <summary>
/// 网站端口
/// </summary>
public int WebPort { get; set; } = 1804;
/// <summary>
/// 网站根目录
/// </summary>
public string WebRoot { get; set; } = "./web/";
}
}

View File

@@ -0,0 +1,89 @@
using linker.config;
using linker.libs.api;
using linker.libs.extends;
using linker.client.capi;
using linker.client.config;
namespace linker.plugins.config
{
public sealed class ConfigClientApiController : IApiClientController
{
private readonly RunningConfig runningConfig;
private readonly FileConfig config;
public ConfigClientApiController(RunningConfig runningConfig, FileConfig config)
{
this.runningConfig = runningConfig;
this.config = config;
}
public object Get(ApiControllerParamsInfo param)
{
return new { Common = config.Data.Common, Client = config.Data.Client, Server = config.Data.Server, Running = runningConfig.Data };
}
public bool Install(ApiControllerParamsInfo param)
{
ConfigInstallInfo info = param.Content.DeJson<ConfigInstallInfo>();
if (info.Common.Modes.Contains("client"))
{
config.Data.Client.Name = info.Client.Name;
config.Data.Client.GroupId = info.Client.GroupId;
config.Data.Client.CApi.WebPort = info.Client.Web;
config.Data.Client.CApi.ApiPort = info.Client.Api;
config.Data.Client.CApi.ApiPassword = info.Client.Password;
}
if (info.Common.Modes.Contains("server"))
{
config.Data.Server.ServicePort = info.Server.ServicePort;
config.Data.Server.Relay.SecretKey = info.Server.Relay.SecretKey;
config.Data.Server.SForward.SecretKey = info.Server.SForward.SecretKey;
config.Data.Server.SForward.WebPort = info.Server.SForward.WebPort;
config.Data.Server.SForward.TunnelPortRange = info.Server.SForward.TunnelPortRange;
}
config.Data.Common.Modes = info.Common.Modes;
config.Data.Common.Install = true;
config.Save();
return true;
}
}
public sealed class ConfigInstallInfo
{
public ConfigInstallClientInfo Client { get; set; } = new ConfigInstallClientInfo();
public ConfigInstallServerInfo Server { get; set; } = new ConfigInstallServerInfo();
public ConfigInstallCommonInfo Common { get; set; } = new ConfigInstallCommonInfo();
}
public sealed class ConfigInstallClientInfo
{
public string Name { get; set; }
public string GroupId { get; set; }
public int Api { get; set; }
public int Web { get; set; }
public string Password { get; set; }
}
public sealed class ConfigInstallServerInfo
{
public int ServicePort { get; set; }
public ConfigInstallServerRelayInfo Relay { get; set; }
public ConfigInstallServerSForwardInfo SForward { get; set; }
}
public sealed class ConfigInstallServerRelayInfo
{
public string SecretKey { get; set; }
}
public sealed class ConfigInstallServerSForwardInfo
{
public string SecretKey { get; set; }
public int WebPort { get; set; }
public int[] TunnelPortRange { get; set; }
}
public sealed class ConfigInstallCommonInfo
{
public string[] Modes { get; set; }
}
}

View File

@@ -0,0 +1,37 @@
using linker.config;
using linker.startup;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;
namespace linker.plugins.config
{
public sealed class ConfigStartup : IStartup
{
public string Name => "config";
public bool Required => true;
public StartupLevel Level => StartupLevel.Normal;
public string[] Dependent => Array.Empty<string>();
public StartupLoadType LoadType => StartupLoadType.Normal;
public void AddClient(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
serviceCollection.AddSingleton<ConfigClientApiController>();
}
public void AddServer(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
}
public void UseClient(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
}
public void UseServer(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
}
}
}

View File

@@ -13,7 +13,7 @@ namespace linker.plugins.firewall
public string[] Dependent => new string[] { };
public StartupLoadType LoadType => StartupLoadType.Dependent;
public void AddClient(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddClient(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
#if DEBUG
#else
@@ -21,15 +21,15 @@ namespace linker.plugins.firewall
#endif
}
public void AddServer(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddServer(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
}
public void UseClient(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseClient(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
}
public void UseServer(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseServer(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
}
}

View File

@@ -17,7 +17,7 @@ namespace linker.plugins.forward
public StartupLoadType LoadType => StartupLoadType.Normal;
public void AddClient(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddClient(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
serviceCollection.AddSingleton<ForwardClientApiController>();
serviceCollection.AddSingleton<ForwardTransfer>();
@@ -27,17 +27,17 @@ namespace linker.plugins.forward
}
public void AddServer(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddServer(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
serviceCollection.AddSingleton<ForwardServerMessenger>();
}
public void UseClient(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseClient(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
ForwardTransfer forwardTransfer = serviceProvider.GetService<ForwardTransfer>();
}
public void UseServer(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseServer(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
}
}

View File

@@ -7,23 +7,54 @@ namespace linker.client.config
{
public sealed partial class RunningConfigInfo
{
/// <summary>
/// 端口转发配置
/// </summary>
public List<ForwardInfo> Forwards { get; set; } = new List<ForwardInfo>();
}
/// <summary>
/// 端口转发配置
/// </summary>
public sealed class ForwardInfo
{
public uint Id { get; set; }
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 目标设备
/// </summary>
public string MachineId { get; set; }
/// <summary>
/// 本地绑定IP
/// </summary>
public IPAddress BindIPAddress { get; set; } = IPAddress.Any;
/// <summary>
/// 本地监听端口
/// </summary>
public int Port { get; set; }
/// <summary>
/// 目标设备服务
/// </summary>
public IPEndPoint TargetEP { get; set; }
/// <summary>
/// 已启动
/// </summary>
public bool Started { get; set; }
/// <summary>
/// 缓冲区
/// </summary>
public byte BufferSize { get; set; } = 3;
/// <summary>
/// 本地监听错误信息
/// </summary>
public string Msg { get; set; }
/// <summary>
/// 目标服务错误信息
/// </summary>
public string TargetMsg { get; set; }
[JsonIgnore, BsonIgnore]

View File

@@ -12,7 +12,7 @@ namespace linker.plugins.forward.proxy
{
public sealed class ForwardProxy : TunnelProxy
{
private readonly ConfigWrap config;
private readonly FileConfig config;
private readonly TunnelTransfer tunnelTransfer;
private readonly RelayTransfer relayTransfer;
@@ -20,7 +20,7 @@ namespace linker.plugins.forward.proxy
private readonly ConcurrentDictionary<string, ITunnelConnection> connections = new ConcurrentDictionary<string, ITunnelConnection>();
private readonly ConcurrentDictionary<string, SemaphoreSlim> locks = new ConcurrentDictionary<string, SemaphoreSlim>();
public ForwardProxy(ConfigWrap config, TunnelTransfer tunnelTransfer, RelayTransfer relayTransfer)
public ForwardProxy(FileConfig config, TunnelTransfer tunnelTransfer, RelayTransfer relayTransfer)
{
this.config = config;
this.tunnelTransfer = tunnelTransfer;
@@ -36,6 +36,10 @@ namespace linker.plugins.forward.proxy
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
LoggerHelper.Instance.Warning($"TryAdd {connection.GetHashCode()} {connection.TransactionId} {connection.ToJson()}");
if (connections.TryGetValue(connection.RemoteMachineId, out ITunnelConnection connectionOld))
{
connectionOld?.Dispose();
}
//把隧道对象添加到缓存,方便下次直接获取
connections.AddOrUpdate(connection.RemoteMachineId, connection, (a, b) => connection);
BindConnectionReceive(connection);
@@ -113,12 +117,13 @@ namespace linker.plugins.forward.proxy
if (connection == null)
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG) LoggerHelper.Instance.Debug($"forward relay to {machineId}");
//转入后台打洞
tunnelTransfer.StartBackground(machineId, "forward");
//尝试中继
connection = await relayTransfer.ConnectAsync(config.Data.Client.Id, machineId, "forward").ConfigureAwait(false);
if (connection != null)
{
//转入后台打洞
tunnelTransfer.StartBackground(machineId, "forward");
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG) LoggerHelper.Instance.Debug($"forward relay to {machineId} success");
}
}

View File

@@ -10,8 +10,8 @@ namespace linker.plugins.logger
{
private readonly List<LoggerModel> loggers = new List<LoggerModel>();
private readonly ConfigWrap config;
public LoggerClientApiController(ConfigWrap config)
private readonly FileConfig config;
public LoggerClientApiController(FileConfig config)
{
this.config = config;
LoggerHelper.Instance.OnLogger += (LoggerModel logger) =>

View File

@@ -17,22 +17,22 @@ namespace linker.plugins.logger
public StartupLoadType LoadType => StartupLoadType.Normal;
public void AddClient(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddClient(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
serviceCollection.AddSingleton<LoggerClientApiController>();
}
public void AddServer(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddServer(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
}
public void UseClient(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseClient(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
LoggerClientApiController logger = serviceProvider.GetService<LoggerClientApiController>();
}
public void UseServer(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseServer(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
}
}

View File

@@ -14,12 +14,12 @@ namespace linker.plugins.relay
/// </summary>
public sealed class RelayApiController : IApiClientController
{
private readonly ConfigWrap config;
private readonly FileConfig config;
private readonly RelayTransfer relayTransfer;
private readonly ClientSignInState clientSignInState;
private readonly MessengerSender messengerSender;
public RelayApiController(ConfigWrap config, RelayTransfer relayTransfer, ClientSignInState clientSignInState, MessengerSender messengerSender)
public RelayApiController(FileConfig config, RelayTransfer relayTransfer, ClientSignInState clientSignInState, MessengerSender messengerSender)
{
this.config = config;
this.relayTransfer = relayTransfer;

View File

@@ -21,7 +21,7 @@ namespace linker.plugins.relay
public StartupLoadType LoadType => StartupLoadType.Normal;
public void AddClient(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddClient(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
serviceCollection.AddSingleton<RelayApiController>();
serviceCollection.AddSingleton<RelayClientMessenger>();
@@ -30,18 +30,18 @@ namespace linker.plugins.relay
}
public void AddServer(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddServer(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
serviceCollection.AddSingleton<RelayServerMessenger>();
}
public void UseClient(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseClient(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
RelayTransfer relayTransfer = serviceProvider.GetService<RelayTransfer>();
relayTransfer.Load(assemblies);
}
public void UseServer(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseServer(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
}
}

View File

@@ -8,12 +8,18 @@ namespace linker.client.config
{
public sealed partial class RunningConfigInfo
{
/// <summary>
/// 中继配置
/// </summary>
public RelayRunningInfo Relay { get; set; } = new RelayRunningInfo();
}
public sealed class RelayRunningInfo
{
public ObjectId Id { get; set; }
/// <summary>
/// 中继服务器列表
/// </summary>
public RelayServerInfo[] Servers { get; set; } = Array.Empty<RelayServerInfo>();
}
}
@@ -23,23 +29,53 @@ namespace linker.config
{
public partial class ConfigServerInfo
{
/// <summary>
/// 中继配置
/// </summary>
public RelayConfigServerInfo Relay { get; set; } = new RelayConfigServerInfo();
}
public sealed class RelayConfigServerInfo
{
/// <summary>
/// 中继密钥
/// </summary>
public string SecretKey { get; set; } = Guid.NewGuid().ToString().ToUpper();
/// <summary>
/// 缓冲区
/// </summary>
public byte BufferSize { get; set; } = 3;
}
/// <summary>
/// 中继服务器
/// </summary>
[MemoryPackable]
public sealed partial class RelayServerInfo
{
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// 中继服务器类别
/// </summary>
public RelayType RelayType { get; set; } = RelayType.Linker;
/// <summary>
/// 密钥
/// </summary>
public string SecretKey { get; set; } = "snltty";
/// <summary>
/// 服务器地址
/// </summary>
public string Host { get; set; } = string.Empty;
/// <summary>
/// 禁用
/// </summary>
public bool Disabled { get; set; }
/// <summary>
/// 开启ssl
/// </summary>
public bool SSL { get; set; } = true;
}

View File

@@ -39,14 +39,14 @@ namespace linker.plugins.relay.messenger
/// </summary>
public sealed class RelayServerMessenger : IMessenger
{
private readonly ConfigWrap config;
private readonly FileConfig config;
private readonly MessengerSender messengerSender;
private readonly SignCaching signCaching;
private readonly ConcurrentDictionary<ulong, TcsWrap> dic = new ConcurrentDictionary<ulong, TcsWrap>();
private ulong flowingId = 0;
public RelayServerMessenger(ConfigWrap config, MessengerSender messengerSender, SignCaching signCaching)
public RelayServerMessenger(FileConfig config, MessengerSender messengerSender, SignCaching signCaching)
{
this.config = config;
this.messengerSender = messengerSender;

View File

@@ -26,7 +26,7 @@ namespace linker.plugins.relay.transport
private X509Certificate2 certificate;
public TransportSelfHost(TcpServer tcpServer, MessengerSender messengerSender, ConfigWrap config)
public TransportSelfHost(TcpServer tcpServer, MessengerSender messengerSender, FileConfig config)
{
this.tcpServer = tcpServer;
this.messengerSender = messengerSender;

View File

@@ -22,7 +22,7 @@ namespace linker.plugins.sforward
public StartupLoadType LoadType => StartupLoadType.Normal;
public void AddClient(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddClient(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
Add(serviceCollection, config, assemblies);
serviceCollection.AddSingleton<SForwardClientApiController>();
@@ -30,7 +30,7 @@ namespace linker.plugins.sforward
serviceCollection.AddSingleton<SForwardClientMessenger>();
}
public void AddServer(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddServer(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
Add(serviceCollection, config, assemblies);
serviceCollection.AddSingleton<SForwardServerMessenger>();
@@ -40,7 +40,7 @@ namespace linker.plugins.sforward
}
bool added = false;
private void Add(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
private void Add(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
if (added == false)
{
@@ -49,12 +49,12 @@ namespace linker.plugins.sforward
}
}
public void UseClient(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseClient(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
SForwardTransfer forwardTransfer = serviceProvider.GetService<SForwardTransfer>();
}
public void UseServer(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseServer(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
SForwardProxy sForwardProxy = serviceProvider.GetService<SForwardProxy>();
if (config.Data.Server.SForward.WebPort > 0)

View File

@@ -8,24 +8,53 @@ namespace linker.client.config
{
public sealed partial class RunningConfigInfo
{
/// <summary>
/// 服务器穿透密钥
/// </summary>
public string SForwardSecretKey { get; set; } = "snltty";
/// <summary>
/// 服务器穿透列表
/// </summary>
public List<SForwardInfo> SForwards { get; set; } =new List<SForwardInfo>();
}
public sealed class SForwardInfo
{
/// <summary>
/// 穿透id
/// </summary>
public uint Id { get; set; }
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 域名
/// </summary>
public string Domain { get; set; }
/// <summary>
/// 端口,
/// </summary>
public int RemotePort { get; set; }
/// <summary>
/// 缓冲区
/// </summary>
public byte BufferSize { get; set; } = 3;
/// <summary>
/// 本地服务
/// </summary>
public IPEndPoint LocalEP { get; set; }
/// <summary>
/// 已启动
/// </summary>
public bool Started { get; set; }
/// <summary>
/// 服务器错误信息
/// </summary>
public string Msg { get; set; }
/// <summary>
/// 本地错误信息
/// </summary>
public string LocalMsg { get; set; }
[JsonIgnore, BsonIgnore]
@@ -38,14 +67,29 @@ namespace linker.config
{
public partial class ConfigServerInfo
{
/// <summary>
/// 服务器穿透配置
/// </summary>
public SForwardConfigServerInfo SForward { get; set; } = new SForwardConfigServerInfo();
}
public sealed class SForwardConfigServerInfo
{
/// <summary>
/// 密钥
/// </summary>
public string SecretKey { get; set; } = Guid.NewGuid().ToString().ToUpper();
/// <summary>
/// 缓冲区
/// </summary>
public byte BufferSize { get; set; } = 3;
/// <summary>
/// web端口
/// </summary>
public int WebPort { get; set; }
/// <summary>
/// 开放端口范围
/// </summary>
public int[] TunnelPortRange { get; set; } = new int[] { 10000, 60000 };
}
@@ -67,7 +111,6 @@ namespace linker.plugins.sforward.config
{
public bool Success { get; set; }
public string Message { get; set; }
public byte BufferSize { get; set; }
}
@@ -78,7 +121,6 @@ namespace linker.plugins.sforward.config
public ulong Id { get; set; }
public string Domain { get; set; }
public int RemotePort { get; set; }
public byte BufferSize { get; set; } = 3;
}
}

View File

@@ -19,10 +19,10 @@ namespace linker.plugins.sforward.messenger
private readonly ISForwardServerCahing sForwardServerCahing;
private readonly MessengerSender sender;
private readonly SignCaching signCaching;
private readonly ConfigWrap configWrap;
private readonly FileConfig configWrap;
private readonly IValidator validator;
public SForwardServerMessenger(SForwardProxy proxy, ISForwardServerCahing sForwardServerCahing, MessengerSender sender, SignCaching signCaching, ConfigWrap configWrap, IValidator validator)
public SForwardServerMessenger(SForwardProxy proxy, ISForwardServerCahing sForwardServerCahing, MessengerSender sender, SignCaching signCaching, FileConfig configWrap, IValidator validator)
{
this.proxy = proxy;
proxy.WebConnect = WebConnect;

View File

@@ -6,8 +6,8 @@ namespace linker.plugins.sforward.validator
{
public sealed class Validator : IValidator
{
private readonly ConfigWrap config;
public Validator(ConfigWrap config)
private readonly FileConfig config;
public Validator(FileConfig config)
{
this.config = config;
}

View File

@@ -6,23 +6,18 @@ using linker.client;
using linker.server;
using MemoryPack;
using linker.client.capi;
using linker.client.config;
using System.Diagnostics;
using linker.libs;
namespace linker.plugins.signin
{
public sealed class SignInClientApiController : IApiClientController
{
private readonly RunningConfig runningConfig;
private readonly ConfigWrap config;
private readonly FileConfig config;
private readonly ClientSignInState clientSignInState;
private readonly ClientSignInTransfer clientSignInTransfer;
private readonly MessengerSender messengerSender;
public SignInClientApiController(RunningConfig runningConfig, ConfigWrap config, ClientSignInState clientSignInState, ClientSignInTransfer clientSignInTransfer, MessengerSender messengerSender)
public SignInClientApiController(FileConfig config, ClientSignInState clientSignInState, ClientSignInTransfer clientSignInTransfer, MessengerSender messengerSender)
{
this.runningConfig = runningConfig;
this.config = config;
this.clientSignInState = clientSignInState;
this.clientSignInTransfer = clientSignInTransfer;
@@ -30,22 +25,38 @@ namespace linker.plugins.signin
}
public object Config(ApiControllerParamsInfo param)
{
return new { Common = config.Data.Common, Client = config.Data.Client, Running = runningConfig.Data };
}
public void Set(ApiControllerParamsInfo param)
{
ConfigSetInfo info = param.Content.DeJson<ConfigSetInfo>();
clientSignInTransfer.UpdateName(info.Name, info.GroupId);
clientSignInTransfer.Set(info.Name, info.GroupId);
}
public async Task<bool> SeName(ApiControllerParamsInfo param)
{
ConfigSetNameInfo info = param.Content.DeJson<ConfigSetNameInfo>();
if (info.Id == config.Data.Client.Id)
{
clientSignInTransfer.SetName(info.NewName);
}
else
{
await messengerSender.SendOnly(new MessageRequestWrap
{
Connection = clientSignInState.Connection,
MessengerId = (ushort)SignInMessengerIds.SetNameForward,
Payload = MemoryPackSerializer.Serialize(info)
}).ConfigureAwait(false);
}
return true;
}
public async Task<bool> SetServers(ApiControllerParamsInfo param)
{
ClientServerInfo[] servers = param.Content.DeJson<ClientServerInfo[]>();
await clientSignInTransfer.UpdateServers(servers);
await clientSignInTransfer.SetServers(servers);
return true;
}
public ClientSignInState Info(ApiControllerParamsInfo param)
{
return clientSignInState;
@@ -90,50 +101,6 @@ namespace linker.plugins.signin
return new SignInIdsResponseInfo { };
}
public async Task<bool> SetName(ApiControllerParamsInfo param)
{
ConfigSetNameInfo info = param.Content.DeJson<ConfigSetNameInfo>();
await messengerSender.SendOnly(new MessageRequestWrap
{
Connection = clientSignInState.Connection,
MessengerId = (ushort)SignInMessengerIds.NameForward,
Payload = MemoryPackSerializer.Serialize(info)
}).ConfigureAwait(false);
if (info.Id == config.Data.Client.Id)
{
clientSignInTransfer.UpdateName(info.NewName);
}
return true;
}
public bool Install(ApiControllerParamsInfo param)
{
ConfigInstallInfo info = param.Content.DeJson<ConfigInstallInfo>();
config.Data.Client.Name = info.Name;
config.Data.Client.GroupId = info.GroupId;
config.Data.Client.CApi.WebPort = info.Web;
config.Data.Client.CApi.ApiPort = info.Api;
config.Data.Client.CApi.ApiPassword = info.Password;
config.Data.Common.Modes = new string[] { "client" };
config.Save();
if (info.Restart)
{
try
{
CommandHelper.Execute(Process.GetCurrentProcess().MainModule.FileName, string.Empty);
Environment.Exit(0);
}
catch (Exception)
{
}
}
return true;
}
}
[MemoryPackable]
@@ -149,13 +116,4 @@ namespace linker.plugins.signin
public string GroupId { get; set; }
}
public sealed class ConfigInstallInfo
{
public string Name { get; set; }
public string GroupId { get; set; }
public int Api { get; set; }
public int Web { get; set; }
public string Password { get; set; }
public bool Restart { get; set; }
}
}

View File

@@ -18,23 +18,23 @@ namespace linker.plugins.signin
public StartupLoadType LoadType => StartupLoadType.Normal;
public void AddClient(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddClient(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
serviceCollection.AddSingleton<SignInClientMessenger>();
serviceCollection.AddSingleton<SignInClientApiController>();
}
public void AddServer(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddServer(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
serviceCollection.AddSingleton<SignCaching>();
serviceCollection.AddSingleton<SignInServerMessenger>();
}
public void UseClient(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseClient(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
}
public void UseServer(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseServer(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
}
}

View File

@@ -9,16 +9,16 @@ namespace linker.plugins.signin.messenger
public sealed class SignInClientMessenger : IMessenger
{
private readonly ClientSignInTransfer clientSignInTransfer;
public SignInClientMessenger(ConfigWrap config, ClientSignInTransfer clientSignInTransfer)
public SignInClientMessenger(FileConfig config, ClientSignInTransfer clientSignInTransfer)
{
this.clientSignInTransfer = clientSignInTransfer;
}
[MessengerId((ushort)SignInMessengerIds.Name)]
[MessengerId((ushort)SignInMessengerIds.SetName)]
public void Name(IConnection connection)
{
ConfigSetNameInfo info = MemoryPackSerializer.Deserialize<ConfigSetNameInfo>(connection.ReceiveRequestWrap.Payload.Span);
clientSignInTransfer.UpdateName(info.NewName);
clientSignInTransfer.SetName(info.NewName);
}
}
@@ -26,10 +26,10 @@ namespace linker.plugins.signin.messenger
public sealed class SignInServerMessenger : IMessenger
{
private readonly SignCaching signCaching;
private readonly ConfigWrap config;
private readonly FileConfig config;
private readonly MessengerSender messengerSender;
public SignInServerMessenger(SignCaching signCaching, ConfigWrap config, MessengerSender messengerSender)
public SignInServerMessenger(SignCaching signCaching, FileConfig config, MessengerSender messengerSender)
{
this.signCaching = signCaching;
this.config = config;
@@ -82,7 +82,7 @@ namespace linker.plugins.signin.messenger
}
}
[MessengerId((ushort)SignInMessengerIds.NameForward)]
[MessengerId((ushort)SignInMessengerIds.SetNameForward)]
public async Task NameForward(IConnection connection)
{
ConfigSetNameInfo info = MemoryPackSerializer.Deserialize<ConfigSetNameInfo>(connection.ReceiveRequestWrap.Payload.Span);
@@ -93,7 +93,7 @@ namespace linker.plugins.signin.messenger
await messengerSender.SendOnly(new MessageRequestWrap
{
Connection = cache.Connection,
MessengerId = (ushort)SignInMessengerIds.Name,
MessengerId = (ushort)SignInMessengerIds.SetName,
Payload = connection.ReceiveRequestWrap.Payload,
}).ConfigureAwait(false);
}

View File

@@ -6,8 +6,8 @@
List = 1,
Delete = 2,
Name = 3,
NameForward = 4,
SetName = 3,
SetNameForward = 4,
Version = 7,

View File

@@ -22,14 +22,14 @@ namespace linker.plugins.tunnel
private readonly ClientSignInState clientSignInState;
private readonly MessengerSender messengerSender;
private readonly ConfigWrap config;
private readonly FileConfig config;
private readonly RunningConfig running;
private readonly RunningConfigTransfer runningConfigTransfer;
private string wanPortConfigKey = "tunnelWanPortProtocols";
private string transportConfigKey = "tunnelTransports";
public TunnelAdapter(ClientSignInState clientSignInState, MessengerSender messengerSender, ConfigWrap config, RunningConfig running, RunningConfigTransfer runningConfigTransfer)
public TunnelAdapter(ClientSignInState clientSignInState, MessengerSender messengerSender, FileConfig config, RunningConfig running, RunningConfigTransfer runningConfigTransfer)
{
this.clientSignInState = clientSignInState;
this.messengerSender = messengerSender;

View File

@@ -19,14 +19,14 @@ namespace linker.plugins.tunnel
/// </summary>
public sealed class TunnelApiController : IApiClientController
{
private readonly ConfigWrap config;
private readonly FileConfig config;
private readonly TunnelWanPortTransfer compactTransfer;
private readonly ClientSignInState clientSignInState;
private readonly MessengerSender messengerSender;
private readonly TunnelConfigTransfer tunnelConfigTransfer;
private readonly ITunnelAdapter tunnelMessengerAdapter;
public TunnelApiController(ConfigWrap config, TunnelWanPortTransfer compactTransfer, ClientSignInState clientSignInState, MessengerSender messengerSender, TunnelConfigTransfer tunnelConfigTransfer, ITunnelAdapter tunnelMessengerAdapter)
public TunnelApiController(FileConfig config, TunnelWanPortTransfer compactTransfer, ClientSignInState clientSignInState, MessengerSender messengerSender, TunnelConfigTransfer tunnelConfigTransfer, ITunnelAdapter tunnelMessengerAdapter)
{
this.config = config;
this.compactTransfer = compactTransfer;
@@ -92,11 +92,11 @@ namespace linker.plugins.tunnel
/// <returns></returns>
public async Task<bool> SetRouteLevel(ApiControllerParamsInfo param)
{
TunnelTransportRouteLevelInfo tunnelTransportConfigWrapInfo = param.Content.DeJson<TunnelTransportRouteLevelInfo>();
TunnelTransportRouteLevelInfo tunnelTransportFileConfigInfo = param.Content.DeJson<TunnelTransportRouteLevelInfo>();
if (tunnelTransportConfigWrapInfo.MachineId == config.Data.Client.Id)
if (tunnelTransportFileConfigInfo.MachineId == config.Data.Client.Id)
{
tunnelConfigTransfer.OnLocalRouteLevel(tunnelTransportConfigWrapInfo);
tunnelConfigTransfer.OnLocalRouteLevel(tunnelTransportFileConfigInfo);
}
else
{
@@ -104,7 +104,7 @@ namespace linker.plugins.tunnel
{
Connection = clientSignInState.Connection,
MessengerId = (ushort)TunnelMessengerIds.RouteLevelForward,
Payload = MemoryPackSerializer.Serialize(tunnelTransportConfigWrapInfo)
Payload = MemoryPackSerializer.Serialize(tunnelTransportFileConfigInfo)
}).ConfigureAwait(false);
}
@@ -141,7 +141,6 @@ namespace linker.plugins.tunnel
tunnelConfigTransfer.SettExcludeIPs(info);
}
public sealed class TunnelListInfo
{
public ConcurrentDictionary<string, TunnelTransportRouteLevelInfo> List { get; set; }

View File

@@ -12,7 +12,7 @@ namespace linker.plugins.tunnel
{
public sealed class TunnelConfigTransfer
{
private readonly ConfigWrap config;
private readonly FileConfig config;
private readonly RunningConfig running;
private readonly ClientSignInState clientSignInState;
private readonly MessengerSender messengerSender;
@@ -26,7 +26,7 @@ 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, ITunnelAdapter tunnelAdapter)
public TunnelConfigTransfer(FileConfig config, RunningConfig running, ClientSignInState clientSignInState, MessengerSender messengerSender, RunningConfigTransfer runningConfigTransfer, ITunnelAdapter tunnelAdapter)
{
this.config = config;
this.running = running;
@@ -90,21 +90,21 @@ namespace linker.plugins.tunnel
/// <summary>
/// 修改自己的网关层级信息
/// </summary>
/// <param name="tunnelTransportConfigWrapInfo"></param>
public void OnLocalRouteLevel(TunnelTransportRouteLevelInfo tunnelTransportConfigWrapInfo)
/// <param name="tunnelTransportFileConfigInfo"></param>
public void OnLocalRouteLevel(TunnelTransportRouteLevelInfo tunnelTransportFileConfigInfo)
{
running.Data.Tunnel.RouteLevelPlus = tunnelTransportConfigWrapInfo.RouteLevelPlus;
running.Data.Tunnel.RouteLevelPlus = tunnelTransportFileConfigInfo.RouteLevelPlus;
running.Data.Update();
GetRemoveRouteLevel();
}
/// <summary>
/// 收到别人发给我的修改我的信息
/// </summary>
/// <param name="tunnelTransportConfigWrapInfo"></param>
/// <param name="tunnelTransportFileConfigInfo"></param>
/// <returns></returns>
public TunnelTransportRouteLevelInfo OnRemoteRouteLevel(TunnelTransportRouteLevelInfo tunnelTransportConfigWrapInfo)
public TunnelTransportRouteLevelInfo OnRemoteRouteLevel(TunnelTransportRouteLevelInfo tunnelTransportFileConfigInfo)
{
configs.AddOrUpdate(tunnelTransportConfigWrapInfo.MachineId, tunnelTransportConfigWrapInfo, (a, b) => tunnelTransportConfigWrapInfo);
configs.AddOrUpdate(tunnelTransportFileConfigInfo.MachineId, tunnelTransportFileConfigInfo, (a, b) => tunnelTransportFileConfigInfo);
Interlocked.Increment(ref version);
return GetLocalRouteLevel();
}

View File

@@ -27,7 +27,7 @@ namespace linker.plugins.tunnel
public StartupLoadType LoadType => StartupLoadType.Normal;
public void AddClient(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddClient(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
//序列化扩展
MemoryPackFormatterProvider.Register(new TunnelWanPortInfoFormatter());
@@ -66,7 +66,7 @@ namespace linker.plugins.tunnel
}
public void AddServer(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddServer(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
MemoryPackFormatterProvider.Register(new TunnelWanPortInfoFormatter());
MemoryPackFormatterProvider.Register(new TunnelTransportWanPortInfoFormatter());
@@ -77,7 +77,7 @@ namespace linker.plugins.tunnel
serviceCollection.AddSingleton<TunnelServerMessenger>();
}
public void UseClient(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseClient(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
ITunnelAdapter tunnelAdapter = serviceProvider.GetService<ITunnelAdapter>();
@@ -95,7 +95,7 @@ namespace linker.plugins.tunnel
TunnelConfigTransfer tunnelConfigTransfer = serviceProvider.GetService<TunnelConfigTransfer>();
}
public void UseServer(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseServer(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
}

View File

@@ -6,24 +6,37 @@ using MemoryPack;
using System.Net;
using System.Text.Json.Serialization;
using linker.tunnel.adapter;
using System.Net.Sockets;
namespace linker.client.config
{
public sealed partial class RunningConfigInfo
{
/// <summary>
/// 打洞配置
/// </summary>
public TunnelRunningInfo Tunnel { get; set; } = new TunnelRunningInfo();
}
public sealed class TunnelRunningInfo
{
public ObjectId Id { get; set; }
/// <summary>
/// 外网端口服务器列表
/// </summary>
public List<TunnelWanPortInfo> Servers { get; set; } = new List<TunnelWanPortInfo>();
/// <summary>
/// 附加的网关层级
/// </summary>
public int RouteLevelPlus { get; set; } = 0;
/// <summary>
/// 打洞排除IP列表
/// </summary>
public ExcludeIPItem[] ExcludeIPs { get; set; } = Array.Empty<ExcludeIPItem>();
/// <summary>
/// 打洞协议列表
/// </summary>
public List<TunnelTransportItemInfo> Transports { get; set; } = new List<TunnelTransportItemInfo>();
}

View File

@@ -68,15 +68,15 @@ namespace linker.plugins.tunnel.messenger
[MessengerId((ushort)TunnelMessengerIds.RouteLevel)]
public void RouteLevel(IConnection connection)
{
TunnelTransportRouteLevelInfo tunnelTransportConfigWrapInfo = MemoryPackSerializer.Deserialize<TunnelTransportRouteLevelInfo>(connection.ReceiveRequestWrap.Payload.Span);
tunnelConfigTransfer.OnLocalRouteLevel(tunnelTransportConfigWrapInfo);
TunnelTransportRouteLevelInfo tunnelTransportFileConfigInfo = MemoryPackSerializer.Deserialize<TunnelTransportRouteLevelInfo>(connection.ReceiveRequestWrap.Payload.Span);
tunnelConfigTransfer.OnLocalRouteLevel(tunnelTransportFileConfigInfo);
}
[MessengerId((ushort)TunnelMessengerIds.Config)]
public void Config(IConnection connection)
{
TunnelTransportRouteLevelInfo tunnelTransportConfigWrapInfo = MemoryPackSerializer.Deserialize<TunnelTransportRouteLevelInfo>(connection.ReceiveRequestWrap.Payload.Span);
TunnelTransportRouteLevelInfo result = tunnelConfigTransfer.OnRemoteRouteLevel(tunnelTransportConfigWrapInfo);
TunnelTransportRouteLevelInfo tunnelTransportFileConfigInfo = MemoryPackSerializer.Deserialize<TunnelTransportRouteLevelInfo>(connection.ReceiveRequestWrap.Payload.Span);
TunnelTransportRouteLevelInfo result = tunnelConfigTransfer.OnRemoteRouteLevel(tunnelTransportFileConfigInfo);
connection.Write(MemoryPackSerializer.Serialize(result));
}

View File

@@ -19,10 +19,10 @@ namespace linker.plugins.tuntap
private readonly MessengerSender messengerSender;
private readonly TuntapTransfer tuntapTransfer;
private readonly ClientSignInState clientSignInState;
private readonly ConfigWrap config;
private readonly FileConfig config;
private readonly TuntapProxy tuntapProxy;
public TuntapClientApiController(MessengerSender messengerSender, TuntapTransfer tuntapTransfer, ClientSignInState clientSignInState, ConfigWrap config, TuntapProxy tuntapProxy)
public TuntapClientApiController(MessengerSender messengerSender, TuntapTransfer tuntapTransfer, ClientSignInState clientSignInState, FileConfig config, TuntapProxy tuntapProxy)
{
this.messengerSender = messengerSender;
this.tuntapTransfer = tuntapTransfer;

View File

@@ -21,7 +21,7 @@ namespace linker.plugins.tuntap
public StartupLoadType LoadType => StartupLoadType.Normal;
public void AddClient(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddClient(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
//不同平台下的虚拟网卡
if (OperatingSystem.IsWindows()) serviceCollection.AddSingleton<ITuntapVea, TuntapVeaWindows>();
@@ -35,18 +35,18 @@ namespace linker.plugins.tuntap
serviceCollection.AddSingleton<TuntapClientMessenger>();
}
public void AddServer(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddServer(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
serviceCollection.AddSingleton<TuntapServerMessenger>();
}
public void UseClient(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseClient(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
TuntapProxy tuntapProxy = serviceProvider.GetService<TuntapProxy>();
TuntapTransfer tuntapTransfer = serviceProvider.GetService<TuntapTransfer>();
}
public void UseServer(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseServer(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
}
}

View File

@@ -21,7 +21,7 @@ namespace linker.plugins.tuntap
private readonly MessengerSender messengerSender;
private readonly ClientSignInState clientSignInState;
private readonly ITuntapVea tuntapVea;
private readonly ConfigWrap config;
private readonly FileConfig config;
private readonly TuntapProxy tuntapProxy;
private readonly RunningConfig runningConfig;
@@ -34,7 +34,7 @@ namespace linker.plugins.tuntap
private bool starting = false;
public TuntapStatus Status => tuntapVea.Running ? TuntapStatus.Running : (starting ? TuntapStatus.Starting : TuntapStatus.Normal);
public TuntapTransfer(MessengerSender messengerSender, ClientSignInState clientSignInState, ITuntapVea tuntapVea, ConfigWrap config, TuntapProxy tuntapProxy, RunningConfig runningConfig)
public TuntapTransfer(MessengerSender messengerSender, ClientSignInState clientSignInState, ITuntapVea tuntapVea, FileConfig config, TuntapProxy tuntapProxy, RunningConfig runningConfig)
{
this.messengerSender = messengerSender;
this.clientSignInState = clientSignInState;

View File

@@ -20,13 +20,22 @@ namespace linker.plugins.tuntap.config
}
public uint IpInt { get; private set; }
/// <summary>
/// 缓冲区大小
/// </summary>
public byte BufferSize { get; set; } = 3;
/// <summary>
/// 局域网IP列表
/// </summary>
public IPAddress[] LanIPs { get; set; } = Array.Empty<IPAddress>();
/// <summary>
/// 局域网掩码列表与IP列表一一对应
/// </summary>
public int[] Masks { get; set; } = Array.Empty<int>();
/// <summary>
/// 是否在运行中
/// </summary>
public bool Running { get; set; }
}
}
@@ -36,6 +45,9 @@ namespace linker.client.config
{
public sealed partial class RunningConfigInfo
{
/// <summary>
/// 虚拟网卡配置
/// </summary>
public TuntapConfigInfo Tuntap { get; set; } = new TuntapConfigInfo();
}
}

View File

@@ -20,7 +20,7 @@ namespace linker.plugins.tuntap.proxy
private readonly TunnelTransfer tunnelTransfer;
private readonly RelayTransfer relayTransfer;
private readonly RunningConfig runningConfig;
private readonly ConfigWrap config;
private readonly FileConfig config;
private IPEndPoint proxyEP;
public override IPAddress UdpBindAdress { get; set; }
@@ -30,7 +30,7 @@ namespace linker.plugins.tuntap.proxy
private readonly ConcurrentDictionary<string, ITunnelConnection> connections = new ConcurrentDictionary<string, ITunnelConnection>();
private readonly ConcurrentDictionary<string, SemaphoreSlim> dicLocks = new ConcurrentDictionary<string, SemaphoreSlim>();
public TuntapProxy(TunnelTransfer tunnelTransfer, RelayTransfer relayTransfer, RunningConfig runningConfig, ConfigWrap config)
public TuntapProxy(TunnelTransfer tunnelTransfer, RelayTransfer relayTransfer, RunningConfig runningConfig, FileConfig config)
{
this.tunnelTransfer = tunnelTransfer;
this.relayTransfer = relayTransfer;
@@ -60,6 +60,10 @@ namespace linker.plugins.tuntap.proxy
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
LoggerHelper.Instance.Warning($"tuntap add connection {connection.GetHashCode()} {connection.ToJson()}");
if(connections.TryGetValue(connection.RemoteMachineId,out ITunnelConnection connectionOld))
{
connectionOld?.Dispose();
}
connections.AddOrUpdate(connection.RemoteMachineId, connection, (a, b) => connection);
BindConnectionReceive(connection);
}
@@ -245,7 +249,6 @@ namespace linker.plugins.tuntap.proxy
try
{
if (connections.TryGetValue(machineId, out connection) && connection.Connected)
{
return connection;
@@ -262,10 +265,10 @@ namespace linker.plugins.tuntap.proxy
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG) LoggerHelper.Instance.Debug($"tuntap relay to {machineId}");
tunnelTransfer.StartBackground(machineId, "tuntap");
connection = await relayTransfer.ConnectAsync(config.Data.Client.Id, machineId, "tuntap").ConfigureAwait(false);
if (connection != null)
{
tunnelTransfer.StartBackground(machineId, "tuntap");
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG) LoggerHelper.Instance.Debug($"tuntap relay success,{connection.ToString()}");
}
}

View File

@@ -19,15 +19,15 @@ namespace linker.plugins.updater
public StartupLoadType LoadType => StartupLoadType.Normal;
public void AddClient(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddClient(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
}
public void AddServer(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddServer(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
}
public void UseClient(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseClient(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
foreach (var item in Process.GetProcessesByName("linker.updater"))
{
@@ -36,7 +36,7 @@ namespace linker.plugins.updater
//CommandHelper.Execute();
}
public void UseServer(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseServer(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
}
}

View File

@@ -17,24 +17,24 @@ namespace linker.serializes
public string[] Dependent => Array.Empty<string>();
public StartupLoadType LoadType => StartupLoadType.Normal;
public void AddClient(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddClient(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
MemoryPackFormatterProvider.Register(new IPEndPointFormatter());
MemoryPackFormatterProvider.Register(new IPAddressFormatter());
}
public void AddServer(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddServer(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
MemoryPackFormatterProvider.Register(new IPEndPointFormatter());
MemoryPackFormatterProvider.Register(new IPAddressFormatter());
}
public void UseClient(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseClient(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
}
public void UseServer(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseServer(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
}
}

View File

@@ -16,7 +16,7 @@ namespace linker.server
public interface IConnection
{
/// <summary>
/// 连接id
/// 连接id存的应该是客户端id
/// </summary>
public string Id { get; set; }
/// <summary>

View File

@@ -17,14 +17,14 @@ namespace linker.server
public string[] Dependent => new string[] { "serialize", "firewall", "signin" };
public StartupLoadType LoadType => StartupLoadType.Normal;
public void AddClient(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddClient(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
serviceCollection.AddSingleton<MessengerSender>();
serviceCollection.AddSingleton<MessengerResolver>();
serviceCollection.AddSingleton<TcpServer>();
}
public void AddServer(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddServer(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
serviceCollection.AddSingleton<MessengerSender>();
serviceCollection.AddSingleton<MessengerResolver>();
@@ -34,7 +34,7 @@ namespace linker.server
private bool loaded = false;
public void UseClient(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseClient(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
if (loaded == false)
{
@@ -44,7 +44,7 @@ namespace linker.server
}
}
public void UseServer(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseServer(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
if (loaded == false)
{
@@ -59,8 +59,11 @@ namespace linker.server
//服务
TcpServer tcpServer = serviceProvider.GetService<TcpServer>();
tcpServer.Init(config.Data.Server.Certificate, config.Data.Server.Password);
if(config.Data.Server.ServicePort > 0)
{
tcpServer.Start(config.Data.Server.ServicePort);
}
}
catch (Exception ex)
{
LoggerHelper.Instance.Error(ex);

View File

@@ -27,11 +27,11 @@ namespace linker.startup
/// </summary>
public StartupLoadType LoadType { get; }
public void AddClient(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies);
public void UseClient(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies);
public void AddClient(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies);
public void UseClient(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies);
public void AddServer(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies);
public void UseServer(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies);
public void AddServer(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies);
public void UseServer(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies);
}
public enum StartupLoadType

View File

@@ -13,7 +13,7 @@ namespace linker.startup
/// </summary>
/// <param name="config"></param>
/// <param name="assemblies"></param>
public static void Init(ConfigWrap config, Assembly[] assemblies)
public static void Init(FileConfig config, Assembly[] assemblies)
{
var types = ReflectionHelper.GetInterfaceSchieves(assemblies, typeof(IStartup));
List<IStartup> temps = types.Select(c => Activator.CreateInstance(c) as IStartup).OrderByDescending(c => c.Level).ToList();
@@ -41,7 +41,7 @@ namespace linker.startup
/// </summary>
/// <param name="config"></param>
/// <param name="temps"></param>
private static void LoadPlugins(ConfigWrap config, List<IStartup> temps)
private static void LoadPlugins(FileConfig config, List<IStartup> temps)
{
//只要哪些
if (config.Data.Common.IncludePlugins.Length > 0)
@@ -84,7 +84,7 @@ namespace linker.startup
/// <param name="serviceCollection"></param>
/// <param name="config"></param>
/// <param name="assemblies"></param>
public static void Add(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public static void Add(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
foreach (var startup in startups)
{
@@ -101,7 +101,7 @@ namespace linker.startup
/// <param name="serviceProvider"></param>
/// <param name="config"></param>
/// <param name="assemblies"></param>
public static void Use(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public static void Use(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
foreach (var startup in startups)
{

View File

@@ -17,17 +17,17 @@ namespace linker.store
public StartupLoadType LoadType => StartupLoadType.Normal;
bool loaded = false;
public void AddClient(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddClient(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
Add(serviceCollection, config, assemblies);
}
public void AddServer(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
public void AddServer(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
Add(serviceCollection, config, assemblies);
}
private void Add(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
private void Add(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
if (loaded == false)
{
@@ -36,11 +36,11 @@ namespace linker.store
}
}
public void UseClient(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseClient(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
}
public void UseServer(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
public void UseServer(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
}
}