mirror of
https://github.com/alireza0/x-ui.git
synced 2026-03-14 05:23:09 +00:00
General exhaustion alert #100
This commit is contained in:
@@ -170,13 +170,13 @@ class AllSetting {
|
||||
this.webCertFile = "";
|
||||
this.webKeyFile = "";
|
||||
this.webBasePath = "/";
|
||||
this.expireDiff = "";
|
||||
this.trafficDiff = "";
|
||||
this.tgBotEnable = false;
|
||||
this.tgBotToken = "";
|
||||
this.tgBotChatId = "";
|
||||
this.tgRunTime = "@daily";
|
||||
this.tgBotBackup = false;
|
||||
this.tgExpireDiff = "";
|
||||
this.tgTrafficDiff = "";
|
||||
this.tgCpu = "";
|
||||
this.xrayTemplateConfig = "";
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ func (a *SettingController) initRouter(g *gin.RouterGroup) {
|
||||
g = g.Group("/setting")
|
||||
|
||||
g.POST("/all", a.getAllSetting)
|
||||
g.POST("/thresholds", a.getThresholds)
|
||||
g.POST("/update", a.updateSetting)
|
||||
g.POST("/updateUser", a.updateUser)
|
||||
g.POST("/restartPanel", a.restartPanel)
|
||||
@@ -47,6 +48,24 @@ func (a *SettingController) getAllSetting(c *gin.Context) {
|
||||
jsonObj(c, allSetting, nil)
|
||||
}
|
||||
|
||||
func (a *SettingController) getThresholds(c *gin.Context) {
|
||||
expireDiff, err := a.settingService.GetExpireDiff()
|
||||
if err != nil {
|
||||
jsonMsg(c, I18n(c, "pages.setting.toasts.getSetting"), err)
|
||||
return
|
||||
}
|
||||
trafficDiff, err := a.settingService.GetTrafficDiff()
|
||||
if err != nil {
|
||||
jsonMsg(c, I18n(c, "pages.setting.toasts.getSetting"), err)
|
||||
return
|
||||
}
|
||||
result := map[string]interface{}{
|
||||
"expireDiff": expireDiff,
|
||||
"trafficDiff": trafficDiff,
|
||||
}
|
||||
jsonObj(c, result, nil)
|
||||
}
|
||||
|
||||
func (a *SettingController) updateSetting(c *gin.Context) {
|
||||
allSetting := &entity.AllSetting{}
|
||||
err := c.ShouldBind(allSetting)
|
||||
|
||||
@@ -32,13 +32,13 @@ type AllSetting struct {
|
||||
WebCertFile string `json:"webCertFile" form:"webCertFile"`
|
||||
WebKeyFile string `json:"webKeyFile" form:"webKeyFile"`
|
||||
WebBasePath string `json:"webBasePath" form:"webBasePath"`
|
||||
ExpireDiff int `json:"expireDiff" form:"expireDiff"`
|
||||
TrafficDiff int `json:"trafficDiff" form:"trafficDiff"`
|
||||
TgBotEnable bool `json:"tgBotEnable" form:"tgBotEnable"`
|
||||
TgBotToken string `json:"tgBotToken" form:"tgBotToken"`
|
||||
TgBotChatId string `json:"tgBotChatId" form:"tgBotChatId"`
|
||||
TgRunTime string `json:"tgRunTime" form:"tgRunTime"`
|
||||
TgBotBackup bool `json:"tgBotBackup" form:"tgBotBackup"`
|
||||
TgExpireDiff int `json:"tgExpireDiff" form:"tgExpireDiff"`
|
||||
TgTrafficDiff int `json:"tgTrafficDiff" form:"tgTrafficDiff"`
|
||||
TgCpu int `json:"tgCpu" form:"tgCpu"`
|
||||
XrayTemplateConfig string `json:"xrayTemplateConfig" form:"xrayTemplateConfig"`
|
||||
TimeLocation string `json:"timeLocation" form:"timeLocation"`
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<a-form-item label="Subscription" v-if="client.email">
|
||||
<a-input v-model.trim="client.subId"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="Telegram ID" v-if="client.email">
|
||||
<a-form-item label="Telegram Username" v-if="client.email">
|
||||
<a-input v-model.trim="client.tgId"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="inbound.xtls" label="flow">
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
</template>
|
||||
<template slot="client" slot-scope="text, client">
|
||||
[[ client.email ]]
|
||||
<a-tag v-if="!isClientEnabled(record, client.email)" color="red">{{ i18n "disabled" }}</a-tag>
|
||||
<a-tag v-if="!isClientEnabled(record, client.email)" color="red">{{ i18n "depleted" }}</a-tag>
|
||||
</template>
|
||||
<template slot="traffic" slot-scope="text, client">
|
||||
<a-tag color="blue">[[ sizeFormat(getUpStats(record, client.email)) ]] / [[ sizeFormat(getDownStats(record, client.email)) ]]</a-tag>
|
||||
|
||||
@@ -63,9 +63,21 @@
|
||||
<tr v-for="col,index in Object.keys(infoModal.clientSettings).slice(0, 3)">
|
||||
<td>[[ col ]]</td>
|
||||
<td><a-tag color="green">[[ infoModal.clientSettings[col] ]]</a-tag></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ i18n "status" }}</td>
|
||||
<td>
|
||||
<a-tag v-if="isEnable" color="blue">{{ i18n "enabled" }}</a-tag>
|
||||
<a-tag v-else color="red">{{ i18n "disabled" }}</a-tag>
|
||||
<a-tag v-if="!isActive" color="red">{{ i18n "depleted" }}</a-tag>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table style="margin-bottom: 10px; width: 100%;">
|
||||
<tr><th>{{ i18n "usage" }}</th><th>{{ i18n "pages.inbounds.totalFlow" }}</th><th>{{ i18n "pages.inbounds.expireDate" }}</th><th>{{ i18n "enable" }}</th></tr>
|
||||
<tr>
|
||||
<th>{{ i18n "usage" }}</th>
|
||||
<th>{{ i18n "pages.inbounds.totalFlow" }}</th>
|
||||
<th>{{ i18n "pages.inbounds.expireDate" }}</th>
|
||||
<tr>
|
||||
<td>
|
||||
<a-tag v-if="infoModal.clientStats" :color="statsColor(infoModal.clientStats)">
|
||||
@@ -86,10 +98,16 @@
|
||||
</template>
|
||||
<a-tag v-else color="green">{{ i18n "indefinite" }}</a-tag>
|
||||
</td>
|
||||
<td>
|
||||
<a-tag v-if="isEnable" color="blue">{{ i18n "enabled" }}</a-tag>
|
||||
<a-tag v-else color="red">{{ i18n "disabled" }}</a-tag>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table v-if="infoModal.clientSettings.subId + infoModal.clientSettings.tgId" style="margin-bottom: 10px;">
|
||||
<tr v-if="infoModal.clientSettings.subId">
|
||||
<td>Subscription link</td>
|
||||
<td><a :href="[[ infoModal.subBase + infoModal.clientSettings.subId ]]" target="_blank">[[ infoModal.subBase + infoModal.clientSettings.subId ]]</a></td>
|
||||
</tr>
|
||||
<tr v-if="infoModal.clientSettings.tgId">
|
||||
<td>Telegram Username</td>
|
||||
<td><a :href="[[ infoModal.tgBase + infoModal.clientSettings.tgId ]]" target="_blank">@[[ infoModal.clientSettings.tgId ]]</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</template>
|
||||
@@ -160,7 +178,6 @@
|
||||
</div>
|
||||
</a-modal>
|
||||
<script>
|
||||
|
||||
const infoModal = {
|
||||
visible: false,
|
||||
inbound: new Inbound(),
|
||||
@@ -174,6 +191,8 @@
|
||||
link: null,
|
||||
index: null,
|
||||
isExpired: false,
|
||||
subBase: window.location.protocol + "//" + window.location.hostname + "/sub/",
|
||||
tgBase: "https://t.me/",
|
||||
show(dbInbound, index) {
|
||||
this.index = index;
|
||||
this.inbound = dbInbound.toInbound();
|
||||
@@ -209,12 +228,19 @@
|
||||
get inbound() {
|
||||
return this.infoModal.inbound;
|
||||
},
|
||||
get isEnable() {
|
||||
get isActive() {
|
||||
if(infoModal.clientStats){
|
||||
return infoModal.clientStats.enable;
|
||||
}
|
||||
return infoModal.dbInbound.isEnable;
|
||||
},
|
||||
get isEnable() {
|
||||
if(infoModal.clientSettings){
|
||||
return infoModal.clientSettings.enable;
|
||||
}
|
||||
return infoModal.dbInbound.isEnable;
|
||||
}
|
||||
|
||||
},
|
||||
methods: {
|
||||
copyTextToClipboard(elmentId,content) {
|
||||
|
||||
@@ -41,8 +41,24 @@
|
||||
<a-col :xs="24" :sm="24" :lg="12">
|
||||
{{ i18n "clients" }}:
|
||||
<a-tag color="green">[[ total.clients ]]</a-tag>
|
||||
<a-tag color="blue">{{ i18n "enabled" }} [[ total.active ]]</a-tag>
|
||||
<a-tag color="red">{{ i18n "disabled" }} [[ total.deactive ]]</a-tag>
|
||||
<a-popover title="{{ i18n "disabled" }}" :overlay-class-name="siderDrawer.isDarkTheme ? 'ant-dark' : ''">
|
||||
<template slot="content">
|
||||
<p v-for="clientEmail in total.deactive">[[ clientEmail ]]</p>
|
||||
</template>
|
||||
<a-tag v-if="total.deactive.length">[[ total.deactive.length ]]</a-tag>
|
||||
</a-popover>
|
||||
<a-popover title="{{ i18n "depleted" }}" :overlay-class-name="siderDrawer.isDarkTheme ? 'ant-dark' : ''">
|
||||
<template slot="content">
|
||||
<p v-for="clientEmail in total.depleted">[[ clientEmail ]]</p>
|
||||
</template>
|
||||
<a-tag color="red" v-if="total.depleted.length">[[ total.depleted.length ]]</a-tag>
|
||||
</a-popover>
|
||||
<a-popover title="{{ i18n "depletingSoon" }}" :overlay-class-name="siderDrawer.isDarkTheme ? 'ant-dark' : ''">
|
||||
<template slot="content">
|
||||
<p v-for="clientEmail in total.expiring">[[ clientEmail ]]</p>
|
||||
</template>
|
||||
<a-tag color="orange" v-if="total.expiring.length">[[ total.expiring.length ]]</a-tag>
|
||||
</a-popover>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-card>
|
||||
@@ -63,7 +79,7 @@
|
||||
<template slot="action" slot-scope="text, dbInbound">
|
||||
<a-dropdown :trigger="['click']">
|
||||
<a-icon @click="e => e.preventDefault()" type="menu"></a-icon>
|
||||
<a-menu slot="overlay" @click="a => clickAction(a, dbInbound)" :theme="siderDrawer.theme" style="border: 1px solid rgba(255, 255, 255, 0.65);">
|
||||
<a-menu slot="overlay" @click="a => clickAction(a, dbInbound)" :theme="siderDrawer.theme">
|
||||
<a-menu-item v-if="dbInbound.isSS" key="qrcode">
|
||||
<a-icon type="qrcode"></a-icon>
|
||||
{{ i18n "qrCode" }}
|
||||
@@ -104,7 +120,35 @@
|
||||
</a-dropdown>
|
||||
</template>
|
||||
<template slot="protocol" slot-scope="text, dbInbound">
|
||||
<a-tag color="blue">[[ dbInbound.protocol ]]</a-tag>
|
||||
<a-tag style="margin:0;" color="blue">[[ dbInbound.protocol ]]</a-tag>
|
||||
<template v-if="dbInbound.isVMess || dbInbound.isVLess || dbInbound.isTrojan || dbInbound.isSS">
|
||||
<a-tag style="margin:0;" color="green">[[ dbInbound.toInbound().stream.network ]]</a-tag>
|
||||
<a-tag style="margin:0;" v-if="dbInbound.toInbound().stream.isTls" color="cyan">tls</a-tag>
|
||||
<a-tag style="margin:0;" v-if="dbInbound.toInbound().stream.isXTls" color="cyan">xtls</a-tag>
|
||||
</template>
|
||||
</template>
|
||||
<template slot="clients" slot-scope="text, dbInbound">
|
||||
<template v-if="clientCount[dbInbound.id]">
|
||||
<a-tag style="margin:0;" color="green">[[ clientCount[dbInbound.id].clients ]]</a-tag>
|
||||
<a-popover title="{{ i18n "disabled" }}" :overlay-class-name="siderDrawer.isDarkTheme ? 'ant-dark' : ''">
|
||||
<template slot="content">
|
||||
<p v-for="clientEmail in clientCount[dbInbound.id].deactive">[[ clientEmail ]]</p>
|
||||
</template>
|
||||
<a-tag style="margin:0; padding: 0 2px;" v-if="clientCount[dbInbound.id].deactive.length">[[ clientCount[dbInbound.id].deactive.length ]]</a-tag>
|
||||
</a-popover>
|
||||
<a-popover title="{{ i18n "depleted" }}" :overlay-class-name="siderDrawer.isDarkTheme ? 'ant-dark' : ''">
|
||||
<template slot="content">
|
||||
<p v-for="clientEmail in clientCount[dbInbound.id].depleted">[[ clientEmail ]]</p>
|
||||
</template>
|
||||
<a-tag style="margin:0; padding: 0 2px;" color="red" v-if="clientCount[dbInbound.id].depleted.length">[[ clientCount[dbInbound.id].depleted.length ]]</a-tag>
|
||||
</a-popover>
|
||||
<a-popover title="{{ i18n "depletingSoon" }}" :overlay-class-name="siderDrawer.isDarkTheme ? 'ant-dark' : ''">
|
||||
<template slot="content">
|
||||
<p v-for="clientEmail in clientCount[dbInbound.id].expiring">[[ clientEmail ]]</p>
|
||||
</template>
|
||||
<a-tag style="margin:0; padding: 0 2px;" color="orange" v-if="clientCount[dbInbound.id].expiring.length">[[ clientCount[dbInbound.id].expiring.length ]]</a-tag>
|
||||
</a-popover>
|
||||
</template>
|
||||
</template>
|
||||
<template slot="traffic" slot-scope="text, dbInbound">
|
||||
<a-tag color="blue">[[ sizeFormat(dbInbound.up) ]] / [[ sizeFormat(dbInbound.down) ]]</a-tag>
|
||||
@@ -114,14 +158,6 @@
|
||||
</template>
|
||||
<a-tag v-else color="green">{{ i18n "unlimited" }}</a-tag>
|
||||
</template>
|
||||
<template slot="stream" slot-scope="text, dbInbound">
|
||||
<template v-if="dbInbound.isVMess || dbInbound.isVLess || dbInbound.isTrojan || dbInbound.isSS">
|
||||
<a-tag color="green">[[ dbInbound.toInbound().stream.network ]]</a-tag>
|
||||
<a-tag v-if="dbInbound.toInbound().stream.isTls" color="blue">tls</a-tag>
|
||||
<a-tag v-if="dbInbound.toInbound().stream.isXTls" color="blue">xtls</a-tag>
|
||||
</template>
|
||||
<template v-else>{{ i18n "none" }}</template>
|
||||
</template>
|
||||
<template slot="enable" slot-scope="text, dbInbound">
|
||||
<a-switch v-model="dbInbound.enable" @change="switchEnable(dbInbound.id)"></a-switch>
|
||||
</template>
|
||||
@@ -184,28 +220,28 @@
|
||||
}, {
|
||||
title: '{{ i18n "pages.inbounds.remark" }}',
|
||||
align: 'center',
|
||||
width: 60,
|
||||
width: 50,
|
||||
dataIndex: "remark",
|
||||
}, {
|
||||
title: '{{ i18n "pages.inbounds.protocol" }}',
|
||||
align: 'center',
|
||||
width: 40,
|
||||
scopedSlots: { customRender: 'protocol' },
|
||||
}, {
|
||||
title: '{{ i18n "pages.inbounds.port" }}',
|
||||
align: 'center',
|
||||
dataIndex: "port",
|
||||
width: 40,
|
||||
}, {
|
||||
title: '{{ i18n "pages.inbounds.protocol" }}',
|
||||
align: 'left',
|
||||
width: 70,
|
||||
scopedSlots: { customRender: 'protocol' },
|
||||
}, {
|
||||
title: '{{ i18n "clients" }}',
|
||||
align: 'left',
|
||||
width: 50,
|
||||
scopedSlots: { customRender: 'clients' },
|
||||
}, {
|
||||
title: '{{ i18n "pages.inbounds.traffic" }}↑|↓',
|
||||
align: 'center',
|
||||
width: 120,
|
||||
scopedSlots: { customRender: 'traffic' },
|
||||
}, {
|
||||
title: '{{ i18n "pages.inbounds.transportConfig" }}',
|
||||
align: 'center',
|
||||
width: 60,
|
||||
scopedSlots: { customRender: 'stream' },
|
||||
}, {
|
||||
title: '{{ i18n "pages.inbounds.expireDate" }}',
|
||||
align: 'center',
|
||||
@@ -241,6 +277,9 @@
|
||||
dbInbounds: [],
|
||||
searchKey: '',
|
||||
searchedInbounds: [],
|
||||
expireDiff: 0,
|
||||
trafficDiff: 0,
|
||||
clientCount: {},
|
||||
},
|
||||
methods: {
|
||||
loading(spinning=true) {
|
||||
@@ -256,17 +295,64 @@
|
||||
this.setInbounds(msg.obj);
|
||||
this.searchKey = '';
|
||||
},
|
||||
async getThresholds() {
|
||||
this.loading();
|
||||
const msg = await HttpUtil.post('/xui/setting/thresholds');
|
||||
this.loading(false);
|
||||
if (!msg.success) {
|
||||
return;
|
||||
}
|
||||
this.expireDiff = msg.obj.expireDiff * 84600000;
|
||||
this.trafficDiff = msg.obj.trafficDiff * 1073741824;
|
||||
},
|
||||
setInbounds(dbInbounds) {
|
||||
this.inbounds.splice(0);
|
||||
this.dbInbounds.splice(0);
|
||||
this.searchedInbounds.splice(0);
|
||||
for (const inbound of dbInbounds) {
|
||||
const dbInbound = new DBInbound(inbound);
|
||||
this.inbounds.push(dbInbound.toInbound());
|
||||
to_inbound = dbInbound.toInbound()
|
||||
this.inbounds.push(to_inbound);
|
||||
this.dbInbounds.push(dbInbound);
|
||||
this.searchedInbounds.push(dbInbound);
|
||||
if([Protocols.VMESS, Protocols.VLESS, Protocols.TROJAN].includes(inbound.protocol) ){
|
||||
this.clientCount[inbound.id] = this.getClientCounts(inbound,to_inbound);
|
||||
}
|
||||
}
|
||||
},
|
||||
getClientCounts(dbInbound,inbound){
|
||||
let clientCount = 0,active = [], deactive = [], depleted = [], expiring = [];
|
||||
clients = this.getClients(dbInbound.protocol, inbound.settings);
|
||||
clientStats = dbInbound.clientStats
|
||||
now = new Date().getTime()
|
||||
if(clients){
|
||||
clientCount = clients.length;
|
||||
if(dbInbound.enable){
|
||||
clients.forEach(client => {
|
||||
client.enable ? active.push(client.email) : deactive.push(client.email);
|
||||
});
|
||||
clientStats.forEach(client => {
|
||||
if(!client.enable) {
|
||||
depleted.push(client.email);
|
||||
} else {
|
||||
if ((client.expiryTime > 0 && (client.expiryTime-now < this.expireDiff)) ||
|
||||
(client.total > 0 && (client.total-client.up+client.down < this.trafficDiff ))) expiring.push(client.email);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
clients.forEach(client => {
|
||||
deactive.push(client.email);
|
||||
});
|
||||
}
|
||||
}
|
||||
return {
|
||||
clients: clientCount,
|
||||
active: active,
|
||||
deactive: deactive,
|
||||
depleted: depleted,
|
||||
expiring: expiring,
|
||||
};
|
||||
},
|
||||
searchInbounds(key) {
|
||||
if (ObjectUtil.isEmpty(key)) {
|
||||
this.searchedInbounds = this.dbInbounds.slice();
|
||||
@@ -591,37 +677,30 @@
|
||||
}, 500)
|
||||
},
|
||||
mounted() {
|
||||
this.getThresholds();
|
||||
this.getDBInbounds();
|
||||
},
|
||||
computed: {
|
||||
total() {
|
||||
let down = 0, up = 0;
|
||||
let clients = 0, active = 0, deactive = 0;
|
||||
let clients = 0, deactive = [], depleted = [], expiring = [];
|
||||
this.dbInbounds.forEach(dbInbound => {
|
||||
down += dbInbound.down;
|
||||
up += dbInbound.up;
|
||||
inbound = dbInbound.toInbound();
|
||||
clients = this.getClients(dbInbound.protocol, inbound.settings);
|
||||
if(clients){
|
||||
if(dbInbound.enable){
|
||||
isClientEnable = false;
|
||||
clients.forEach(client => {
|
||||
isClientEnable = client.email == "" ? true: this.isClientEnabled(dbInbound,client.email);
|
||||
isClientEnable ? active++ : deactive++;
|
||||
});
|
||||
} else {
|
||||
deactive += clients.length;
|
||||
}
|
||||
} else {
|
||||
dbInbound.enable ? active++ : deactive++;
|
||||
if (this.clientCount[dbInbound.id]) {
|
||||
clients += this.clientCount[dbInbound.id].clients;
|
||||
deactive = deactive.concat(this.clientCount[dbInbound.id].deactive);
|
||||
depleted = depleted.concat(this.clientCount[dbInbound.id].depleted);
|
||||
expiring = expiring.concat(this.clientCount[dbInbound.id].expiring);
|
||||
}
|
||||
});
|
||||
return {
|
||||
down: down,
|
||||
up: up,
|
||||
clients: active + deactive,
|
||||
active: active,
|
||||
clients: clients,
|
||||
deactive: deactive,
|
||||
depleted: depleted,
|
||||
expiring: expiring,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -44,6 +44,8 @@
|
||||
<setting-list-item type="text" title='{{ i18n "pages.setting.publicKeyPath"}}' desc='{{ i18n "pages.setting.publicKeyPathDesc"}}' v-model="allSetting.webCertFile"></setting-list-item>
|
||||
<setting-list-item type="text" title='{{ i18n "pages.setting.privateKeyPath"}}' desc='{{ i18n "pages.setting.privateKeyPathDesc"}}' v-model="allSetting.webKeyFile"></setting-list-item>
|
||||
<setting-list-item type="text" title='{{ i18n "pages.setting.panelUrlPath"}}' desc='{{ i18n "pages.setting.panelUrlPathDesc"}}' v-model="allSetting.webBasePath"></setting-list-item>
|
||||
<setting-list-item type="number" title='{{ i18n "pages.setting.expireTimeDiff" }}' desc='{{ i18n "pages.setting.expireTimeDiffDesc" }}' v-model="allSetting.expireDiff" :min="0"></setting-list-item>
|
||||
<setting-list-item type="number" title='{{ i18n "pages.setting.trafficDiff" }}' desc='{{ i18n "pages.setting.trafficDiffDesc" }}' v-model="allSetting.trafficDiff" :min="0"></setting-list-item>
|
||||
<a-list-item>
|
||||
<a-row style="padding: 20px">
|
||||
<a-col :lg="24" :xl="12">
|
||||
@@ -120,8 +122,6 @@
|
||||
<setting-list-item type="text" title='{{ i18n "pages.setting.telegramChatId"}}' desc='{{ i18n "pages.setting.telegramChatIdDesc"}}' v-model="allSetting.tgBotChatId"></setting-list-item>
|
||||
<setting-list-item type="text" title='{{ i18n "pages.setting.telegramNotifyTime"}}' desc='{{ i18n "pages.setting.telegramNotifyTimeDesc"}}' v-model="allSetting.tgRunTime"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.setting.tgNotifyBackup" }}' desc='{{ i18n "pages.setting.tgNotifyBackupDesc" }}' v-model="allSetting.tgBotBackup"></setting-list-item>
|
||||
<setting-list-item type="number" title='{{ i18n "pages.setting.tgNotifyExpireTimeDiff" }}' desc='{{ i18n "pages.setting.tgNotifyExpireTimeDiffDesc" }}' v-model="allSetting.tgExpireDiff" :min="0"></setting-list-item>
|
||||
<setting-list-item type="number" title='{{ i18n "pages.setting.tgNotifyTrafficDiff" }}' desc='{{ i18n "pages.setting.tgNotifyTrafficDiffDesc" }}' v-model="allSetting.tgTrafficDiff" :min="0"></setting-list-item>
|
||||
<setting-list-item type="number" title='{{ i18n "pages.setting.tgNotifyCpu" }}' desc='{{ i18n "pages.setting.tgNotifyCpuDesc" }}' v-model="allSetting.tgCpu" :min="0" :max="100"></setting-list-item>
|
||||
</a-list>
|
||||
</a-tab-pane>
|
||||
|
||||
@@ -28,14 +28,14 @@ var defaultValueMap = map[string]string{
|
||||
"webKeyFile": "",
|
||||
"secret": random.Seq(32),
|
||||
"webBasePath": "/",
|
||||
"expireDiff": "0",
|
||||
"trafficDiff": "0",
|
||||
"timeLocation": "Asia/Tehran",
|
||||
"tgBotEnable": "false",
|
||||
"tgBotToken": "",
|
||||
"tgBotChatId": "",
|
||||
"tgRunTime": "@daily",
|
||||
"tgBotBackup": "false",
|
||||
"tgExpireDiff": "0",
|
||||
"tgTrafficDiff": "0",
|
||||
"tgCpu": "0",
|
||||
}
|
||||
|
||||
@@ -238,22 +238,6 @@ func (s *SettingService) SetTgBotBackup(value bool) error {
|
||||
return s.setBool("tgBotBackup", value)
|
||||
}
|
||||
|
||||
func (s *SettingService) GetTgExpireDiff() (int, error) {
|
||||
return s.getInt("tgExpireDiff")
|
||||
}
|
||||
|
||||
func (s *SettingService) SetTgExpireDiff(value int) error {
|
||||
return s.setInt("tgExpireDiff", value)
|
||||
}
|
||||
|
||||
func (s *SettingService) GetTgTrafficDiff() (int, error) {
|
||||
return s.getInt("tgTrafficDiff")
|
||||
}
|
||||
|
||||
func (s *SettingService) SetTgTrafficDiff(value int) error {
|
||||
return s.setInt("tgTrafficDiff", value)
|
||||
}
|
||||
|
||||
func (s *SettingService) GetTgCpu() (int, error) {
|
||||
return s.getInt("tgCpu")
|
||||
}
|
||||
@@ -278,6 +262,22 @@ func (s *SettingService) GetKeyFile() (string, error) {
|
||||
return s.getString("webKeyFile")
|
||||
}
|
||||
|
||||
func (s *SettingService) GetExpireDiff() (int, error) {
|
||||
return s.getInt("expireDiff")
|
||||
}
|
||||
|
||||
func (s *SettingService) SetExpireDiff(value int) error {
|
||||
return s.setInt("expireDiff", value)
|
||||
}
|
||||
|
||||
func (s *SettingService) GetTrafficDiff() (int, error) {
|
||||
return s.getInt("trafficDiff")
|
||||
}
|
||||
|
||||
func (s *SettingService) SetgetTrafficDiff(value int) error {
|
||||
return s.setInt("trafficDiff", value)
|
||||
}
|
||||
|
||||
func (s *SettingService) GetSecret() ([]byte, error) {
|
||||
secret, err := s.getString("secret")
|
||||
if secret == defaultValueMap["secret"] {
|
||||
|
||||
@@ -160,7 +160,7 @@ func (t *Tgbot) asnwerCallback(callbackQuery *tgbotapi.CallbackQuery, isAdmin bo
|
||||
t.SendMsgToTgbot(callbackQuery.From.ID, t.getServerUsage())
|
||||
case "inbounds":
|
||||
t.SendMsgToTgbot(callbackQuery.From.ID, t.getInboundUsages())
|
||||
case "exhausted_soon":
|
||||
case "deplete_soon":
|
||||
t.SendMsgToTgbot(callbackQuery.From.ID, t.getExhausted())
|
||||
case "get_backup":
|
||||
t.sendBackup(callbackQuery.From.ID)
|
||||
@@ -190,7 +190,7 @@ func (t *Tgbot) SendAnswer(chatId int64, msg string, isAdmin bool) {
|
||||
),
|
||||
tgbotapi.NewInlineKeyboardRow(
|
||||
tgbotapi.NewInlineKeyboardButtonData("Get Inbounds", "inbounds"),
|
||||
tgbotapi.NewInlineKeyboardButtonData("Exhausted soon", "exhausted_soon"),
|
||||
tgbotapi.NewInlineKeyboardButtonData("Deplete soon", "deplete_soon"),
|
||||
),
|
||||
tgbotapi.NewInlineKeyboardRow(
|
||||
tgbotapi.NewInlineKeyboardButtonData("Commands", "commands"),
|
||||
@@ -507,11 +507,11 @@ func (t *Tgbot) getExhausted() string {
|
||||
var disabledInbounds []model.Inbound
|
||||
var disabledClients []xray.ClientTraffic
|
||||
output := ""
|
||||
TrafficThreshold, err := t.settingService.GetTgTrafficDiff()
|
||||
TrafficThreshold, err := t.settingService.GetTrafficDiff()
|
||||
if err == nil && TrafficThreshold > 0 {
|
||||
trDiff = int64(TrafficThreshold) * 1073741824
|
||||
}
|
||||
ExpireThreshold, err := t.settingService.GetTgExpireDiff()
|
||||
ExpireThreshold, err := t.settingService.GetExpireDiff()
|
||||
if err == nil && ExpireThreshold > 0 {
|
||||
exDiff = int64(ExpireThreshold) * 84600000
|
||||
}
|
||||
@@ -541,7 +541,7 @@ func (t *Tgbot) getExhausted() string {
|
||||
disabledInbounds = append(disabledInbounds, *inbound)
|
||||
}
|
||||
}
|
||||
output += fmt.Sprintf("Exhausted Inbounds count:\r\n🛑 Disabled: %d\r\n🔜 Exhaust soon: %d\r\n \r\n", len(disabledInbounds), len(exhaustedInbounds))
|
||||
output += fmt.Sprintf("Exhausted Inbounds count:\r\n🛑 Disabled: %d\r\n🔜 Deplete soon: %d\r\n \r\n", len(disabledInbounds), len(exhaustedInbounds))
|
||||
if len(exhaustedInbounds) > 0 {
|
||||
output += "Exhausted Inbounds:\r\n"
|
||||
for _, inbound := range exhaustedInbounds {
|
||||
@@ -553,7 +553,7 @@ func (t *Tgbot) getExhausted() string {
|
||||
}
|
||||
}
|
||||
}
|
||||
output += fmt.Sprintf("Exhausted Clients count:\r\n🛑 Disabled: %d\r\n🔜 Exhaust soon: %d\r\n \r\n", len(disabledClients), len(exhaustedClients))
|
||||
output += fmt.Sprintf("Exhausted Clients count:\r\n🛑 Exhausted: %d\r\n🔜 Deplete soon: %d\r\n \r\n", len(disabledClients), len(exhaustedClients))
|
||||
if len(exhaustedClients) > 0 {
|
||||
output += "Exhausted Clients:\r\n"
|
||||
for _, traffic := range exhaustedClients {
|
||||
|
||||
@@ -33,8 +33,11 @@
|
||||
"host" = "Host"
|
||||
"path" = "Path"
|
||||
"camouflage" = "Camouflage"
|
||||
"status" = "Status"
|
||||
"enabled" = "Enabled"
|
||||
"disabled" = "Disabled"
|
||||
"depleted" = "Depleted"
|
||||
"depletingSoon" = "Depleting soon"
|
||||
"domainName" = "Domain name"
|
||||
"additional" = "Alter"
|
||||
"monitor" = "Listen IP"
|
||||
@@ -211,10 +214,10 @@
|
||||
"telegramNotifyTimeDesc" = "Using Crontab timing format. Restart the panel to take effect"
|
||||
"tgNotifyBackup" = "Database backup"
|
||||
"tgNotifyBackupDesc" = "Sending database backup file with report notification. Restart the panel to take effect"
|
||||
"tgNotifyExpireTimeDiff" = "Remained time threshold"
|
||||
"tgNotifyExpireTimeDiffDesc" = "This telegram bot will send you a notification before expiration (unit:day)"
|
||||
"tgNotifyTrafficDiff" = "Remained traffic threshold"
|
||||
"tgNotifyTrafficDiffDesc" = "This telegram bot will send you a notification before finishing traffic (unit:GB)"
|
||||
"expireTimeDiff" = "Exhaustion time threshold"
|
||||
"expireTimeDiffDesc" = "Detect exhaustion before expiration (unit:day)"
|
||||
"trafficDiff" = "Exhaustion traffic threshold"
|
||||
"trafficDiffDesc" = "Detect exhaustion before finishing traffic (unit:GB)"
|
||||
"tgNotifyCpu" = "CPU percentage alert threshold"
|
||||
"tgNotifyCpuDesc" = "This telegram bot will send you a notification if CPU usage is more than this percentage (unit:%)"
|
||||
"timeZonee" = "Time Zone"
|
||||
|
||||
@@ -33,8 +33,11 @@
|
||||
"host" = "آدرس"
|
||||
"path" = "مسیر"
|
||||
"camouflage" = "استتار"
|
||||
"status" = "وضعیت"
|
||||
"enabled" = "فعال"
|
||||
"disabled" = "غیرفعال"
|
||||
"depleted" = "منقضی"
|
||||
"depletingSoon" = "در حال انقضا"
|
||||
"domainName" = "آدرس دامنه"
|
||||
"additional" = "آی دی جایگزین"
|
||||
"monitor" = "آی پی اتصال"
|
||||
@@ -211,10 +214,10 @@
|
||||
"telegramNotifyTimeDesc" = "از فرمت زمان بندی Crontab استفاده کنید . پنل را مجدداً راه اندازی کنید تا اعمال شود"
|
||||
"tgNotifyBackup" = "پشتیبان گیری از پایگاه داده"
|
||||
"tgNotifyBackupDesc" = "ارسال کپی فایل پایگاه داده به همراه گزارش دوره ای"
|
||||
"tgNotifyExpireTimeDiff" = "آستانه زمان باقی مانده"
|
||||
"tgNotifyExpireTimeDiffDesc" = "این ربات تلگرام قبل از انقضا برای شما پیام ارسال می کند (واحد: روز)"
|
||||
"tgNotifyTrafficDiff" = "آستانه ترافیک باقی مانده"
|
||||
"tgNotifyTrafficDiffDesc" = "این ربات تلگرام قبل از اتمام ترافیک برای شما پیام ارسال می کند (واحد: گیگابایت)"
|
||||
"expireTimeDiff" = "آستانه زمان باقی مانده"
|
||||
"expireTimeDiffDesc" = "فاصله زمانی هشدار تا رسیدن به زمان انقضا (واحد: روز)"
|
||||
"trafficDiff" = "آستانه ترافیک باقی مانده"
|
||||
"trafficDiffDesc" = "فاصله زمانی هشدار تا رسیدن به اتمام ترافیک (واحد: گیگابایت)"
|
||||
"tgNotifyCpu" = "آستانه هشدار درصد پردازنده"
|
||||
"tgNotifyCpuDesc" = "این ربات تلگرام در صورت استفاده پردازنده بیشتر از این درصد برای شما پیام ارسال می کند.(واحد: درصد)"
|
||||
"timeZonee" = "منظقه زمانی"
|
||||
|
||||
@@ -33,8 +33,11 @@
|
||||
"host" = "主持人"
|
||||
"path" = "小路"
|
||||
"camouflage" = "伪装"
|
||||
"status" = "状态"
|
||||
"enabled" = "开启"
|
||||
"disabled" = "关闭"
|
||||
"depleted" = "耗尽"
|
||||
"depletingSoon" = "即将耗尽"
|
||||
"domainName" = "域名"
|
||||
"additional" = "额外"
|
||||
"monitor" = "监听"
|
||||
@@ -211,10 +214,10 @@
|
||||
"telegramNotifyTimeDesc" = "采用Crontab定时格式,重启面板生效"
|
||||
"tgNotifyBackup" = "数据库备份"
|
||||
"tgNotifyBackupDesc" = "正在发送数据库备份文件和报告通知。重启面板生效"
|
||||
"tgNotifyExpireTimeDiff" = "剩余时间阈值"
|
||||
"tgNotifyExpireTimeDiffDesc" = "这个 talegram bot 会在到期前给你发送通知(单位:天)"
|
||||
"tgNotifyTrafficDiff" = "剩余流量阈值"
|
||||
"tgNotifyTrafficDiffDesc" = "这个 talegram bot 会在流量结束前给你发送通知(单位:GB)"
|
||||
"expireTimeDiff" = "耗尽时间阈值"
|
||||
"expireTimeDiffDesc" = "到期前检测耗尽(单位:天)"
|
||||
"trafficDiff" = "耗尽流量阈值"
|
||||
"trafficDiffDesc" = "完成流量前检测耗尽(单位:GB)"
|
||||
"tgNotifyCpu" = "CPU 百分比警报阈值"
|
||||
"tgNotifyCpuDesc" = "如果 CPU 使用率超过此百分比(单位:%),此 talegram bot 将向您发送通知"
|
||||
"timeZonee" = "时区"
|
||||
|
||||
Reference in New Issue
Block a user