mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2025-09-09 19:56:19 +00:00
Merge branch 'MHSanaei:main' into MH
This commit is contained in:
commit
9f6fd7bdca
14 changed files with 394 additions and 23 deletions
8
go.mod
8
go.mod
|
@ -18,12 +18,12 @@ require (
|
||||||
go.uber.org/atomic v1.11.0
|
go.uber.org/atomic v1.11.0
|
||||||
golang.org/x/text v0.14.0
|
golang.org/x/text v0.14.0
|
||||||
google.golang.org/grpc v1.61.0
|
google.golang.org/grpc v1.61.0
|
||||||
gorm.io/driver/sqlite v1.5.4
|
gorm.io/driver/sqlite v1.5.5
|
||||||
gorm.io/gorm v1.25.6
|
gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/andybalholm/brotli v1.0.6 // indirect
|
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||||
github.com/bytedance/sonic v1.10.2 // indirect
|
github.com/bytedance/sonic v1.10.2 // indirect
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
|
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
|
||||||
github.com/chenzhuoyu/iasm v0.9.1 // indirect
|
github.com/chenzhuoyu/iasm v0.9.1 // indirect
|
||||||
|
@ -91,7 +91,7 @@ require (
|
||||||
golang.org/x/tools v0.16.1 // indirect
|
golang.org/x/tools v0.16.1 // indirect
|
||||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect
|
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 // indirect
|
||||||
google.golang.org/protobuf v1.32.0 // indirect
|
google.golang.org/protobuf v1.32.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
gvisor.dev/gvisor v0.0.0-20231104011432-48a6d7d5bd0b // indirect
|
gvisor.dev/gvisor v0.0.0-20231104011432-48a6d7d5bd0b // indirect
|
||||||
|
|
16
go.sum
16
go.sum
|
@ -12,8 +12,8 @@ github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8
|
||||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||||
github.com/Calidity/gin-sessions v1.3.1 h1:nF3dCBWa7TZ4j26iYLwGRmzZy9YODhWoOS3fmi+snyE=
|
github.com/Calidity/gin-sessions v1.3.1 h1:nF3dCBWa7TZ4j26iYLwGRmzZy9YODhWoOS3fmi+snyE=
|
||||||
github.com/Calidity/gin-sessions v1.3.1/go.mod h1:I0+QE6qkO50TeN/n6If6novvxHk4Isvr23U8EdvPdns=
|
github.com/Calidity/gin-sessions v1.3.1/go.mod h1:I0+QE6qkO50TeN/n6If6novvxHk4Isvr23U8EdvPdns=
|
||||||
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
|
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
||||||
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
||||||
|
@ -406,8 +406,8 @@ google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoA
|
||||||
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
|
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
|
||||||
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 h1:gphdwh0npgs8elJ4T6J+DQJHPVF7RsuJHCfwztUb4J4=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 h1:6G8oQ016D88m1xAKljMlBOOGWDZkes4kMhgGFlf8WcQ=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917/go.mod h1:xtjpI3tXFPP051KaWnhvxkiubL/6dJ18vLVf7q2pTOU=
|
||||||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||||
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
||||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||||
|
@ -434,10 +434,10 @@ gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gorm.io/driver/sqlite v1.5.4 h1:IqXwXi8M/ZlPzH/947tn5uik3aYQslP9BVveoax0nV0=
|
gorm.io/driver/sqlite v1.5.5 h1:7MDMtUZhV065SilG62E0MquljeArQZNfJnjd9i9gx3E=
|
||||||
gorm.io/driver/sqlite v1.5.4/go.mod h1:qxAuCol+2r6PannQDpOP1FP6ag3mKi4esLnB/jHed+4=
|
gorm.io/driver/sqlite v1.5.5/go.mod h1:6NgQ7sQWAIFsPrJJl1lSNSu2TABh0ZZ/zm5fosATavE=
|
||||||
gorm.io/gorm v1.25.6 h1:V92+vVda1wEISSOMtodHVRcUIOPYa2tgQtyF+DfFx+A=
|
gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde h1:9DShaph9qhkIYw7QF91I/ynrr4cOO2PZra2PFD7Mfeg=
|
||||||
gorm.io/gorm v1.25.6/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||||
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
|
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
|
||||||
gvisor.dev/gvisor v0.0.0-20231104011432-48a6d7d5bd0b h1:yqkg3pTifuKukuWanp8spDsL4irJkHF5WI0J47hU87o=
|
gvisor.dev/gvisor v0.0.0-20231104011432-48a6d7d5bd0b h1:yqkg3pTifuKukuWanp8spDsL4irJkHF5WI0J47hU87o=
|
||||||
gvisor.dev/gvisor v0.0.0-20231104011432-48a6d7d5bd0b/go.mod h1:10sU+Uh5KKNv1+2x2A0Gvzt8FjD3ASIhorV3YsauXhk=
|
gvisor.dev/gvisor v0.0.0-20231104011432-48a6d7d5bd0b/go.mod h1:10sU+Uh5KKNv1+2x2A0Gvzt8FjD3ASIhorV3YsauXhk=
|
||||||
|
|
|
@ -430,8 +430,8 @@
|
||||||
loading: false,
|
loading: false,
|
||||||
show(logs) {
|
show(logs) {
|
||||||
this.visible = true;
|
this.visible = true;
|
||||||
this.logs = logs;
|
this.logs = logs || [];
|
||||||
this.formattedLogs = logs.length > 0 ? this.formatLogs(logs) : "No Record...";
|
this.formattedLogs = this.logs.length > 0 ? this.formatLogs(this.logs) : "No Record...";
|
||||||
},
|
},
|
||||||
formatLogs(logs) {
|
formatLogs(logs) {
|
||||||
let formattedLogs = '';
|
let formattedLogs = '';
|
||||||
|
|
|
@ -327,6 +327,14 @@
|
||||||
[[ rule.outboundTag ]]
|
[[ rule.outboundTag ]]
|
||||||
</a-popover>
|
</a-popover>
|
||||||
</template>
|
</template>
|
||||||
|
<template slot="balancer" slot-scope="text, rule, index">
|
||||||
|
<a-popover :overlay-class-name="themeSwitcher.currentTheme">
|
||||||
|
<template slot="content">
|
||||||
|
<p v-if="rule.balancerTag">Balancer Tag: [[ rule.balancerTag ]]</p>
|
||||||
|
</template>
|
||||||
|
[[ rule.balancerTag ]]
|
||||||
|
</a-popover>
|
||||||
|
</template>
|
||||||
<template slot="info" slot-scope="text, rule, index">
|
<template slot="info" slot-scope="text, rule, index">
|
||||||
<a-popover placement="bottomRight"
|
<a-popover placement="bottomRight"
|
||||||
v-if="(rule.source+rule.sourcePort+rule.network+rule.protocol+rule.attrs+rule.ip+rule.domain+rule.port).length>0"
|
v-if="(rule.source+rule.sourcePort+rule.network+rule.protocol+rule.attrs+rule.ip+rule.domain+rule.port).length>0"
|
||||||
|
@ -452,6 +460,41 @@
|
||||||
</template>
|
</template>
|
||||||
</a-table>
|
</a-table>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
|
<a-tab-pane key="tpl-balancers" 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
|
||||||
|
:row-key="r => r.key"
|
||||||
|
:data-source="balancersData"
|
||||||
|
:scroll="isMobile ? {} : { x: 200 }"
|
||||||
|
:pagination="false"
|
||||||
|
:indent-size="0"
|
||||||
|
:style="isMobile ? 'padding: 5px 0' : 'margin-left: 1px;'">
|
||||||
|
<template slot="action" slot-scope="text, balancer, index">
|
||||||
|
[[ index+1 ]]
|
||||||
|
<a-dropdown :trigger="['click']">
|
||||||
|
<a-icon @click="e => e.preventDefault()" type="more" style="font-size: 16px; text-decoration: bold;"></a-icon>
|
||||||
|
<a-menu slot="overlay" :theme="themeSwitcher.currentTheme">
|
||||||
|
<a-menu-item @click="editBalancer(index)">
|
||||||
|
<a-icon type="edit"></a-icon>
|
||||||
|
{{ i18n "edit" }}
|
||||||
|
</a-menu-item>
|
||||||
|
<a-menu-item @click="deleteBalancer(index)">
|
||||||
|
<span style="color: #FF4D4F">
|
||||||
|
<a-icon type="delete"></a-icon> {{ i18n "delete"}}
|
||||||
|
</span>
|
||||||
|
</a-menu-item>
|
||||||
|
</a-menu>
|
||||||
|
</a-dropdown>
|
||||||
|
</template>
|
||||||
|
<template slot="strategy" slot-scope="text, balancer, index">
|
||||||
|
<a-tag style="margin:0;" v-if="balancer.strategy=='random'" color="purple">Random</a-tag>
|
||||||
|
<a-tag style="margin:0;" v-if="balancer.strategy=='roundRobin'" color="green">Round Robin</a-tag>
|
||||||
|
</template>
|
||||||
|
<template slot="selector" slot-scope="text, balancer, index">
|
||||||
|
<a-tag class="info-large-tag" style="margin:1;" v-for="sel in balancer.selector">[[ sel ]]</a-tag>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</a-tab-pane>
|
||||||
<a-tab-pane key="tpl-advanced" tab='{{ i18n "pages.xray.advancedTemplate"}}' style="padding-top: 20px;" force-render="true">
|
<a-tab-pane key="tpl-advanced" tab='{{ i18n "pages.xray.advancedTemplate"}}' style="padding-top: 20px;" force-render="true">
|
||||||
<a-list-item-meta title='{{ i18n "pages.xray.Template"}}' description='{{ i18n "pages.xray.TemplateDesc"}}'></a-list-item-meta>
|
<a-list-item-meta title='{{ i18n "pages.xray.Template"}}' description='{{ i18n "pages.xray.TemplateDesc"}}'></a-list-item-meta>
|
||||||
<a-radio-group v-model="advSettings" @change="changeCode" button-style="solid" style="margin: 10px 0;" :size="isMobile ? 'small' : ''">
|
<a-radio-group v-model="advSettings" @change="changeCode" button-style="solid" style="margin: 10px 0;" :size="isMobile ? 'small' : ''">
|
||||||
|
@ -474,6 +517,7 @@
|
||||||
{{template "ruleModal"}}
|
{{template "ruleModal"}}
|
||||||
{{template "outModal"}}
|
{{template "outModal"}}
|
||||||
{{template "reverseModal"}}
|
{{template "reverseModal"}}
|
||||||
|
{{template "balancerModal"}}
|
||||||
{{template "warpModal"}}
|
{{template "warpModal"}}
|
||||||
<script>
|
<script>
|
||||||
const rulesColumns = [
|
const rulesColumns = [
|
||||||
|
@ -490,9 +534,10 @@
|
||||||
{ title: 'Domain', dataIndex: 'domain', align: 'center', width: 20, ellipsis: true },
|
{ title: 'Domain', dataIndex: 'domain', align: 'center', width: 20, ellipsis: true },
|
||||||
{ title: 'Port', dataIndex: 'port', align: 'center', width: 10, ellipsis: true }]},
|
{ title: 'Port', dataIndex: 'port', align: 'center', width: 10, ellipsis: true }]},
|
||||||
{ title: '{{ i18n "pages.xray.rules.inbound"}}', children: [
|
{ title: '{{ i18n "pages.xray.rules.inbound"}}', children: [
|
||||||
{ title: 'Inbound Tag', dataIndex: 'inboundTag', align: 'center', width: 20, ellipsis: true },
|
{ title: 'Inbound Tag', dataIndex: 'inboundTag', align: 'center', width: 15, ellipsis: true },
|
||||||
{ title: 'Client Email', dataIndex: 'user', align: 'center', width: 20, ellipsis: true }]},
|
{ title: 'Client Email', dataIndex: 'user', align: 'center', width: 20, ellipsis: true }]},
|
||||||
{ title: '{{ i18n "pages.xray.rules.outbound"}}', dataIndex: 'outboundTag', align: 'center', width: 20 },
|
{ title: '{{ i18n "pages.xray.rules.outbound"}}', dataIndex: 'outboundTag', align: 'center', width: 15 },
|
||||||
|
{ title: '{{ i18n "pages.xray.rules.balancer"}}', dataIndex: 'balancerTag', align: 'center', width: 15 },
|
||||||
];
|
];
|
||||||
|
|
||||||
const rulesMobileColumns = [
|
const rulesMobileColumns = [
|
||||||
|
@ -517,6 +562,13 @@
|
||||||
{ title: '{{ i18n "pages.xray.outbound.domain"}}', dataIndex: 'domain', align: 'center', width: 50 },
|
{ 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 app = new Vue({
|
const app = new Vue({
|
||||||
delimiters: ['[[', ']]'],
|
delimiters: ['[[', ']]'],
|
||||||
el: '#app',
|
el: '#app',
|
||||||
|
@ -895,6 +947,95 @@
|
||||||
this.refreshing = false;
|
this.refreshing = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
addBalancer() {
|
||||||
|
balancerModal.show({
|
||||||
|
title: '{{ i18n "pages.xray.balancer.addBalancer"}}',
|
||||||
|
okText: '{{ i18n "pages.xray.balancer.addBalancer"}}',
|
||||||
|
balancerTags: this.balancersData.filter((o) => !ObjectUtil.isEmpty(o.tag)).map(obj => obj.tag),
|
||||||
|
balancer: {
|
||||||
|
tag: '',
|
||||||
|
strategy: 'random',
|
||||||
|
selector: []
|
||||||
|
},
|
||||||
|
confirm: (balancer) => {
|
||||||
|
balancerModal.loading();
|
||||||
|
newTemplateSettings = this.templateSettings;
|
||||||
|
if (newTemplateSettings.routing.balancers == undefined) {
|
||||||
|
newTemplateSettings.routing.balancers = [];
|
||||||
|
}
|
||||||
|
let tmpBalancer = {
|
||||||
|
'tag': balancer.tag,
|
||||||
|
'selector': balancer.selector
|
||||||
|
};
|
||||||
|
if (balancer.strategy == 'roundRobin') {
|
||||||
|
tmpBalancer.strategy = {
|
||||||
|
'type': balancer.strategy
|
||||||
|
};
|
||||||
|
}
|
||||||
|
newTemplateSettings.routing.balancers.push(tmpBalancer);
|
||||||
|
this.templateSettings = newTemplateSettings;
|
||||||
|
balancerModal.close();
|
||||||
|
},
|
||||||
|
isEdit: false
|
||||||
|
});
|
||||||
|
},
|
||||||
|
editBalancer(index) {
|
||||||
|
const oldTag = this.balancersData[index].tag;
|
||||||
|
balancerModal.show({
|
||||||
|
title: '{{ i18n "pages.xray.balancer.editBalancer"}}',
|
||||||
|
okText: '{{ i18n "sure" }}',
|
||||||
|
balancerTags: this.balancersData.filter((o) => !ObjectUtil.isEmpty(o.tag)).map(obj => obj.tag),
|
||||||
|
balancer: this.balancersData[index],
|
||||||
|
confirm: (balancer) => {
|
||||||
|
balancerModal.loading();
|
||||||
|
newTemplateSettings = this.templateSettings;
|
||||||
|
|
||||||
|
let tmpBalancer = {
|
||||||
|
'tag': balancer.tag,
|
||||||
|
'selector': balancer.selector
|
||||||
|
};
|
||||||
|
if (balancer.strategy == 'roundRobin') {
|
||||||
|
tmpBalancer.strategy = {
|
||||||
|
'type': balancer.strategy
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
newTemplateSettings.routing.balancers[index] = tmpBalancer;
|
||||||
|
// change edited tag if used in rule section
|
||||||
|
if (oldTag != balancer.tag) {
|
||||||
|
newTemplateSettings.routing.rules.forEach((rule) => {
|
||||||
|
if (rule.balancerTag && rule.balancerTag == oldTag) {
|
||||||
|
rule.balancerTag = balancer.tag;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.templateSettings = newTemplateSettings;
|
||||||
|
balancerModal.close();
|
||||||
|
},
|
||||||
|
isEdit: true
|
||||||
|
});
|
||||||
|
},
|
||||||
|
deleteBalancer(index) {
|
||||||
|
newTemplateSettings = this.templateSettings;
|
||||||
|
|
||||||
|
//remove from balancers
|
||||||
|
const oldTag = this.balancersData[index].tag;
|
||||||
|
this.balancersData.splice(index, 1);
|
||||||
|
|
||||||
|
// remove from settings
|
||||||
|
let realIndex = newTemplateSettings.routing.balancers.findIndex((b) => b.tag == oldTag);
|
||||||
|
newTemplateSettings.routing.balancers.splice(realIndex, 1);
|
||||||
|
|
||||||
|
// remove related routing rules
|
||||||
|
let rules = [];
|
||||||
|
newTemplateSettings.routing.rules.forEach((r) => {
|
||||||
|
if (!r.balancerTag || r.balancerTag != oldTag) {
|
||||||
|
rules.push(r);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
newTemplateSettings.routing.rules = rules;
|
||||||
|
this.templateSettings = newTemplateSettings;
|
||||||
|
},
|
||||||
addReverse(){
|
addReverse(){
|
||||||
reverseModal.show({
|
reverseModal.show({
|
||||||
title: '{{ i18n "pages.xray.outbound.addReverse"}}',
|
title: '{{ i18n "pages.xray.outbound.addReverse"}}',
|
||||||
|
@ -1084,6 +1225,27 @@
|
||||||
return data;
|
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") {
|
||||||
|
strategy = o.strategy.type
|
||||||
|
}
|
||||||
|
|
||||||
|
data.push({
|
||||||
|
'key': index,
|
||||||
|
'tag': o.tag ? o.tag : "",
|
||||||
|
'strategy': strategy,
|
||||||
|
'selector': o.selector ? o.selector : []
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
},
|
||||||
routingRuleSettings: {
|
routingRuleSettings: {
|
||||||
get: function () { return this.templateSettings ? JSON.stringify(this.templateSettings.routing.rules, null, 2) : null; },
|
get: function () { return this.templateSettings ? JSON.stringify(this.templateSettings.routing.rules, null, 2) : null; },
|
||||||
set: function (newValue) {
|
set: function (newValue) {
|
||||||
|
|
111
web/html/xui/xray_balancer_modal.html
Normal file
111
web/html/xui/xray_balancer_modal.html
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
{{define "balancerModal"}}
|
||||||
|
<a-modal
|
||||||
|
id="balancer-modal"
|
||||||
|
v-model="balancerModal.visible"
|
||||||
|
:title="balancerModal.title"
|
||||||
|
@ok="balancerModal.ok"
|
||||||
|
:confirm-loading="balancerModal.confirmLoading"
|
||||||
|
:ok-button-props="{ props: { disabled: !balancerModal.isValid } }"
|
||||||
|
:closable="true"
|
||||||
|
:mask-closable="false"
|
||||||
|
:ok-text="balancerModal.okText"
|
||||||
|
cancel-text='{{ i18n "close" }}'
|
||||||
|
:class="themeSwitcher.currentTheme">
|
||||||
|
<a-form :colon="false" :label-col="{ md: {span:6} }" :wrapper-col="{ md: {span:14} }">
|
||||||
|
<a-form-item label='{{ i18n "pages.xray.balancer.tag" }}' has-feedback
|
||||||
|
:validate-status="balancerModal.duplicateTag? 'warning' : 'success'">
|
||||||
|
<a-input v-model.trim="balancerModal.balancer.tag" @change="balancerModal.check()"
|
||||||
|
placeholder='{{ i18n "pages.xray.balancer.tagDesc" }}'></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label='{{ i18n "pages.xray.balancer.balancerStrategy" }}'>
|
||||||
|
<a-select v-model="balancerModal.balancer.strategy" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
|
<a-select-option value="random">Random</a-select-option>
|
||||||
|
<a-select-option value="roundRobin">Round Robin</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label='{{ i18n "pages.xray.balancer.balancerSelectors" }}' has-feedback :validate-status="balancerModal.emptySelector? 'warning' : 'success'">
|
||||||
|
<a-select v-model="balancerModal.balancer.selector" mode="tags" @change="balancerModal.checkSelector()"
|
||||||
|
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
|
<a-select-option v-for="tag in balancerModal.outboundTags" :value="tag">[[ tag ]]</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</table>
|
||||||
|
</a-form>
|
||||||
|
</a-modal>
|
||||||
|
<script>
|
||||||
|
const balancerModal = {
|
||||||
|
title: '',
|
||||||
|
visible: false,
|
||||||
|
confirmLoading: false,
|
||||||
|
okText: '{{ i18n "sure" }}',
|
||||||
|
isEdit: false,
|
||||||
|
confirm: null,
|
||||||
|
duplicateTag: false,
|
||||||
|
emptySelector: false,
|
||||||
|
balancer: {
|
||||||
|
tag: '',
|
||||||
|
strategy: 'random',
|
||||||
|
selector: []
|
||||||
|
},
|
||||||
|
outboundTags: [],
|
||||||
|
balancerTags:[],
|
||||||
|
ok() {
|
||||||
|
if (balancerModal.balancer.selector.length == 0) {
|
||||||
|
balancerModal.emptySelector = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
balancerModal.emptySelector = false;
|
||||||
|
ObjectUtil.execute(balancerModal.confirm, balancerModal.balancer);
|
||||||
|
},
|
||||||
|
show({ title = '', okText = '{{ i18n "sure" }}', balancerTags = [], balancer, confirm = (balancer) => { }, isEdit = false }) {
|
||||||
|
this.title = title;
|
||||||
|
this.okText = okText;
|
||||||
|
this.confirm = confirm;
|
||||||
|
this.visible = true;
|
||||||
|
if (isEdit) {
|
||||||
|
balancerModal.balancer = balancer;
|
||||||
|
} else {
|
||||||
|
balancerModal.balancer = {
|
||||||
|
tag: '',
|
||||||
|
strategy: 'random',
|
||||||
|
selector: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
this.balancerTags = balancerTags.filter((tag) => tag != balancer.tag);
|
||||||
|
this.outboundTags = app.templateSettings.outbounds.filter((o) => !ObjectUtil.isEmpty(o.tag)).map(obj => obj.tag);
|
||||||
|
this.isEdit = isEdit;
|
||||||
|
this.check()
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
balancerModal.visible = false;
|
||||||
|
balancerModal.loading(false);
|
||||||
|
},
|
||||||
|
loading(loading) {
|
||||||
|
balancerModal.confirmLoading = loading;
|
||||||
|
},
|
||||||
|
check() {
|
||||||
|
if (balancerModal.balancer.tag == '' || balancerModal.balancerTags.includes(balancerModal.balancer.tag)) {
|
||||||
|
this.duplicateTag = true;
|
||||||
|
this.isValid = false;
|
||||||
|
} else {
|
||||||
|
this.duplicateTag = false;
|
||||||
|
this.isValid = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
checkSelector() {
|
||||||
|
balancerModal.emptySelector = balancerModal.balancer.selector.length == 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
new Vue({
|
||||||
|
delimiters: ['[[', ']]'],
|
||||||
|
el: '#balancer-modal',
|
||||||
|
data: {
|
||||||
|
balancerModal: balancerModal
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
{{end}}
|
|
@ -107,6 +107,19 @@
|
||||||
<a-select-option v-for="tag in ruleModal.outboundTags" :value="tag">[[ tag ]]</a-select-option>
|
<a-select-option v-for="tag in ruleModal.outboundTags" :value="tag">[[ tag ]]</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item>
|
||||||
|
<template slot="label">
|
||||||
|
<a-tooltip>
|
||||||
|
<template slot="title">
|
||||||
|
<span>{{ i18n "pages.xray.balancer.balancerDesc" }}</span>
|
||||||
|
</template>
|
||||||
|
Balancer Tag <a-icon type="question-circle"></a-icon>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<a-select v-model="ruleModal.rule.balancerTag" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
|
<a-select-option v-for="tag in ruleModal.balancerTags" :value="tag">[[ tag ]]</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
</table>
|
</table>
|
||||||
</a-form>
|
</a-form>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
|
@ -133,11 +146,12 @@
|
||||||
protocol: [],
|
protocol: [],
|
||||||
attrs: [],
|
attrs: [],
|
||||||
outboundTag: "",
|
outboundTag: "",
|
||||||
|
balancerTag: "",
|
||||||
},
|
},
|
||||||
inboundTags: [],
|
inboundTags: [],
|
||||||
outboundTags: [],
|
outboundTags: [],
|
||||||
users: [],
|
users: [],
|
||||||
balancerTag: [],
|
balancerTags: [],
|
||||||
ok() {
|
ok() {
|
||||||
newRule = ruleModal.getResult();
|
newRule = ruleModal.getResult();
|
||||||
ObjectUtil.execute(ruleModal.confirm, newRule);
|
ObjectUtil.execute(ruleModal.confirm, newRule);
|
||||||
|
@ -160,6 +174,7 @@
|
||||||
this.rule.protocol = rule.protocol;
|
this.rule.protocol = rule.protocol;
|
||||||
this.rule.attrs = rule.attrs ? Object.entries(rule.attrs) : [];
|
this.rule.attrs = rule.attrs ? Object.entries(rule.attrs) : [];
|
||||||
this.rule.outboundTag = rule.outboundTag;
|
this.rule.outboundTag = rule.outboundTag;
|
||||||
|
this.rule.balancerTag = rule.balancerTag ? rule.balancerTag : ""
|
||||||
} else {
|
} else {
|
||||||
this.rule = {
|
this.rule = {
|
||||||
domainMatcher: "",
|
domainMatcher: "",
|
||||||
|
@ -174,6 +189,7 @@
|
||||||
protocol: [],
|
protocol: [],
|
||||||
attrs: [],
|
attrs: [],
|
||||||
outboundTag: "",
|
outboundTag: "",
|
||||||
|
balancerTag: "",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.isEdit = isEdit;
|
this.isEdit = isEdit;
|
||||||
|
@ -186,6 +202,10 @@
|
||||||
}
|
}
|
||||||
if(app.templateSettings.reverse.portals) this.outboundTags.push(...app.templateSettings.reverse.portals.map(b => b.tag));
|
if(app.templateSettings.reverse.portals) this.outboundTags.push(...app.templateSettings.reverse.portals.map(b => b.tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (app.templateSettings.routing && app.templateSettings.routing.balancers) {
|
||||||
|
this.balancerTags = app.templateSettings.routing.balancers.filter((o) => !ObjectUtil.isEmpty(o.tag)).map(obj => obj.tag)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
close() {
|
close() {
|
||||||
ruleModal.visible = false;
|
ruleModal.visible = false;
|
||||||
|
@ -211,6 +231,7 @@
|
||||||
rule.protocol = value.protocol;
|
rule.protocol = value.protocol;
|
||||||
rule.attrs = Object.fromEntries(value.attrs);
|
rule.attrs = Object.fromEntries(value.attrs);
|
||||||
rule.outboundTag = value.outboundTag;
|
rule.outboundTag = value.outboundTag;
|
||||||
|
rule.balancerTag = value.balancerTag;
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(rule)) {
|
for (const [key, value] of Object.entries(rule)) {
|
||||||
if (
|
if (
|
||||||
|
|
|
@ -88,7 +88,7 @@ func (j *CheckClientIpJob) checkFail2BanInstalled() {
|
||||||
|
|
||||||
err := exec.Command(cmd, args...).Run()
|
err := exec.Command(cmd, args...).Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Warning("fail2ban is not installed. IP limiting may not work properly.")
|
logger.Error("fail2ban is not installed. IP limiting may not work properly.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,12 +96,12 @@ func (j *CheckClientIpJob) processLogFile() {
|
||||||
accessLogPath := xray.GetAccessLogPath()
|
accessLogPath := xray.GetAccessLogPath()
|
||||||
|
|
||||||
if accessLogPath == "none" {
|
if accessLogPath == "none" {
|
||||||
logger.Warning("Access log is set to 'none' check your Xray Configs")
|
logger.Error("Access log is set to 'none' check your Xray Configs")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if accessLogPath == "" {
|
if accessLogPath == "" {
|
||||||
logger.Warning("Access log doesn't exist in your Xray Configs")
|
logger.Error("Access log doesn't exist in your Xray Configs")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -390,6 +390,7 @@
|
||||||
"Inbounds" = "Inbounds"
|
"Inbounds" = "Inbounds"
|
||||||
"InboundsDesc" = "Accepting the specific clients."
|
"InboundsDesc" = "Accepting the specific clients."
|
||||||
"Outbounds" = "Outbounds"
|
"Outbounds" = "Outbounds"
|
||||||
|
"Balancers" = "Balancers"
|
||||||
"OutboundsDesc" = "Set the outgoing traffic pathway."
|
"OutboundsDesc" = "Set the outgoing traffic pathway."
|
||||||
"Routings" = "Routing Rules"
|
"Routings" = "Routing Rules"
|
||||||
"RoutingsDesc" = "The priority of each rule is important!"
|
"RoutingsDesc" = "The priority of each rule is important!"
|
||||||
|
@ -408,6 +409,7 @@
|
||||||
"dest" = "Destination"
|
"dest" = "Destination"
|
||||||
"inbound" = "Inbound"
|
"inbound" = "Inbound"
|
||||||
"outbound" = "Outbound"
|
"outbound" = "Outbound"
|
||||||
|
"balancer" = "Balancer"
|
||||||
"info" = "Info"
|
"info" = "Info"
|
||||||
"add" = "Add Rule"
|
"add" = "Add Rule"
|
||||||
"edit" = "Edit Rule"
|
"edit" = "Edit Rule"
|
||||||
|
@ -428,6 +430,15 @@
|
||||||
"portal" = "Portal"
|
"portal" = "Portal"
|
||||||
"intercon" = "Interconnection"
|
"intercon" = "Interconnection"
|
||||||
|
|
||||||
|
[pages.xray.balancer]
|
||||||
|
"addBalancer" = "Add Balancer"
|
||||||
|
"editBalancer" = "Edit Balancer"
|
||||||
|
"balancerStrategy" = "Strategy"
|
||||||
|
"balancerSelectors" = "Selectors"
|
||||||
|
"tag" = "Tag"
|
||||||
|
"tagDesc" = "Unique Tag"
|
||||||
|
"balancerDesc" = "It is not possible to use balancerTag and outboundTag at the same time. If used at the same time, only outboundTag will work."
|
||||||
|
|
||||||
[pages.xray.wireguard]
|
[pages.xray.wireguard]
|
||||||
"secretKey" = "Secret Key"
|
"secretKey" = "Secret Key"
|
||||||
"publicKey" = "Public Key"
|
"publicKey" = "Public Key"
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
"check" = "Verificar"
|
"check" = "Verificar"
|
||||||
"indefinite" = "Indefinido"
|
"indefinite" = "Indefinido"
|
||||||
"unlimited" = "Ilimitado"
|
"unlimited" = "Ilimitado"
|
||||||
"none" = "Ninguno"
|
"none" = "None"
|
||||||
"qrCode" = "Código QR"
|
"qrCode" = "Código QR"
|
||||||
"info" = "Más Información"
|
"info" = "Más Información"
|
||||||
"edit" = "Editar"
|
"edit" = "Editar"
|
||||||
|
@ -390,6 +390,7 @@
|
||||||
"Inbounds" = "Entrante"
|
"Inbounds" = "Entrante"
|
||||||
"InboundsDesc" = "Cambia la plantilla de configuración para aceptar clientes específicos."
|
"InboundsDesc" = "Cambia la plantilla de configuración para aceptar clientes específicos."
|
||||||
"Outbounds" = "Salidas"
|
"Outbounds" = "Salidas"
|
||||||
|
"Balancers" = "Equilibradores"
|
||||||
"OutboundsDesc" = "Cambia la plantilla de configuración para definir formas de salida para este servidor."
|
"OutboundsDesc" = "Cambia la plantilla de configuración para definir formas de salida para este servidor."
|
||||||
"Routings" = "Reglas de enrutamiento"
|
"Routings" = "Reglas de enrutamiento"
|
||||||
"RoutingsDesc" = "¡La prioridad de cada regla es importante!"
|
"RoutingsDesc" = "¡La prioridad de cada regla es importante!"
|
||||||
|
@ -408,6 +409,7 @@
|
||||||
"dest" = "Destino"
|
"dest" = "Destino"
|
||||||
"inbound" = "Entrante"
|
"inbound" = "Entrante"
|
||||||
"outbound" = "saliente"
|
"outbound" = "saliente"
|
||||||
|
"balancer" = "Balancín"
|
||||||
"info" = "Información"
|
"info" = "Información"
|
||||||
"add" = "Agregar regla"
|
"add" = "Agregar regla"
|
||||||
"edit" = "Editar regla"
|
"edit" = "Editar regla"
|
||||||
|
@ -428,6 +430,15 @@
|
||||||
"portal" = "portal"
|
"portal" = "portal"
|
||||||
"intercon" = "Interconexión"
|
"intercon" = "Interconexión"
|
||||||
|
|
||||||
|
[pages.xray.balancer]
|
||||||
|
"addBalancer" = "Agregar equilibrador"
|
||||||
|
"editBalancer" = "Editar balanceador"
|
||||||
|
"balancerStrategy" = "Estrategia"
|
||||||
|
"balancerSelectors" = "Selectores"
|
||||||
|
"tag" = "Etiqueta"
|
||||||
|
"tagDesc" = "etiqueta única"
|
||||||
|
"balancerDesc" = "No es posible utilizar balancerTag y outboundTag al mismo tiempo. Si se utilizan al mismo tiempo, sólo funcionará outboundTag."
|
||||||
|
|
||||||
[pages.xray.wireguard]
|
[pages.xray.wireguard]
|
||||||
"secretKey" = "Llave secreta"
|
"secretKey" = "Llave secreta"
|
||||||
"publicKey" = "Llave pública"
|
"publicKey" = "Llave pública"
|
||||||
|
|
|
@ -390,6 +390,7 @@
|
||||||
"Inbounds" = "ورودیها"
|
"Inbounds" = "ورودیها"
|
||||||
"InboundsDesc" = "پذیرش کلاینت خاص"
|
"InboundsDesc" = "پذیرش کلاینت خاص"
|
||||||
"Outbounds" = "خروجیها"
|
"Outbounds" = "خروجیها"
|
||||||
|
"Balancers" = "بالانسرها"
|
||||||
"OutboundsDesc" = "مسیر ترافیک خروجی را تنظیم کنید"
|
"OutboundsDesc" = "مسیر ترافیک خروجی را تنظیم کنید"
|
||||||
"Routings" = "قوانین مسیریابی"
|
"Routings" = "قوانین مسیریابی"
|
||||||
"RoutingsDesc" = "اولویت هر قانون مهم است"
|
"RoutingsDesc" = "اولویت هر قانون مهم است"
|
||||||
|
@ -408,6 +409,7 @@
|
||||||
"dest" = "مقصد"
|
"dest" = "مقصد"
|
||||||
"inbound" = "ورودی"
|
"inbound" = "ورودی"
|
||||||
"outbound" = "خروجی"
|
"outbound" = "خروجی"
|
||||||
|
"balancer" = "بالانسر"
|
||||||
"info" = "اطلاعات"
|
"info" = "اطلاعات"
|
||||||
"add" = "افزودن قانون"
|
"add" = "افزودن قانون"
|
||||||
"edit" = "ویرایش قانون"
|
"edit" = "ویرایش قانون"
|
||||||
|
@ -428,6 +430,15 @@
|
||||||
"portal" = "پورتال"
|
"portal" = "پورتال"
|
||||||
"intercon" = "اتصال میانی"
|
"intercon" = "اتصال میانی"
|
||||||
|
|
||||||
|
[pages.xray.balancer]
|
||||||
|
"addBalancer" = "افزودن بالانسر"
|
||||||
|
"editBalancer" = "ویرایش بالانسر"
|
||||||
|
"balancerStrategy" = "استراتژی"
|
||||||
|
"balancerSelectors" = "انتخابگرها"
|
||||||
|
"tag" = "برچسب"
|
||||||
|
"tagDesc" = "برچسب یگانه"
|
||||||
|
"balancerDesc" = "امکان استفاده همزمان balancerTag و outboundTag باهم وجود ندارد. درصورت استفاده همزمان فقط outboundTag عمل خواهد کرد."
|
||||||
|
|
||||||
[pages.xray.wireguard]
|
[pages.xray.wireguard]
|
||||||
"secretKey" = "کلید شخصی"
|
"secretKey" = "کلید شخصی"
|
||||||
"publicKey" = "کلید عمومی"
|
"publicKey" = "کلید عمومی"
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
"check" = "Centang"
|
"check" = "Centang"
|
||||||
"indefinite" = "Tak Terbatas"
|
"indefinite" = "Tak Terbatas"
|
||||||
"unlimited" = "Tanpa Batas"
|
"unlimited" = "Tanpa Batas"
|
||||||
"none" = "Tidak Ada"
|
"none" = "None"
|
||||||
"qrCode" = "Kode QR"
|
"qrCode" = "Kode QR"
|
||||||
"info" = "Informasi Lebih Lanjut"
|
"info" = "Informasi Lebih Lanjut"
|
||||||
"edit" = "Edit"
|
"edit" = "Edit"
|
||||||
|
@ -390,6 +390,7 @@
|
||||||
"Inbounds" = "Masuk"
|
"Inbounds" = "Masuk"
|
||||||
"InboundsDesc" = "Menerima klien tertentu."
|
"InboundsDesc" = "Menerima klien tertentu."
|
||||||
"Outbounds" = "Keluar"
|
"Outbounds" = "Keluar"
|
||||||
|
"Balancers" = "Penyeimbang"
|
||||||
"OutboundsDesc" = "Atur jalur lalu lintas keluar."
|
"OutboundsDesc" = "Atur jalur lalu lintas keluar."
|
||||||
"Routings" = "Aturan Pengalihan"
|
"Routings" = "Aturan Pengalihan"
|
||||||
"RoutingsDesc" = "Prioritas setiap aturan penting!"
|
"RoutingsDesc" = "Prioritas setiap aturan penting!"
|
||||||
|
@ -408,6 +409,7 @@
|
||||||
"dest" = "Tujuan"
|
"dest" = "Tujuan"
|
||||||
"inbound" = "Masuk"
|
"inbound" = "Masuk"
|
||||||
"outbound" = "Keluar"
|
"outbound" = "Keluar"
|
||||||
|
"balancer" = "Pengimbang"
|
||||||
"info" = "Info"
|
"info" = "Info"
|
||||||
"add" = "Tambahkan Aturan"
|
"add" = "Tambahkan Aturan"
|
||||||
"edit" = "Edit Aturan"
|
"edit" = "Edit Aturan"
|
||||||
|
@ -428,6 +430,15 @@
|
||||||
"portal" = "Portal"
|
"portal" = "Portal"
|
||||||
"intercon" = "Interkoneksi"
|
"intercon" = "Interkoneksi"
|
||||||
|
|
||||||
|
[pages.xray.balancer]
|
||||||
|
"addBalancer" = "Tambahkan Penyeimbang"
|
||||||
|
"editBalancer" = "Sunting Penyeimbang"
|
||||||
|
"balancerStrategy" = "Strategi"
|
||||||
|
"balancerSelectors" = "Penyeleksi"
|
||||||
|
"tag" = "Menandai"
|
||||||
|
"tagDesc" = "Label Unik"
|
||||||
|
"balancerDesc" = "BalancerTag dan outboundTag tidak dapat digunakan secara bersamaan. Jika digunakan secara bersamaan, hanya outboundTag yang akan berfungsi."
|
||||||
|
|
||||||
[pages.xray.wireguard]
|
[pages.xray.wireguard]
|
||||||
"secretKey" = "Kunci Rahasia"
|
"secretKey" = "Kunci Rahasia"
|
||||||
"publicKey" = "Kunci Publik"
|
"publicKey" = "Kunci Publik"
|
||||||
|
|
|
@ -390,6 +390,7 @@
|
||||||
"Inbounds" = "Входящие"
|
"Inbounds" = "Входящие"
|
||||||
"InboundsDesc" = "Изменение шаблона конфигурации для подключения определенных пользователей"
|
"InboundsDesc" = "Изменение шаблона конфигурации для подключения определенных пользователей"
|
||||||
"Outbounds" = "Исходящие"
|
"Outbounds" = "Исходящие"
|
||||||
|
"Balancers" = "Балансиры"
|
||||||
"OutboundsDesc" = "Изменение шаблона конфигурации, чтобы определить исходящие пути для этого сервера"
|
"OutboundsDesc" = "Изменение шаблона конфигурации, чтобы определить исходящие пути для этого сервера"
|
||||||
"Routings" = "Правила маршрутизации"
|
"Routings" = "Правила маршрутизации"
|
||||||
"RoutingsDesc" = "Важен приоритет каждого правила!"
|
"RoutingsDesc" = "Важен приоритет каждого правила!"
|
||||||
|
@ -408,6 +409,7 @@
|
||||||
"dest" = "Пункт назначения"
|
"dest" = "Пункт назначения"
|
||||||
"inbound" = "Входящий"
|
"inbound" = "Входящий"
|
||||||
"outbound" = "Исходящий"
|
"outbound" = "Исходящий"
|
||||||
|
"balancer" = "балансир"
|
||||||
"info" = "Информация"
|
"info" = "Информация"
|
||||||
"add" = "Добавить правило"
|
"add" = "Добавить правило"
|
||||||
"edit" = "Редактировать правило"
|
"edit" = "Редактировать правило"
|
||||||
|
@ -428,6 +430,15 @@
|
||||||
"portal" = "Портал"
|
"portal" = "Портал"
|
||||||
"intercon" = "Соединение"
|
"intercon" = "Соединение"
|
||||||
|
|
||||||
|
[pages.xray.balancer]
|
||||||
|
"addBalancer" = "Добавить балансир"
|
||||||
|
"editBalancer" = "Редактировать балансир"
|
||||||
|
"balancerStrategy" = "Стратегия"
|
||||||
|
"balancerSelectors" = "Селекторы"
|
||||||
|
"tag" = "Тег"
|
||||||
|
"tagDesc" = "уникальный тег"
|
||||||
|
"balancerDesc" = "Невозможно одновременно использовать balancerTag и outboundTag. При одновременном использовании будет работать только outboundTag."
|
||||||
|
|
||||||
[pages.xray.wireguard]
|
[pages.xray.wireguard]
|
||||||
"secretKey" = "Секретный ключ"
|
"secretKey" = "Секретный ключ"
|
||||||
"publicKey" = "Открытый ключ"
|
"publicKey" = "Открытый ключ"
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
"check" = "Kiểm tra"
|
"check" = "Kiểm tra"
|
||||||
"indefinite" = "Không xác định"
|
"indefinite" = "Không xác định"
|
||||||
"unlimited" = "Không giới hạn"
|
"unlimited" = "Không giới hạn"
|
||||||
"none" = "Không có"
|
"none" = "None"
|
||||||
"qrCode" = "Mã QR"
|
"qrCode" = "Mã QR"
|
||||||
"info" = "Thông tin thêm"
|
"info" = "Thông tin thêm"
|
||||||
"edit" = "Chỉnh sửa"
|
"edit" = "Chỉnh sửa"
|
||||||
|
@ -390,6 +390,7 @@
|
||||||
"Inbounds" = "Đầu vào"
|
"Inbounds" = "Đầu vào"
|
||||||
"InboundsDesc" = "Thay đổi mẫu cấu hình để chấp nhận các máy khách cụ thể."
|
"InboundsDesc" = "Thay đổi mẫu cấu hình để chấp nhận các máy khách cụ thể."
|
||||||
"Outbounds" = "Đầu ra"
|
"Outbounds" = "Đầu ra"
|
||||||
|
"Balancers" = "Cân bằng"
|
||||||
"OutboundsDesc" = "Thay đổi mẫu cấu hình để xác định các cách ra đi cho máy chủ này."
|
"OutboundsDesc" = "Thay đổi mẫu cấu hình để xác định các cách ra đi cho máy chủ này."
|
||||||
"Routings" = "Quy tắc định tuyến"
|
"Routings" = "Quy tắc định tuyến"
|
||||||
"RoutingsDesc" = "Mức độ ưu tiên của mỗi quy tắc đều quan trọng!"
|
"RoutingsDesc" = "Mức độ ưu tiên của mỗi quy tắc đều quan trọng!"
|
||||||
|
@ -408,6 +409,7 @@
|
||||||
"dest" = "Đích"
|
"dest" = "Đích"
|
||||||
"inbound" = "Vào"
|
"inbound" = "Vào"
|
||||||
"outbound" = "Ra"
|
"outbound" = "Ra"
|
||||||
|
"balancer" = "Cân bằng"
|
||||||
"info" = "Thông tin"
|
"info" = "Thông tin"
|
||||||
"add" = "Thêm quy tắc"
|
"add" = "Thêm quy tắc"
|
||||||
"edit" = "Chỉnh sửa quy tắc"
|
"edit" = "Chỉnh sửa quy tắc"
|
||||||
|
@ -428,6 +430,15 @@
|
||||||
"portal" = "Cổng thông tin"
|
"portal" = "Cổng thông tin"
|
||||||
"intercon" = "Kết nối"
|
"intercon" = "Kết nối"
|
||||||
|
|
||||||
|
[pages.xray.balancer]
|
||||||
|
"addBalancer" = "Thêm cân bằng"
|
||||||
|
"editBalancer" = "Chỉnh sửa cân bằng"
|
||||||
|
"balancerStrategy" = "Chiến lược"
|
||||||
|
"balancerSelectors" = "Bộ chọn"
|
||||||
|
"tag" = "Thẻ"
|
||||||
|
"tagDesc" = "thẻ duy nhất"
|
||||||
|
"balancerDesc" = "Không thể sử dụng balancerTag và outboundTag cùng một lúc. Nếu sử dụng cùng lúc thì chỉ outboundTag mới hoạt động."
|
||||||
|
|
||||||
[pages.xray.wireguard]
|
[pages.xray.wireguard]
|
||||||
"secretKey" = "Khoá bí mật"
|
"secretKey" = "Khoá bí mật"
|
||||||
"publicKey" = "Khóa công khai"
|
"publicKey" = "Khóa công khai"
|
||||||
|
|
|
@ -390,6 +390,7 @@
|
||||||
"Inbounds" = "入站"
|
"Inbounds" = "入站"
|
||||||
"InboundsDesc" = "更改配置模板接受特殊客户端"
|
"InboundsDesc" = "更改配置模板接受特殊客户端"
|
||||||
"Outbounds" = "出站"
|
"Outbounds" = "出站"
|
||||||
|
"Balancers" = "平衡器"
|
||||||
"OutboundsDesc" = "更改配置模板定义此服务器的传出方式"
|
"OutboundsDesc" = "更改配置模板定义此服务器的传出方式"
|
||||||
"Routings" = "路由规则"
|
"Routings" = "路由规则"
|
||||||
"RoutingsDesc" = "每条规则的优先级都很重要"
|
"RoutingsDesc" = "每条规则的优先级都很重要"
|
||||||
|
@ -408,6 +409,7 @@
|
||||||
"dest" = "目的地"
|
"dest" = "目的地"
|
||||||
"inbound" = "入站"
|
"inbound" = "入站"
|
||||||
"outbound" = "出站"
|
"outbound" = "出站"
|
||||||
|
"balancer" = "平衡器"
|
||||||
"info" = "信息"
|
"info" = "信息"
|
||||||
"add" = "添加规则"
|
"add" = "添加规则"
|
||||||
"edit" = "编辑规则"
|
"edit" = "编辑规则"
|
||||||
|
@ -428,6 +430,15 @@
|
||||||
"portal" = "门户"
|
"portal" = "门户"
|
||||||
"intercon" = "互连"
|
"intercon" = "互连"
|
||||||
|
|
||||||
|
[pages.xray.balancer]
|
||||||
|
"addBalancer" = "添加平衡器"
|
||||||
|
"editBalancer" = "编辑平衡器"
|
||||||
|
"balancerStrategy" = "战略"
|
||||||
|
"balancerSelectors" = "选择器"
|
||||||
|
"tag" = "标签"
|
||||||
|
"tagDesc" = "唯一标记"
|
||||||
|
"balancerDesc" = "不能同时使用balancerTag和outboundTag。 如果同时使用,则只有outboundTag起作用。"
|
||||||
|
|
||||||
[pages.xray.wireguard]
|
[pages.xray.wireguard]
|
||||||
"secretKey" = "密钥"
|
"secretKey" = "密钥"
|
||||||
"publicKey" = "公钥"
|
"publicKey" = "公钥"
|
||||||
|
|
Loading…
Reference in a new issue