Compare commits

..

21 Commits
0.4.1 ... 0.4.2

Author SHA1 Message Date
Alireza Ahmadi
2f1f28cc0b v0.4.2 2023-03-20 12:03:52 +01:00
Alireza Ahmadi
70ff51d629 [Bulk client] add option: without random email #72 2023-03-20 11:50:44 +01:00
Alireza Ahmadi
7472c31c34 [TGBOT] add seach inbound #75 2023-03-20 11:18:47 +01:00
Alireza Ahmadi
04a8d5c177 [DarkMode] better dark theme based on antdv2 2023-03-20 10:50:31 +01:00
Alireza Ahmadi
7b2bd4247d TGBOT: Add xray config to backup #75 2023-03-20 10:22:41 +01:00
Alireza Ahmadi
5aee1c886b Merge branch 'main' of https://github.com/alireza0/x-ui 2023-03-19 20:19:04 +01:00
Alireza Ahmadi
7a9a30a038 Dark-Mode: Better contrast 2023-03-19 19:59:35 +01:00
Alireza Ahmadi
eb17cec289 Remove chat answer 2023-03-19 19:07:40 +01:00
Alireza Ahmadi
22e107c746 Update install.sh
Fix centos7+ message
2023-03-19 11:56:42 +01:00
Alireza Ahmadi
36a93e2959 Merge pull request #77 from forkeer/main
Fedora OS Support
2023-03-19 11:56:13 +01:00
Alireza Ahmadi
073247f054 Fix Link bug 2023-03-19 11:51:08 +01:00
Leonardo
96c8932961 Merge branch 'alireza0:main' into main 2023-03-19 00:14:23 +03:30
Leonardo
5fac7df174 Merge branch 'alireza0:main' into main 2023-03-18 13:45:41 +03:30
Leonardo
8bba9f3c25 Update install.sh
Fix s390x
2023-03-18 13:43:54 +03:30
Leonardo
268e8c7eb1 Update x-ui.sh
Fix Debian 8 Support
2023-03-18 13:39:54 +03:30
Leonardo
14e8f6cbfa Update x-ui.sh
Fix OS Version
2023-03-18 13:38:37 +03:30
Leonardo
7f0ba495db Update install.sh
Fix OS Version
2023-03-18 13:36:01 +03:30
Leonardo
f829213dd1 go-version
go-version update to stable
2023-03-14 14:17:52 +03:30
Leonardo
4d5a73512e Update README.md
Fedora 36+
2023-03-14 14:01:52 +03:30
Leonardo
6dccc5b891 Update install.sh
Fedora OS Fix
2023-03-14 14:00:14 +03:30
Leonardo
f642830dc8 Update x-ui.sh
Fix Fedora
2023-03-14 13:56:56 +03:30
13 changed files with 469 additions and 366 deletions

View File

@@ -14,7 +14,7 @@ jobs:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v4 uses: actions/setup-go@v4
with: with:
go-version: '1.20' go-version: 'stable'
- name: build linux amd64 version - name: build linux amd64 version
run: | run: |
CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -o xui-release -v main.go CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -o xui-release -v main.go

View File

@@ -153,6 +153,7 @@ Reference syntax:
- CentOS 7+ - CentOS 7+
- Ubuntu 16+ - Ubuntu 16+
- Debian 8+ - Debian 8+
- Fedora 36+
# common problem # common problem

View File

@@ -1 +1 @@
0.4.1 0.4.2

View File

@@ -10,24 +10,18 @@ cur_dir=$(pwd)
# check root # check root
[[ $EUID -ne 0 ]] && echo -e "${red}Fatal error${plain} Please run this script with root privilege \n " && exit 1 [[ $EUID -ne 0 ]] && echo -e "${red}Fatal error${plain} Please run this script with root privilege \n " && exit 1
# check os # Check OS and set release variable
if [[ -f /etc/redhat-release ]]; then if [[ -f /etc/os-release ]]; then
release="centos" source /etc/os-release
elif cat /etc/issue | grep -Eqi "debian"; then release=$ID
release="debian" elif [[ -f /usr/lib/os-release ]]; then
elif cat /etc/issue | grep -Eqi "ubuntu"; then source /usr/lib/os-release
release="ubuntu" release=$ID
elif cat /etc/issue | grep -Eqi "centos|red hat|redhat"; then
release="centos"
elif cat /proc/version | grep -Eqi "debian"; then
release="debian"
elif cat /proc/version | grep -Eqi "ubuntu"; then
release="ubuntu"
elif cat /proc/version | grep -Eqi "centos|red hat|redhat"; then
release="centos"
else else
echo -e "${red} Check system OS failed, please contact the author! ${plain}\n" && exit 1 echo "Failed to check the system OS, please contact the author!" >&2
exit 1
fi fi
echo "The OS release is: $release"
arch=$(arch) arch=$(arch)
@@ -39,42 +33,44 @@ elif [[ $arch == "s390x" ]]; then
arch="s390x" arch="s390x"
else else
arch="amd64" arch="amd64"
echo -e "${red} Fail to check system arch, will use default arch: ${arch}${plain}" echo -e "${red} Failed to check system arch, will use default arch: ${arch}${plain}"
fi fi
echo "arch: ${arch}" echo "arch: ${arch}"
if [ $(getconf WORD_BIT) != '32' ] && [ $(getconf LONG_BIT) != '64' ]; then if [ $(getconf WORD_BIT) != '32' ] && [ $(getconf LONG_BIT) != '64' ]; then
echo "x-ui dosen't support 32-bit(x86) system, please use 64 bit operating system(x86_64) instead,if there is something wrong, plz let me know" echo "x-ui dosen't support 32-bit(x86) system, please use 64 bit operating system(x86_64) instead, if there is something wrong, please get in touch with me!"
exit -1 exit -1
fi fi
os_version="" os_version=""
os_version=$(grep -i version_id /etc/os-release | cut -d \" -f2 | cut -d . -f1)
# os version if [[ "${release}" == "centos" ]]; then
if [[ -f /etc/os-release ]]; then if [[ ${os_version} -lt 7 ]]; then
os_version=$(awk -F'[= ."]' '/VERSION_ID/{print $3}' /etc/os-release) echo -e "${red} Please use CentOS 7 or higher ${plain}\n" && exit 1
fi fi
if [[ -z "$os_version" && -f /etc/lsb-release ]]; then elif [[ "${release}" == "ubuntu" ]]; then
os_version=$(awk -F'[= ."]+' '/DISTRIB_RELEASE/{print $2}' /etc/lsb-release) if [[ ${os_version} -lt 18 ]]; then
fi echo -e "${red}please use Ubuntu 18 or higher version${plain}\n" && exit 1
fi
if [[ x"${release}" == x"centos" ]]; then elif [[ "${release}" == "fedora" ]]; then
if [[ ${os_version} -le 6 ]]; then if [[ ${os_version} -lt 36 ]]; then
echo -e "${red} Please use CentOS 7 or higher version ${plain}\n" && exit 1 echo -e "${red}please use Fedora 36 or higher version${plain}\n" && exit 1
fi fi
elif [[ x"${release}" == x"ubuntu" ]]; then
if [[ ${os_version} -lt 16 ]]; then elif [[ "${release}" == "debian" ]]; then
echo -e "${red} Please use Ubuntu 16 or higher version ${plain}\n" && exit 1
fi
elif [[ x"${release}" == x"debian" ]]; then
if [[ ${os_version} -lt 8 ]]; then if [[ ${os_version} -lt 8 ]]; then
echo -e "${red} Please use Debian 8 or higher version ${plain}\n" && exit 1 echo -e "${red} Please use Debian 8 or higher ${plain}\n" && exit 1
fi fi
else
echo -e "${red}Failed to check the OS version, please contact the author!${plain}" && exit 1
fi fi
install_base() { install_base() {
if [[ x"${release}" == x"centos" ]]; then if [[ "${release}" == "centos" ]]; then
yum install wget curl tar -y yum install wget curl tar -y
else else
apt install wget curl tar -y apt install wget curl tar -y

View File

@@ -156,9 +156,19 @@
padding:16px; padding:16px;
} }
.ant-menu-dark,
.ant-menu-dark .ant-menu-sub,
.ant-layout-header,
.ant-layout-sider-dark,
.ant-layout-sider-zero-width-trigger,
.ant-dropdown-menu-dark,.ant-dropdown-menu-dark .ant-dropdown-menu,
.ant-menu-dark.ant-menu-horizontal>.ant-menu-item,.ant-menu-dark.ant-menu-horizontal>.ant-menu-submenu {
background:#161b22
}
.ant-card-dark { .ant-card-dark {
color: hsla(0,0%,100%,.65); color: hsla(0,0%,100%,.65);
background-color: #001529; background-color: #1a212a;
border-color:rgba(0,0,0,.09); border-color:rgba(0,0,0,.09);
} }
@@ -168,7 +178,7 @@
.ant-card-dark .ant-table-thead th { .ant-card-dark .ant-table-thead th {
color: hsla(0,0%,100%,.65); color: hsla(0,0%,100%,.65);
background-color: #000c17; background-color: #161b22;
} }
.ant-card-dark .ant-table-tbody tr td, .ant-card-dark .ant-table-tbody tr td,
@@ -180,7 +190,7 @@
.ant-card-dark .ant-calendar, .ant-card-dark .ant-calendar,
.ant-card-dark .ant-table-placeholder { .ant-card-dark .ant-table-placeholder {
color: hsla(0,0%,100%,.65); color: hsla(0,0%,100%,.65);
background-color: #001529; background-color: #262f3d;
} }
.ant-card-dark .ant-list-item-meta-title, .ant-card-dark .ant-list-item-meta-title,
@@ -210,7 +220,7 @@
.ant-card-dark tbody .ant-table-expanded-row { .ant-card-dark tbody .ant-table-expanded-row {
color: hsla(0,0%,100%,.65); color: hsla(0,0%,100%,.65);
background-color: #023366; background-color: #1a212a;
} }
.ant-card-dark .ant-input, .ant-card-dark .ant-input,
@@ -219,12 +229,12 @@
.ant-card-dark .ant-select-dropdown-menu-item-selected, .ant-card-dark .ant-select-dropdown-menu-item-selected,
.ant-card-dark .ant-select-selection { .ant-card-dark .ant-select-selection {
color: hsla(0,0%,100%,.65); color: hsla(0,0%,100%,.65);
background-color: #023366; background-color: #2e3b52;
} }
.ant-card-dark .ant-collapse-item { .ant-card-dark .ant-collapse-item {
color: hsla(0,0%,100%,.65); color: hsla(0,0%,100%,.65);
background-color: #000c17; background-color: #161b22;
} }
.ant-card-dark .ant-modal-content, .ant-card-dark .ant-modal-content,
@@ -232,7 +242,7 @@
.ant-card-dark .ant-modal-header, .ant-card-dark .ant-modal-header,
.ant-card-dark .ant-calendar-selected-day .ant-calendar-date { .ant-card-dark .ant-calendar-selected-day .ant-calendar-date {
color: hsla(0,0%,100%,.65); color: hsla(0,0%,100%,.65);
background-color: #1C262D; background-color: #222a37;
} }
.client-table-header { .client-table-header {
@@ -244,13 +254,13 @@
} }
.ant-card-dark .client-table-header { .ant-card-dark .client-table-header {
background-color: #023366; background-color: #1a212a;
color: hsla(0,0%,100%,.65); color: hsla(0,0%,100%,.65);
} }
.ant-card-dark .client-table-odd-row { .ant-card-dark .client-table-odd-row {
color: hsla(0,0%,100%,.65); color: hsla(0,0%,100%,.65);
background-color: #1C262D; background-color: #242c3a;
} }
.ant-card-dark .ant-calendar-last-month-cell .ant-calendar-date, .ant-card-dark .ant-calendar-last-month-cell .ant-calendar-date,
@@ -264,6 +274,58 @@
.ant-drawer-dark .ant-drawer-wrapper-body, .ant-drawer-dark .ant-drawer-wrapper-body,
.ant-drawer-dark .drawer-handle { .ant-drawer-dark .drawer-handle {
background-color: #001529; background-color: #1a212a;
border: 1px solid hsla(0,0%,100%,.30); border: 1px solid hsla(0,0%,100%,.30);
} }
.ant-card-dark .ant-tag-blue {
color: #3c9ae8;
background: #111d2c;
border-color: #15395b;
}
.ant-card-dark .ant-tag-green {
color: #6abe39;
background: #162312;
border-color: #274916;
}
.ant-card-dark .ant-tag-cyan {
color: #33bcb7;
background: #112123;
border-color: #144848;
}
.ant-card-dark .ant-tag-red {
color: #e84749;
background: #2a1215;
border-color: #58181c;
}
.ant-card-dark .ant-tag-orange {
color: #e89a3c;
background: #2b1d11;
border-color: #593815;
}
.ant-card-dark .ant-table-row-expand-icon {
background: none;
}
.ant-card-dark .ant-switch-checked {
background-color: #0c61b0;
}
.ant-card-dark .ant-btn {
color: hsla(0,0%,100%,.65);
background: none;
border: 1px solid hsla(0,0%,100%,.65);
}
.ant-card-dark .ant-btn-primary {
color: hsla(0,0%,100%,.65);
background-color: #073763;
border-color: #1890ff;
text-shadow: 0 -1px 0 rgba(0,0,0,.12);
box-shadow: 0 2px 0 rgba(0,0,0,.045);
}

View File

@@ -1155,10 +1155,8 @@ class Inbound extends XrayCommonClass {
if (this.xtls) { if (this.xtls) {
if (!ObjectUtil.isEmpty(this.stream.tls.server)) { if (!ObjectUtil.isEmpty(this.stream.tls.server)) {
address = this.stream.tls.server; address = this.stream.tls.server;
if (type === "tcp") {
params.set("flow", this.settings.vlesses[clientIndex].flow);
}
} }
params.set("flow", this.settings.vlesses[clientIndex].flow);
} }
const link = `vless://${uuid}@${address}:${port}`; const link = `vless://${uuid}@${address}:${port}`;
@@ -1250,10 +1248,8 @@ class Inbound extends XrayCommonClass {
if (this.xtls) { if (this.xtls) {
if (!ObjectUtil.isEmpty(this.stream.tls.server)) { if (!ObjectUtil.isEmpty(this.stream.tls.server)) {
address = this.stream.tls.server; address = this.stream.tls.server;
if (type === "tcp" && this.settings.trojans[clientIndex].flow.length > 0) {
params.set("flow", this.settings.trojans[clientIndex].flow);
}
} }
params.set("flow", this.settings.trojans[clientIndex].flow);
} }
const link = `trojan://${settings.trojans[clientIndex].password}@${address}:${this.port}#${encodeURIComponent(remark)}`; const link = `trojan://${settings.trojans[clientIndex].password}@${address}:${this.port}#${encodeURIComponent(remark)}`;

View File

@@ -7,10 +7,11 @@
<a-form-item label='{{ i18n "pages.client.method" }}'> <a-form-item label='{{ i18n "pages.client.method" }}'>
<a-select v-model="clientsBulkModal.emailMethod" buttonStyle="solid" style="width: 350px" :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''"> <a-select v-model="clientsBulkModal.emailMethod" buttonStyle="solid" style="width: 350px" :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''">
<a-select-option :value="0">Random</a-select-option> <a-select-option :value="0">Random</a-select-option>
<a-select-option :value="1">Random_Prefix</a-select-option> <a-select-option :value="1">Random+Prefix</a-select-option>
<a-select-option :value="2">Random_Prefix+Num</a-select-option> <a-select-option :value="2">Random+Prefix+Num</a-select-option>
<a-select-option :value="3">Random_Prefix+Num+Postfix</a-select-option> <a-select-option :value="3">Random+Prefix+Num+Postfix</a-select-option>
<a-select-option :value="4">Random_Prefix+Num@Telegram Username</a-select-option> <a-select-option :value="4">Random+Prefix+Num@Telegram Username</a-select-option>
<a-select-option :value="5">Prefix+Num+Postfix [ BE CAREFUL! ]</a-select-option>
</a-select> </a-select>
</a-form-item><br /> </a-form-item><br />
<a-form-item v-if="clientsBulkModal.emailMethod>1"> <a-form-item v-if="clientsBulkModal.emailMethod>1">
@@ -91,11 +92,12 @@
start=0; start=0;
end=clientsBulkModal.quantity; end=clientsBulkModal.quantity;
} }
prefix = (method>0 && clientsBulkModal.emailPrefix.length>0) ? "_" + clientsBulkModal.emailPrefix : ""; prefix = (method>0 && clientsBulkModal.emailPrefix.length>0) ? clientsBulkModal.emailPrefix : "";
useNum=(method>1); useNum=(method>1);
postfix = (method>2 && clientsBulkModal.emailPostfix.length>0) ? (method == 4 ? "@" : "") + clientsBulkModal.emailPostfix : ""; postfix = (method>2 && clientsBulkModal.emailPostfix.length>0) ? (method == 4 ? "@" : "") + clientsBulkModal.emailPostfix : "";
for (let i = start; i < end; i++) { for (let i = start; i < end; i++) {
newClient = clientsBulkModal.newClient(clientsBulkModal.dbInbound.protocol); newClient = clientsBulkModal.newClient(clientsBulkModal.dbInbound.protocol);
if(method==5) newClient.email = "";
newClient.email += useNum ? prefix + i.toString() + postfix : prefix + postfix; newClient.email += useNum ? prefix + i.toString() + postfix : prefix + postfix;
newClient._totalGB = clientsBulkModal.totalGB; newClient._totalGB = clientsBulkModal.totalGB;
newClient._expiryTime = clientsBulkModal.expiryTime; newClient._expiryTime = clientsBulkModal.expiryTime;

View File

@@ -72,7 +72,7 @@
</a-drawer> </a-drawer>
<script> <script>
const darkClass = "ant-card-dark"; const darkClass = "ant-card-dark";
const bgDarkStyle = "background-color: #1C262D"; const bgDarkStyle = "background-color: #242c3a";
const siderDrawer = { const siderDrawer = {
visible: false, visible: false,
collapsed: false, collapsed: false,

View File

@@ -11,10 +11,6 @@
.ant-col-sm-24 { .ant-col-sm-24 {
margin-top: 10px; margin-top: 10px;
} }
.ant-table-row-expand-icon {
color: rgba(0,0,0,.65);
}
</style> </style>
<body> <body>
<a-layout id="app" v-cloak> <a-layout id="app" v-cloak>

View File

@@ -84,16 +84,16 @@
</template> </template>
<a-icon type="question-circle" theme="filled"></a-icon> <a-icon type="question-circle" theme="filled"></a-icon>
</a-tooltip> </a-tooltip>
<a-tag color="green" @click="openSelectV2rayVersion">[[ status.xray.version ]]</a-tag> <a-tag color="green" style="cursor: pointer;" @click="openSelectV2rayVersion">[[ status.xray.version ]]</a-tag>
<a-tag color="blue" @click="stopXrayService">{{ i18n "pages.index.stopXray" }}</a-tag> <a-tag color="blue" style="cursor: pointer;" @click="stopXrayService">{{ i18n "pages.index.stopXray" }}</a-tag>
<a-tag color="blue" @click="restartXrayService">{{ i18n "pages.index.restartXray" }}</a-tag> <a-tag color="blue" style="cursor: pointer;" @click="restartXrayService">{{ i18n "pages.index.restartXray" }}</a-tag>
<a-tag color="blue" @click="openSelectV2rayVersion">{{ i18n "pages.index.xraySwitch" }}</a-tag> <a-tag color="blue" style="cursor: pointer;" @click="openSelectV2rayVersion">{{ i18n "pages.index.xraySwitch" }}</a-tag>
</a-card> </a-card>
</a-col> </a-col>
<a-col :sm="24" :md="12"> <a-col :sm="24" :md="12">
<a-card hoverable :class="siderDrawer.isDarkTheme ? darkClass : ''"> <a-card hoverable :class="siderDrawer.isDarkTheme ? darkClass : ''">
{{ i18n "pages.index.operationHours" }}: {{ i18n "pages.index.operationHours" }}:
<a-tag color="#87d068">[[ formatSecond(status.uptime) ]]</a-tag> <a-tag color="green">[[ formatSecond(status.uptime) ]]</a-tag>
<a-tooltip> <a-tooltip>
<template slot="title"> <template slot="title">
{{ i18n "pages.index.operationHoursDesc" }} {{ i18n "pages.index.operationHoursDesc" }}

View File

@@ -571,3 +571,13 @@ func (s *InboundService) SearchClientTraffic(query string) (traffic *xray.Client
} }
return traffic, err return traffic, err
} }
func (s *InboundService) SearchInbounds(query string) ([]*model.Inbound, error) {
db := database.GetDB()
var inbounds []*model.Inbound
err := db.Model(model.Inbound{}).Preload("ClientStats").Where("remark like ?", "%"+query+"%").Find(&inbounds).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
return inbounds, nil
}

View File

@@ -105,8 +105,6 @@ func (t *Tgbot) OnReceive() {
} else { } else {
if update.Message.IsCommand() { if update.Message.IsCommand() {
t.answerCommand(update.Message, chatId, isAdmin) t.answerCommand(update.Message, chatId, isAdmin)
} else {
t.aswerChat(update.Message.Text, chatId, isAdmin)
} }
} }
} }
@@ -133,16 +131,18 @@ func (t *Tgbot) answerCommand(message *tgbotapi.Message, chatId int64, isAdmin b
} else { } else {
t.searchForClient(chatId, message.CommandArguments()) t.searchForClient(chatId, message.CommandArguments())
} }
case "inbound":
if isAdmin {
t.searchInbound(chatId, message.CommandArguments())
} else {
msg = "❗ Unknown command"
}
default: default:
msg = "❗ Unknown command" msg = "❗ Unknown command"
} }
t.SendAnswer(chatId, msg, isAdmin) t.SendAnswer(chatId, msg, isAdmin)
} }
func (t *Tgbot) aswerChat(message string, chatId int64, isAdmin bool) {
t.SendAnswer(chatId, "❗ Unknown message", isAdmin)
}
func (t *Tgbot) asnwerCallback(callbackQuery *tgbotapi.CallbackQuery, isAdmin bool) { func (t *Tgbot) asnwerCallback(callbackQuery *tgbotapi.CallbackQuery, isAdmin bool) {
// Respond to the callback query, telling Telegram to show the user // Respond to the callback query, telling Telegram to show the user
// a message with the data received. // a message with the data received.
@@ -165,7 +165,7 @@ func (t *Tgbot) asnwerCallback(callbackQuery *tgbotapi.CallbackQuery, isAdmin bo
case "client_commands": case "client_commands":
t.SendMsgToTgbot(callbackQuery.From.ID, "To search for statistics, just use folowing command:\r\n \r\n<code>/usage [UID|Passowrd]</code>\r\n \r\nUse UID for vmess and vless and Password for Trojan.") t.SendMsgToTgbot(callbackQuery.From.ID, "To search for statistics, just use folowing command:\r\n \r\n<code>/usage [UID|Passowrd]</code>\r\n \r\nUse UID for vmess and vless and Password for Trojan.")
case "commands": case "commands":
t.SendMsgToTgbot(callbackQuery.From.ID, "To search for a client email, just use folowing command:\r\n \r\n<code>/usage email</code>") t.SendMsgToTgbot(callbackQuery.From.ID, "Search for a client email:\r\n<code>/usage email</code>\r\n \r\nSearch for inbounds (with client stats):\r\n<code>/inbound [remark]</code>")
} }
} }
@@ -423,6 +423,45 @@ func (t *Tgbot) searchClient(chatId int64, email string) {
} }
} }
func (t *Tgbot) searchInbound(chatId int64, remark string) {
inbouds, err := t.inboundService.SearchInbounds(remark)
if err != nil {
logger.Warning(err)
msg := "❌ Something went wrong!"
t.SendMsgToTgbot(chatId, msg)
return
}
for _, inbound := range inbouds {
info := ""
info += fmt.Sprintf("📍Inbound:%s\r\nPort:%d\r\n", inbound.Remark, inbound.Port)
info += fmt.Sprintf("Traffic: %s (↑%s,↓%s)\r\n", common.FormatTraffic((inbound.Up + inbound.Down)), common.FormatTraffic(inbound.Up), common.FormatTraffic(inbound.Down))
if inbound.ExpiryTime == 0 {
info += "Expire date: ♾ Unlimited\r\n \r\n"
} else {
info += fmt.Sprintf("Expire date:%s\r\n \r\n", time.Unix((inbound.ExpiryTime/1000), 0).Format("2006-01-02 15:04:05"))
}
t.SendMsgToTgbot(chatId, info)
for _, traffic := range inbound.ClientStats {
expiryTime := ""
if traffic.ExpiryTime == 0 {
expiryTime = "♾Unlimited"
} else {
expiryTime = time.Unix((traffic.ExpiryTime / 1000), 0).Format("2006-01-02 15:04:05")
}
total := ""
if traffic.Total == 0 {
total = "♾Unlimited"
} else {
total = common.FormatTraffic((traffic.Total))
}
output := fmt.Sprintf("💡 Active: %t\r\n📧 Email: %s\r\n🔼 Upload↑: %s\r\n🔽 Download↓: %s\r\n🔄 Total: %s / %s\r\n📅 Expire in: %s\r\n",
traffic.Enable, traffic.Email, common.FormatTraffic(traffic.Up), common.FormatTraffic(traffic.Down), common.FormatTraffic((traffic.Up + traffic.Down)),
total, expiryTime)
t.SendMsgToTgbot(chatId, output)
}
}
}
func (t *Tgbot) searchForClient(chatId int64, query string) { func (t *Tgbot) searchForClient(chatId int64, query string) {
traffic, err := t.inboundService.SearchClientTraffic(query) traffic, err := t.inboundService.SearchClientTraffic(query)
if err != nil { if err != nil {
@@ -543,4 +582,10 @@ func (t *Tgbot) sendBackup(chatId int64) {
if err != nil { if err != nil {
logger.Warning("Error in uploading backup: ", err) logger.Warning("Error in uploading backup: ", err)
} }
file = tgbotapi.FilePath(xray.GetConfigPath())
msg = tgbotapi.NewDocument(chatId, file)
_, err = bot.Send(msg)
if err != nil {
logger.Warning("Error in uploading config.json: ", err)
}
} }

59
x-ui.sh
View File

@@ -20,46 +20,41 @@ function LOGI() {
# check root # check root
[[ $EUID -ne 0 ]] && LOGE "ERROR: You must be root to run this script! \n" && exit 1 [[ $EUID -ne 0 ]] && LOGE "ERROR: You must be root to run this script! \n" && exit 1
# check os # Check OS and set release variable
if [[ -f /etc/redhat-release ]]; then if [[ -f /etc/os-release ]]; then
release="centos" source /etc/os-release
elif cat /etc/issue | grep -Eqi "debian"; then release=$ID
release="debian" elif [[ -f /usr/lib/os-release ]]; then
elif cat /etc/issue | grep -Eqi "ubuntu"; then source /usr/lib/os-release
release="ubuntu" release=$ID
elif cat /etc/issue | grep -Eqi "centos|red hat|redhat"; then
release="centos"
elif cat /proc/version | grep -Eqi "debian"; then
release="debian"
elif cat /proc/version | grep -Eqi "ubuntu"; then
release="ubuntu"
elif cat /proc/version | grep -Eqi "centos|red hat|redhat"; then
release="centos"
else else
LOGE "check system OS failed,please contact with author! \n" && exit 1 echo "Failed to check the system OS, please contact the author!" >&2
exit 1
fi fi
echo "The OS release is: $release"
os_version="" os_version=""
os_version=$(grep -i version_id /etc/os-release | cut -d \" -f2 | cut -d . -f1)
# os version if [[ "${release}" == "centos" ]]; then
if [[ -f /etc/os-release ]]; then if [[ ${os_version} -lt 7 ]]; then
os_version=$(awk -F'[= ."]' '/VERSION_ID/{print $3}' /etc/os-release) echo -e "${red} Please use CentOS 7 or higher ${plain}\n" && exit 1
fi fi
if [[ -z "$os_version" && -f /etc/lsb-release ]]; then elif [[ "${release}" == "ubuntu" ]]; then
os_version=$(awk -F'[= ."]+' '/DISTRIB_RELEASE/{print $2}' /etc/lsb-release) if [[ ${os_version} -lt 18 ]]; then
fi echo -e "${red}please use Ubuntu 18 or higher version${plain}\n" && exit 1
fi
if [[ x"${release}" == x"centos" ]]; then elif [[ "${release}" == "fedora" ]]; then
if [[ ${os_version} -le 6 ]]; then if [[ ${os_version} -lt 36 ]]; then
LOGE "please use CentOS 7 or higher version! \n" && exit 1 echo -e "${red}please use Fedora 36 or higher version${plain}\n" && exit 1
fi fi
elif [[ x"${release}" == x"ubuntu" ]]; then
if [[ ${os_version} -lt 16 ]]; then elif [[ "${release}" == "debian" ]]; then
LOGE "please use Ubuntu 16 or higher version\n" && exit 1
fi
elif [[ x"${release}" == x"debian" ]]; then
if [[ ${os_version} -lt 8 ]]; then if [[ ${os_version} -lt 8 ]]; then
LOGE "please use Debian 8 or higher version\n" && exit 1 echo -e "${red} Please use Debian 8 or higher ${plain}\n" && exit 1
fi fi
fi fi