|
@@ -75,7 +75,7 @@
|
|
|
<a-space direction="vertical">
|
|
|
<a-card hoverable style="margin-bottom: .5rem;">
|
|
|
<a-row style="display: flex; flex-wrap: wrap; align-items: center;">
|
|
|
- <a-col :xs="24" :sm="10" style="padding: 4px;">
|
|
|
+ <a-col :xs="24" :sm="8" style="padding: 4px;">
|
|
|
<a-space direction="horizontal">
|
|
|
<a-button type="primary" :disabled="saveBtnDisable" @click="updateXraySetting">{{ i18n "pages.xray.save" }}</a-button>
|
|
|
<a-button type="danger" :disabled="!saveBtnDisable" @click="restartXray">{{ i18n "pages.xray.restart" }}</a-button>
|
|
@@ -89,7 +89,7 @@
|
|
|
</a-popover>
|
|
|
</a-space>
|
|
|
</a-col>
|
|
|
- <a-col :xs="24" :sm="14">
|
|
|
+ <a-col :xs="24" :sm="16">
|
|
|
<template>
|
|
|
<div>
|
|
|
<a-back-top :target="() => document.getElementById('content-layout')" visibility-height="200">
|
|
@@ -103,13 +103,10 @@
|
|
|
</a-col>
|
|
|
</a-row>
|
|
|
</a-card>
|
|
|
- <a-tabs class="ant-card-dark-box-nohover" default-active-key="tpl-1"
|
|
|
- @change="(activeKey) => { if(activeKey == 'tpl-advanced') this.changeCode(); }"
|
|
|
+ <a-tabs class="ant-card-dark-box-nohover" default-active-key="1"
|
|
|
+ @change="(activeKey) => { this.changePage(activeKey); }"
|
|
|
:class="themeSwitcher.currentTheme">
|
|
|
- <a-tab-pane key="tpl-1" tab='{{ i18n "pages.xray.basicTemplate"}}'>
|
|
|
- <a-space direction="horizontal" style="padding: 20px 20px">
|
|
|
- <a-button type="danger" @click="resetXrayConfigToDefault">{{ i18n "pages.settings.resetDefaultConfig" }}</a-button>
|
|
|
- </a-space>
|
|
|
+ <a-tab-pane key="tpl-basic" tab='{{ i18n "pages.xray.basicTemplate"}}' style="padding-top: 20px;">
|
|
|
<a-collapse>
|
|
|
<a-collapse-panel header='{{ i18n "pages.xray.generalConfigs"}}'>
|
|
|
<a-row :xs="24" :sm="24" :lg="12">
|
|
@@ -284,11 +281,14 @@
|
|
|
</template>
|
|
|
<a-button v-else type="primary" icon="cloud" style="margin: 15px 20px;" @click="showWarp()">WARP</a-button>
|
|
|
</a-collapse-panel>
|
|
|
+ <a-collapse-panel header='{{ i18n "pages.settings.resetDefaultConfig"}}'>
|
|
|
+ <a-space direction="horizontal" style="padding: 0 20px">
|
|
|
+ <a-button type="danger" @click="resetXrayConfigToDefault">{{ i18n "pages.settings.resetDefaultConfig" }}</a-button>
|
|
|
+ </a-space>
|
|
|
+ </a-collapse-panel>
|
|
|
</a-collapse>
|
|
|
</a-tab-pane>
|
|
|
- <a-tab-pane key="tpl-2" tab='{{ i18n "pages.xray.Routings"}}' style="padding-top: 20px;">
|
|
|
- <a-alert type="warning" style="margin-bottom: 10px; width: fit-content"
|
|
|
- message='{{ i18n "pages.xray.RoutingsDesc"}}' show-icon></a-alert>
|
|
|
+ <a-tab-pane key="tpl-routing" tab='{{ i18n "pages.xray.Routings"}}' style="padding-top: 20px;">
|
|
|
<a-button type="primary" icon="plus" @click="addRule">{{ i18n "pages.xray.rules.add" }}</a-button>
|
|
|
<a-table-sortable :columns="isMobile ? rulesMobileColumns : rulesColumns" bordered
|
|
|
:row-key="r => r.key"
|
|
@@ -410,7 +410,7 @@
|
|
|
</template>
|
|
|
</a-table-sortable>
|
|
|
</a-tab-pane>
|
|
|
- <a-tab-pane key="tpl-3" tab='{{ i18n "pages.xray.Outbounds"}}' style="padding-top: 20px;" force-render="true">
|
|
|
+ <a-tab-pane key="tpl-outbound" tab='{{ i18n "pages.xray.Outbounds"}}' style="padding-top: 20px;" force-render="true">
|
|
|
<a-row>
|
|
|
<a-col :xs="12" :sm="12" :lg="12">
|
|
|
<a-button type="primary" icon="plus" @click="addOutbound()" style="margin-bottom: 10px;">{{ i18n
|
|
@@ -478,7 +478,7 @@
|
|
|
</template>
|
|
|
</a-table>
|
|
|
</a-tab-pane>
|
|
|
- <a-tab-pane key="tpl-4" tab='{{ i18n "pages.xray.outbound.reverse"}}' style="padding-top: 20px;" force-render="true">
|
|
|
+ <a-tab-pane key="tpl-reverse" tab='{{ i18n "pages.xray.outbound.reverse"}}' style="padding-top: 20px;" force-render="true">
|
|
|
<a-button type="primary" icon="plus" @click="addReverse()" style="margin-bottom: 10px;">{{ i18n "pages.xray.outbound.addReverse" }}</a-button>
|
|
|
<a-table :columns="reverseColumns" bordered v-if="reverseData.length>0"
|
|
|
:row-key="r => r.key"
|
|
@@ -506,9 +506,7 @@
|
|
|
</template>
|
|
|
</a-table>
|
|
|
</a-tab-pane>
|
|
|
- <a-tab-pane key="tpl-5" tab='{{ i18n "pages.xray.Balancers"}}' style="padding-top: 20px;" force-render="true">
|
|
|
- <a-alert type="warning" style="margin-bottom: 10px; width: fit-content"
|
|
|
- message='{{ i18n "pages.xray.balancer.balancerDesc" }}' show-icon></a-alert>
|
|
|
+ <a-tab-pane key="tpl-balancer" tab='{{ i18n "pages.xray.Balancers"}}' style="padding-top: 20px;" force-render="true">
|
|
|
<a-button type="primary" icon="plus" @click="addBalancer()" style="margin-bottom: 10px;">{{ i18n "pages.xray.balancer.addBalancer"}}</a-button>
|
|
|
<a-table :columns="balancerColumns" bordered v-if="balancersData.length>0"
|
|
|
:row-key="r => r.key"
|
|
@@ -544,8 +542,19 @@
|
|
|
<a-tag class="info-large-tag" style="margin:1;" v-for="sel in balancer.selector">[[ sel ]]</a-tag>
|
|
|
</template>
|
|
|
</a-table>
|
|
|
+ <a-radio-group
|
|
|
+ v-model="obsSettings"
|
|
|
+ v-if="observatoryEnable || burstObservatoryEnable"
|
|
|
+ @change="changeObsCode"
|
|
|
+ button-style="solid"
|
|
|
+ style="margin: 10px 0;"
|
|
|
+ :size="isMobile ? 'small' : ''">
|
|
|
+ <a-radio-button value="observatory" v-if="observatoryEnable">Observatory</a-radio-button>
|
|
|
+ <a-radio-button value="burstObservatory" v-if="burstObservatoryEnable">Burst Observatory</a-radio-button>
|
|
|
+ </a-radio-group>
|
|
|
+ <textarea style="position:absolute; left: -800px;" id="obsSetting"></textarea>
|
|
|
</a-tab-pane>
|
|
|
- <a-tab-pane key="tpl-6" tab='DNS' style="padding-top: 20px;" force-render="true">
|
|
|
+ <a-tab-pane key="tpl-dns" tab='DNS' style="padding-top: 20px;" force-render="true">
|
|
|
<setting-list-item type="switch" title='{{ i18n "pages.xray.dns.enable" }}' desc='{{ i18n "pages.xray.dns.enableDesc" }}' v-model="enableDNS"></setting-list-item>
|
|
|
<template v-if="enableDNS">
|
|
|
<setting-list-item type="text" title='{{ i18n "pages.xray.dns.tag" }}' desc='{{ i18n "pages.xray.dns.tagDesc" }}' v-model="dnsTag"></setting-list-item>
|
|
@@ -696,6 +705,13 @@
|
|
|
{ title: '{{ i18n "pages.xray.outbound.domain"}}', dataIndex: 'domain', align: 'center', width: 50 },
|
|
|
];
|
|
|
|
|
|
+ const balancerColumns = [
|
|
|
+ { title: "#", align: 'center', width: 20, scopedSlots: { customRender: 'action' } },
|
|
|
+ { title: '{{ i18n "pages.xray.balancer.tag"}}', dataIndex: 'tag', align: 'center', width: 50 },
|
|
|
+ { title: '{{ i18n "pages.xray.balancer.balancerStrategy"}}', align: 'center', width: 50, scopedSlots: { customRender: 'strategy' }},
|
|
|
+ { title: '{{ i18n "pages.xray.balancer.balancerSelectors"}}', align: 'center', width: 100, scopedSlots: { customRender: 'selector' }},
|
|
|
+ ];
|
|
|
+
|
|
|
const dnsColumns = [
|
|
|
{ title: "#", align: 'center', width: 20, scopedSlots: { customRender: 'action' } },
|
|
|
{ title: '{{ i18n "pages.xray.outbound.address"}}', align: 'center', width: 50, scopedSlots: { customRender: 'address' } },
|
|
@@ -708,13 +724,6 @@
|
|
|
{ title: '{{ i18n "pages.xray.fakedns.poolSize"}}', dataIndex: 'poolSize', align: 'center', width: 50 },
|
|
|
];
|
|
|
|
|
|
- const balancerColumns = [
|
|
|
- { title: "#", align: 'center', width: 20, scopedSlots: { customRender: 'action' } },
|
|
|
- { title: '{{ i18n "pages.xray.balancer.tag"}}', dataIndex: 'tag', align: 'center', width: 50 },
|
|
|
- { title: '{{ i18n "pages.xray.balancer.balancerStrategy"}}', align: 'center', width: 50, scopedSlots: { customRender: 'strategy' }},
|
|
|
- { title: '{{ i18n "pages.xray.balancer.balancerSelectors"}}', align: 'center', width: 100, scopedSlots: { customRender: 'selector' }},
|
|
|
- ];
|
|
|
-
|
|
|
const app = new Vue({
|
|
|
delimiters: ['[[', ']]'],
|
|
|
el: '#app',
|
|
@@ -733,6 +742,7 @@
|
|
|
showAlert: false,
|
|
|
isMobile: window.innerWidth <= 768,
|
|
|
advSettings: 'xraySetting',
|
|
|
+ obsSettings: '',
|
|
|
cm: null,
|
|
|
cmOptions: {
|
|
|
lineNumbers: true,
|
|
@@ -827,6 +837,22 @@
|
|
|
],
|
|
|
"queryStrategy": "UseIP"
|
|
|
},
|
|
|
+ },
|
|
|
+ defaultObservatory: {
|
|
|
+ subjectSelector: [],
|
|
|
+ probeURL: "http://www.google.com/gen_204",
|
|
|
+ probeInterval: "10m",
|
|
|
+ enableConcurrency: true
|
|
|
+ },
|
|
|
+ defaultBurstObservatory: {
|
|
|
+ subjectSelector: [],
|
|
|
+ pingConfig: {
|
|
|
+ destination: "http://www.google.com/gen_204",
|
|
|
+ interval: "30m",
|
|
|
+ connectivity: "http://connectivitycheck.platform.hicloud.com/generate_204",
|
|
|
+ timeout: "10s",
|
|
|
+ sampling: 2
|
|
|
+ }
|
|
|
}
|
|
|
},
|
|
|
methods: {
|
|
@@ -927,6 +953,10 @@
|
|
|
this.saveBtnDisable = true;
|
|
|
}
|
|
|
},
|
|
|
+ changePage(pageKey) {
|
|
|
+ if(pageKey == 'tpl-advanced') this.changeCode();
|
|
|
+ if(pageKey == 'tpl-balancer') this.changeObsCode();
|
|
|
+ },
|
|
|
syncRulesWithOutbound(tag, setting) {
|
|
|
const newTemplateSettings = this.templateSettings;
|
|
|
const haveRules = newTemplateSettings.routing.rules.some((r) => r?.outboundTag === tag);
|
|
@@ -1009,6 +1039,23 @@
|
|
|
}
|
|
|
});
|
|
|
},
|
|
|
+ changeObsCode() {
|
|
|
+ if (this.obsSettings == ''){
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if(this.cm != null) {
|
|
|
+ this.cm.toTextArea();
|
|
|
+ }
|
|
|
+ textAreaObj = document.getElementById('obsSetting');
|
|
|
+ textAreaObj.value = this[this.obsSettings];
|
|
|
+ this.cm = CodeMirror.fromTextArea(textAreaObj, this.cmOptions);
|
|
|
+ this.cm.on('change',editor => {
|
|
|
+ value = editor.getValue();
|
|
|
+ if(this.isJsonString(value)){
|
|
|
+ this[this.obsSettings] = value;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
isJsonString(str) {
|
|
|
try {
|
|
|
JSON.parse(str);
|
|
@@ -1087,6 +1134,91 @@
|
|
|
outbounds.splice(0, 0, outbounds.splice(index, 1)[0]);
|
|
|
this.outboundSettings = JSON.stringify(outbounds);
|
|
|
},
|
|
|
+ addReverse(){
|
|
|
+ reverseModal.show({
|
|
|
+ title: '{{ i18n "pages.xray.outbound.addReverse"}}',
|
|
|
+ okText: '{{ i18n "pages.xray.outbound.addReverse" }}',
|
|
|
+ confirm: (reverse, rules) => {
|
|
|
+ reverseModal.loading();
|
|
|
+ if(reverse.tag.length > 0){
|
|
|
+ newTemplateSettings = this.templateSettings;
|
|
|
+ if(newTemplateSettings.reverse == undefined) newTemplateSettings.reverse = {};
|
|
|
+ if(newTemplateSettings.reverse[reverse.type+'s'] == undefined) newTemplateSettings.reverse[reverse.type+'s'] = [];
|
|
|
+ newTemplateSettings.reverse[reverse.type+'s'].push({ tag: reverse.tag, domain: reverse.domain });
|
|
|
+ this.templateSettings = newTemplateSettings;
|
|
|
+
|
|
|
+ // Add related rules
|
|
|
+ this.templateSettings.routing.rules.push(...rules);
|
|
|
+ this.routingRuleSettings = JSON.stringify(this.templateSettings.routing.rules);
|
|
|
+ }
|
|
|
+ reverseModal.close();
|
|
|
+ },
|
|
|
+ isEdit: false
|
|
|
+ });
|
|
|
+ },
|
|
|
+ editReverse(index){
|
|
|
+ if(this.reverseData[index].type == "bridge") {
|
|
|
+ oldRules = this.templateSettings.routing.rules.filter(r => r.inboundTag && r.inboundTag[0] == this.reverseData[index].tag);
|
|
|
+ } else {
|
|
|
+ oldRules = this.templateSettings.routing.rules.filter(r => r.outboundTag && r.outboundTag == this.reverseData[index].tag);
|
|
|
+ }
|
|
|
+ reverseModal.show({
|
|
|
+ title: '{{ i18n "pages.xray.outbound.editReverse"}} ' + (index+1),
|
|
|
+ reverse: this.reverseData[index],
|
|
|
+ rules: oldRules,
|
|
|
+ confirm: (reverse, rules) => {
|
|
|
+ reverseModal.loading();
|
|
|
+ if(reverse.tag.length > 0){
|
|
|
+ oldData = this.reverseData[index];
|
|
|
+ newTemplateSettings = this.templateSettings;
|
|
|
+ oldReverseIndex = newTemplateSettings.reverse[oldData.type+'s'].findIndex(rs => rs.tag == oldData.tag);
|
|
|
+ oldRuleIndex0 = oldRules.length>0 ? newTemplateSettings.routing.rules.findIndex(r => JSON.stringify(r) == JSON.stringify(oldRules[0])) : -1;
|
|
|
+ oldRuleIndex1 = oldRules.length==2 ? newTemplateSettings.routing.rules.findIndex(r => JSON.stringify(r) == JSON.stringify(oldRules[1])) : -1;
|
|
|
+ if(oldData.type == reverse.type){
|
|
|
+ newTemplateSettings.reverse[oldData.type + 's'][oldReverseIndex] = { tag: reverse.tag, domain: reverse.domain };
|
|
|
+ } else {
|
|
|
+ newTemplateSettings.reverse[oldData.type+'s'].splice(oldReverseIndex,1);
|
|
|
+ // delete empty object
|
|
|
+ if(newTemplateSettings.reverse[oldData.type+'s'].length == 0) Reflect.deleteProperty(newTemplateSettings.reverse, oldData.type+'s');
|
|
|
+ // add other type of reverse if it is not exist
|
|
|
+ if(!newTemplateSettings.reverse[reverse.type+'s']) newTemplateSettings.reverse[reverse.type+'s'] = [];
|
|
|
+ newTemplateSettings.reverse[reverse.type+'s'].push({ tag: reverse.tag, domain: reverse.domain });
|
|
|
+ }
|
|
|
+ this.templateSettings = newTemplateSettings;
|
|
|
+
|
|
|
+ // Adjust Rules
|
|
|
+ newRules = this.templateSettings.routing.rules;
|
|
|
+ oldRuleIndex0 != -1 ? newRules[oldRuleIndex0] = rules[0] : newRules.push(rules[0]);
|
|
|
+ oldRuleIndex1 != -1 ? newRules[oldRuleIndex1] = rules[1] : newRules.push(rules[1]);
|
|
|
+ this.routingRuleSettings = JSON.stringify(newRules);
|
|
|
+ }
|
|
|
+ reverseModal.close();
|
|
|
+ },
|
|
|
+ isEdit: true
|
|
|
+ });
|
|
|
+ },
|
|
|
+ deleteReverse(index){
|
|
|
+ oldData = this.reverseData[index];
|
|
|
+ newTemplateSettings = this.templateSettings;
|
|
|
+ reverseTypeObj = newTemplateSettings.reverse[oldData.type+'s'];
|
|
|
+ realIndex = reverseTypeObj.findIndex(r => r.tag==oldData.tag && r.domain==oldData.domain);
|
|
|
+ newTemplateSettings.reverse[oldData.type+'s'].splice(realIndex,1);
|
|
|
+
|
|
|
+ // delete empty objects
|
|
|
+ if(reverseTypeObj.length == 0) Reflect.deleteProperty(newTemplateSettings.reverse, oldData.type+'s');
|
|
|
+ if(Object.keys(newTemplateSettings.reverse).length === 0) Reflect.deleteProperty(newTemplateSettings, 'reverse');
|
|
|
+
|
|
|
+ // delete related routing rules
|
|
|
+ newRules = newTemplateSettings.routing.rules;
|
|
|
+ if(oldData.type == "bridge"){
|
|
|
+ newRules = newTemplateSettings.routing.rules.filter(r => !( r.inboundTag && r.inboundTag.length == 1 && r.inboundTag[0] == oldData.tag));
|
|
|
+ } else if(oldData.type == "portal"){
|
|
|
+ newRules = newTemplateSettings.routing.rules.filter(r => r.outboundTag != oldData.tag);
|
|
|
+ }
|
|
|
+ newTemplateSettings.routing.rules = newRules;
|
|
|
+
|
|
|
+ this.templateSettings = newTemplateSettings;
|
|
|
+ },
|
|
|
async refreshOutboundTraffic() {
|
|
|
if (!this.refreshing) {
|
|
|
this.refreshing = true;
|
|
@@ -1133,14 +1265,27 @@
|
|
|
'tag': balancer.tag,
|
|
|
'selector': balancer.selector
|
|
|
};
|
|
|
- if (balancer.strategy === 'roundRobin' || balancer.strategy === 'leastload' || balancer.strategy === 'leastping') {
|
|
|
+ if (balancer.strategy && balancer.strategy != 'random') {
|
|
|
tmpBalancer.strategy = {
|
|
|
'type': balancer.strategy
|
|
|
};
|
|
|
+ if (balancer.strategy == 'leastPing'){
|
|
|
+ if (!newTemplateSettings.observatory)
|
|
|
+ newTemplateSettings.observatory = this.defaultObservatory;
|
|
|
+ if (!newTemplateSettings.observatory.subjectSelector.includes(balancer.tag))
|
|
|
+ newTemplateSettings.observatory.subjectSelector.push(balancer.tag);
|
|
|
+ }
|
|
|
+ if (balancer.strategy == 'leastLoad'){
|
|
|
+ if (!newTemplateSettings.burstObservatory)
|
|
|
+ newTemplateSettings.burstObservatory = this.defaultBurstObservatory;
|
|
|
+ if (!newTemplateSettings.burstObservatory.subjectSelector.includes(balancer.tag))
|
|
|
+ newTemplateSettings.burstObservatory.subjectSelector.push(balancer.tag);
|
|
|
+ }
|
|
|
}
|
|
|
newTemplateSettings.routing.balancers.push(tmpBalancer);
|
|
|
this.templateSettings = newTemplateSettings;
|
|
|
balancerModal.close();
|
|
|
+ this.changeObsCode();
|
|
|
},
|
|
|
isEdit: false
|
|
|
});
|
|
@@ -1160,10 +1305,31 @@
|
|
|
'tag': balancer.tag,
|
|
|
'selector': balancer.selector
|
|
|
};
|
|
|
- if (balancer.strategy === 'roundRobin' || balancer.strategy === 'leastload' || balancer.strategy === 'leastping') {
|
|
|
+
|
|
|
+ // Remove old tag
|
|
|
+ if (newTemplateSettings.observatory){
|
|
|
+ newTemplateSettings.observatory.subjectSelector = newTemplateSettings.observatory.subjectSelector.filter(s => s != oldTag);
|
|
|
+ }
|
|
|
+ if (newTemplateSettings.burstObservatory){
|
|
|
+ newTemplateSettings.burstObservatory.subjectSelector = newTemplateSettings.burstObservatory.subjectSelector.filter(s => s != oldTag);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (balancer.strategy && balancer.strategy != 'random') {
|
|
|
tmpBalancer.strategy = {
|
|
|
'type': balancer.strategy
|
|
|
};
|
|
|
+ if (balancer.strategy == 'leastPing'){
|
|
|
+ if (!newTemplateSettings.observatory)
|
|
|
+ newTemplateSettings.observatory = this.defaultObservatory;
|
|
|
+ if (!newTemplateSettings.observatory.subjectSelector.includes(balancer.tag))
|
|
|
+ newTemplateSettings.observatory.subjectSelector.push(balancer.tag);
|
|
|
+ }
|
|
|
+ if (balancer.strategy == 'leastLoad'){
|
|
|
+ if (!newTemplateSettings.burstObservatory)
|
|
|
+ newTemplateSettings.burstObservatory = this.defaultBurstObservatory;
|
|
|
+ if (!newTemplateSettings.burstObservatory.subjectSelector.includes(balancer.tag))
|
|
|
+ newTemplateSettings.burstObservatory.subjectSelector.push(balancer.tag);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
newTemplateSettings.routing.balancers[index] = tmpBalancer;
|
|
@@ -1177,6 +1343,7 @@
|
|
|
}
|
|
|
this.templateSettings = newTemplateSettings;
|
|
|
balancerModal.close();
|
|
|
+ this.changeObsCode();
|
|
|
},
|
|
|
isEdit: true
|
|
|
});
|
|
@@ -1191,6 +1358,14 @@
|
|
|
let realIndex = newTemplateSettings.routing.balancers.findIndex((b) => b.tag === removedBalancer.tag);
|
|
|
newTemplateSettings.routing.balancers.splice(realIndex, 1);
|
|
|
|
|
|
+ // Remove tag from observatory
|
|
|
+ if (newTemplateSettings.observatory){
|
|
|
+ newTemplateSettings.observatory.subjectSelector = newTemplateSettings.observatory.subjectSelector.filter(s => s != removedBalancer.tag);
|
|
|
+ }
|
|
|
+ if (newTemplateSettings.burstObservatory){
|
|
|
+ newTemplateSettings.burstObservatory.subjectSelector = newTemplateSettings.burstObservatory.subjectSelector.filter(s => s != removedBalancer.tag);
|
|
|
+ }
|
|
|
+
|
|
|
// Remove related routing rules
|
|
|
newTemplateSettings.routing.rules.forEach((rule) => {
|
|
|
if (rule.balancerTag === removedBalancer.tag) {
|
|
@@ -1203,91 +1378,7 @@
|
|
|
delete newTemplateSettings.routing.balancers;
|
|
|
}
|
|
|
this.templateSettings = newTemplateSettings;
|
|
|
- },
|
|
|
- addReverse(){
|
|
|
- reverseModal.show({
|
|
|
- title: '{{ i18n "pages.xray.outbound.addReverse"}}',
|
|
|
- okText: '{{ i18n "pages.xray.outbound.addReverse" }}',
|
|
|
- confirm: (reverse, rules) => {
|
|
|
- reverseModal.loading();
|
|
|
- if(reverse.tag.length > 0){
|
|
|
- newTemplateSettings = this.templateSettings;
|
|
|
- if(newTemplateSettings.reverse == undefined) newTemplateSettings.reverse = {};
|
|
|
- if(newTemplateSettings.reverse[reverse.type+'s'] == undefined) newTemplateSettings.reverse[reverse.type+'s'] = [];
|
|
|
- newTemplateSettings.reverse[reverse.type+'s'].push({ tag: reverse.tag, domain: reverse.domain });
|
|
|
- this.templateSettings = newTemplateSettings;
|
|
|
-
|
|
|
- // Add related rules
|
|
|
- this.templateSettings.routing.rules.push(...rules);
|
|
|
- this.routingRuleSettings = JSON.stringify(this.templateSettings.routing.rules);
|
|
|
- }
|
|
|
- reverseModal.close();
|
|
|
- },
|
|
|
- isEdit: false
|
|
|
- });
|
|
|
- },
|
|
|
- editReverse(index){
|
|
|
- if(this.reverseData[index].type == "bridge") {
|
|
|
- oldRules = this.templateSettings.routing.rules.filter(r => r.inboundTag && r.inboundTag[0] == this.reverseData[index].tag);
|
|
|
- } else {
|
|
|
- oldRules = this.templateSettings.routing.rules.filter(r => r.outboundTag && r.outboundTag == this.reverseData[index].tag);
|
|
|
- }
|
|
|
- reverseModal.show({
|
|
|
- title: '{{ i18n "pages.xray.outbound.editReverse"}} ' + (index+1),
|
|
|
- reverse: this.reverseData[index],
|
|
|
- rules: oldRules,
|
|
|
- confirm: (reverse, rules) => {
|
|
|
- reverseModal.loading();
|
|
|
- if(reverse.tag.length > 0){
|
|
|
- oldData = this.reverseData[index];
|
|
|
- newTemplateSettings = this.templateSettings;
|
|
|
- oldReverseIndex = newTemplateSettings.reverse[oldData.type+'s'].findIndex(rs => rs.tag == oldData.tag);
|
|
|
- oldRuleIndex0 = oldRules.length>0 ? newTemplateSettings.routing.rules.findIndex(r => JSON.stringify(r) == JSON.stringify(oldRules[0])) : -1;
|
|
|
- oldRuleIndex1 = oldRules.length==2 ? newTemplateSettings.routing.rules.findIndex(r => JSON.stringify(r) == JSON.stringify(oldRules[1])) : -1;
|
|
|
- if(oldData.type == reverse.type){
|
|
|
- newTemplateSettings.reverse[oldData.type + 's'][oldReverseIndex] = { tag: reverse.tag, domain: reverse.domain };
|
|
|
- } else {
|
|
|
- newTemplateSettings.reverse[oldData.type+'s'].splice(oldReverseIndex,1);
|
|
|
- // delete empty object
|
|
|
- if(newTemplateSettings.reverse[oldData.type+'s'].length == 0) Reflect.deleteProperty(newTemplateSettings.reverse, oldData.type+'s');
|
|
|
- // add other type of reverse if it is not exist
|
|
|
- if(!newTemplateSettings.reverse[reverse.type+'s']) newTemplateSettings.reverse[reverse.type+'s'] = [];
|
|
|
- newTemplateSettings.reverse[reverse.type+'s'].push({ tag: reverse.tag, domain: reverse.domain });
|
|
|
- }
|
|
|
- this.templateSettings = newTemplateSettings;
|
|
|
-
|
|
|
- // Adjust Rules
|
|
|
- newRules = this.templateSettings.routing.rules;
|
|
|
- oldRuleIndex0 != -1 ? newRules[oldRuleIndex0] = rules[0] : newRules.push(rules[0]);
|
|
|
- oldRuleIndex1 != -1 ? newRules[oldRuleIndex1] = rules[1] : newRules.push(rules[1]);
|
|
|
- this.routingRuleSettings = JSON.stringify(newRules);
|
|
|
- }
|
|
|
- reverseModal.close();
|
|
|
- },
|
|
|
- isEdit: true
|
|
|
- });
|
|
|
- },
|
|
|
- deleteReverse(index){
|
|
|
- oldData = this.reverseData[index];
|
|
|
- newTemplateSettings = this.templateSettings;
|
|
|
- reverseTypeObj = newTemplateSettings.reverse[oldData.type+'s'];
|
|
|
- realIndex = reverseTypeObj.findIndex(r => r.tag==oldData.tag && r.domain==oldData.domain);
|
|
|
- newTemplateSettings.reverse[oldData.type+'s'].splice(realIndex,1);
|
|
|
-
|
|
|
- // delete empty objects
|
|
|
- if(reverseTypeObj.length == 0) Reflect.deleteProperty(newTemplateSettings.reverse, oldData.type+'s');
|
|
|
- if(Object.keys(newTemplateSettings.reverse).length === 0) Reflect.deleteProperty(newTemplateSettings, 'reverse');
|
|
|
-
|
|
|
- // delete related routing rules
|
|
|
- newRules = newTemplateSettings.routing.rules;
|
|
|
- if(oldData.type == "bridge"){
|
|
|
- newRules = newTemplateSettings.routing.rules.filter(r => !( r.inboundTag && r.inboundTag.length == 1 && r.inboundTag[0] == oldData.tag));
|
|
|
- } else if(oldData.type == "portal"){
|
|
|
- newRules = newTemplateSettings.routing.rules.filter(r => r.outboundTag != oldData.tag);
|
|
|
- }
|
|
|
- newTemplateSettings.routing.rules = newRules;
|
|
|
-
|
|
|
- this.templateSettings = newTemplateSettings;
|
|
|
+ this.changeObsCode()
|
|
|
},
|
|
|
addDNSServer(){
|
|
|
dnsModal.show({
|
|
@@ -1479,27 +1570,6 @@
|
|
|
return data;
|
|
|
},
|
|
|
},
|
|
|
- balancersData: {
|
|
|
- get: function () {
|
|
|
- data = []
|
|
|
- if (this.templateSettings != null && this.templateSettings.routing != null && this.templateSettings.routing.balancers != null) {
|
|
|
- this.templateSettings.routing.balancers.forEach((o, index) => {
|
|
|
- let strategy = "random"
|
|
|
- if (o.strategy && (o.strategy.type == "roundRobin" || o.strategy.type == "leastload" || o.strategy.type == "leastping")) {
|
|
|
- strategy = o.strategy.type;
|
|
|
- }
|
|
|
-
|
|
|
- data.push({
|
|
|
- 'key': index,
|
|
|
- 'tag': o.tag ? o.tag : "",
|
|
|
- 'strategy': strategy,
|
|
|
- 'selector': o.selector ? o.selector : []
|
|
|
- });
|
|
|
- });
|
|
|
- }
|
|
|
- return data;
|
|
|
- }
|
|
|
- },
|
|
|
routingRuleSettings: {
|
|
|
get: function () { return this.templateSettings ? JSON.stringify(this.templateSettings.routing.rules, null, 2) : null; },
|
|
|
set: function (newValue) {
|
|
@@ -1529,6 +1599,58 @@
|
|
|
return data;
|
|
|
}
|
|
|
},
|
|
|
+ balancersData: {
|
|
|
+ get: function () {
|
|
|
+ data = []
|
|
|
+ if (this.templateSettings != null && this.templateSettings.routing != null && this.templateSettings.routing.balancers != null) {
|
|
|
+ this.templateSettings.routing.balancers.forEach((o, index) => {
|
|
|
+ data.push({
|
|
|
+ 'key': index,
|
|
|
+ 'tag': o.tag ? o.tag : "",
|
|
|
+ 'strategy': o.strategy?.type ?? "random",
|
|
|
+ 'selector': o.selector ? o.selector : []
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return data;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ observatory: {
|
|
|
+ get: function () {
|
|
|
+ return this.templateSettings?.observatory ? JSON.stringify(this.templateSettings.observatory, null, 2) : null;
|
|
|
+ },
|
|
|
+ set: function (newValue) {
|
|
|
+ newTemplateSettings = this.templateSettings;
|
|
|
+ newTemplateSettings.observatory = JSON.parse(newValue);
|
|
|
+ this.templateSettings = newTemplateSettings;
|
|
|
+ },
|
|
|
+ },
|
|
|
+ burstObservatory: {
|
|
|
+ get: function () {
|
|
|
+ return this.templateSettings?.burstObservatory ? JSON.stringify(this.templateSettings.burstObservatory, null, 2) : null;
|
|
|
+ },
|
|
|
+ set: function (newValue) {
|
|
|
+ newTemplateSettings = this.templateSettings;
|
|
|
+ newTemplateSettings.burstObservatory = JSON.parse(newValue);
|
|
|
+ this.templateSettings = newTemplateSettings;
|
|
|
+ },
|
|
|
+ },
|
|
|
+ observatoryEnable: {
|
|
|
+ get: function () { return this.templateSettings != null && this.templateSettings.observatory },
|
|
|
+ set: function (v) {
|
|
|
+ newTemplateSettings = this.templateSettings;
|
|
|
+ newTemplateSettings.observatory = v ? this.defaultObservatory : undefined;
|
|
|
+ this.templateSettings = newTemplateSettings;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ burstObservatoryEnable: {
|
|
|
+ get: function () { return this.templateSettings != null && this.templateSettings.burstObservatory },
|
|
|
+ set: function (v) {
|
|
|
+ newTemplateSettings = this.templateSettings;
|
|
|
+ newTemplateSettings.burstObservatory = v ? this.defaultBurstObservatory : undefined;
|
|
|
+ this.templateSettings = newTemplateSettings;
|
|
|
+ }
|
|
|
+ },
|
|
|
freedomStrategy: {
|
|
|
get: function () {
|
|
|
if (!this.templateSettings) return "AsIs";
|