[tgbot] Big Updates

Added Notifications for Clients throught Tgbot (when Expire)
Added compability for Usernames both w/wo @
Added more buttons overall for admins
This commit is contained in:
somebodywashere 2023-12-24 23:42:32 +03:00
parent 3131542e5d
commit 60b3c87aa4
8 changed files with 248 additions and 135 deletions

View file

@ -1650,9 +1650,11 @@ func (s *InboundService) DelDepletedClients(id int) (err error) {
}
func (s *InboundService) GetClientTrafficTgBot(tguname string) ([]*xray.ClientTraffic, error) {
tguname = strings.Trim(tguname, "@")
tguname2 := "@" + tguname
db := database.GetDB()
var inbounds []*model.Inbound
err := db.Model(model.Inbound{}).Where("settings like ?", fmt.Sprintf(`%%"tgId": "%s"%%`, tguname)).Find(&inbounds).Error
err := db.Model(model.Inbound{}).Where("settings like ?", fmt.Sprintf(`%%"tgId": "%s"%%`, tguname)).Or("settings like ?", fmt.Sprintf(`%%"tgId": "%s"%%`, tguname2)).Find(&inbounds).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
@ -1665,6 +1667,8 @@ func (s *InboundService) GetClientTrafficTgBot(tguname string) ([]*xray.ClientTr
for _, client := range clients {
if client.TgID == tguname {
emails = append(emails, client.Email)
} else if client.TgID == tguname2 {
emails = append(emails, client.Email)
}
}
}

View file

@ -7,6 +7,7 @@ import (
"os"
"strconv"
"strings"
"slices"
"time"
"x-ui/config"
"x-ui/database"
@ -215,11 +216,7 @@ func (t *Tgbot) answerCommand(message *telego.Message, chatId int64, isAdmin boo
case "usage":
onlyMessage = true
if len(commandArgs) > 0 {
if isAdmin {
t.searchClient(chatId, commandArgs[0])
} else {
t.searchForClient(chatId, commandArgs[0])
}
t.searchClient(chatId, commandArgs[0], isAdmin)
} else {
msg += t.I18nBot("tgbot.commands.usage")
}
@ -259,13 +256,13 @@ func (t *Tgbot) asnwerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool
switch dataArray[0] {
case "client_get_usage":
t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.messages.email", "Email=="+email))
t.searchClient(chatId, email)
t.searchClient(chatId, email, isAdmin)
case "client_refresh":
t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.clientRefreshSuccess", "Email=="+email))
t.searchClient(chatId, email, callbackQuery.Message.MessageID)
t.searchClient(chatId, email, isAdmin, callbackQuery.Message.MessageID)
case "client_cancel":
t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.canceled", "Email=="+email))
t.searchClient(chatId, email, callbackQuery.Message.MessageID)
t.searchClient(chatId, email, isAdmin, callbackQuery.Message.MessageID)
case "ips_refresh":
t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.IpRefreshSuccess", "Email=="+email))
t.searchClientIps(chatId, email, callbackQuery.Message.MessageID)
@ -293,7 +290,7 @@ func (t *Tgbot) asnwerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool
if err == nil {
t.xrayService.SetToNeedRestart()
t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.resetTrafficSuccess", "Email=="+email))
t.searchClient(chatId, email, callbackQuery.Message.MessageID)
t.searchClient(chatId, email, isAdmin, callbackQuery.Message.MessageID)
} else {
t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
}
@ -336,13 +333,13 @@ func (t *Tgbot) asnwerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool
if err == nil {
t.xrayService.SetToNeedRestart()
t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.setTrafficLimitSuccess", "Email=="+email))
t.searchClient(chatId, email, callbackQuery.Message.MessageID)
t.searchClient(chatId, email, isAdmin, callbackQuery.Message.MessageID)
return
}
}
}
t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
t.searchClient(chatId, email, callbackQuery.Message.MessageID)
t.searchClient(chatId, email, isAdmin, callbackQuery.Message.MessageID)
case "limit_traffic_in":
if len(dataArray) >= 3 {
oldInputNumber, err := strconv.Atoi(dataArray[2])
@ -403,7 +400,7 @@ func (t *Tgbot) asnwerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool
}
}
t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
t.searchClient(chatId, email, callbackQuery.Message.MessageID)
t.searchClient(chatId, email, isAdmin, callbackQuery.Message.MessageID)
case "reset_exp":
inlineKeyboard := tu.InlineKeyboard(
tu.InlineKeyboardRow(
@ -465,13 +462,13 @@ func (t *Tgbot) asnwerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool
if err == nil {
t.xrayService.SetToNeedRestart()
t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.expireResetSuccess", "Email=="+email))
t.searchClient(chatId, email, callbackQuery.Message.MessageID)
t.searchClient(chatId, email, isAdmin, callbackQuery.Message.MessageID)
return
}
}
}
t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
t.searchClient(chatId, email, callbackQuery.Message.MessageID)
t.searchClient(chatId, email, isAdmin, callbackQuery.Message.MessageID)
case "reset_exp_in":
if len(dataArray) >= 3 {
oldInputNumber, err := strconv.Atoi(dataArray[2])
@ -532,7 +529,7 @@ func (t *Tgbot) asnwerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool
}
}
t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
t.searchClient(chatId, email, callbackQuery.Message.MessageID)
t.searchClient(chatId, email, isAdmin, callbackQuery.Message.MessageID)
case "ip_limit":
inlineKeyboard := tu.InlineKeyboard(
tu.InlineKeyboardRow(
@ -570,13 +567,13 @@ func (t *Tgbot) asnwerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool
if err == nil {
t.xrayService.SetToNeedRestart()
t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.resetIpSuccess", "Email=="+email, "Count=="+strconv.Itoa(count)))
t.searchClient(chatId, email, callbackQuery.Message.MessageID)
t.searchClient(chatId, email, isAdmin, callbackQuery.Message.MessageID)
return
}
}
}
t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
t.searchClient(chatId, email, callbackQuery.Message.MessageID)
t.searchClient(chatId, email, isAdmin, callbackQuery.Message.MessageID)
case "ip_limit_in":
if len(dataArray) >= 3 {
oldInputNumber, err := strconv.Atoi(dataArray[2])
@ -637,7 +634,7 @@ func (t *Tgbot) asnwerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool
}
}
t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
t.searchClient(chatId, email, callbackQuery.Message.MessageID)
t.searchClient(chatId, email, isAdmin, callbackQuery.Message.MessageID)
case "clear_ips":
inlineKeyboard := tu.InlineKeyboard(
tu.InlineKeyboardRow(
@ -704,7 +701,7 @@ func (t *Tgbot) asnwerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool
} else {
t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.disableSuccess", "Email=="+email))
}
t.searchClient(chatId, email, callbackQuery.Message.MessageID)
t.searchClient(chatId, email, isAdmin, callbackQuery.Message.MessageID)
} else {
t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
}
@ -722,7 +719,7 @@ func (t *Tgbot) asnwerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool
t.SendMsgToTgbot(chatId, t.getInboundUsages())
case "deplete_soon":
t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.depleteSoon"))
t.SendMsgToTgbot(chatId, t.getExhausted())
t.getExhausted(chatId)
case "get_backup":
t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.dbBackup"))
t.sendBackup(chatId)
@ -836,9 +833,15 @@ func (t *Tgbot) SendMsgToTgbot(chatId int64, msg string, replyMarkup ...telego.R
}
}
func (t *Tgbot) SendMsgToTgbotAdmins(msg string) {
for _, adminId := range adminIds {
t.SendMsgToTgbot(adminId, msg)
func (t *Tgbot) SendMsgToTgbotAdmins(msg string, replyMarkup ...telego.ReplyMarkup) {
if len(replyMarkup) > 0 {
for _, adminId := range adminIds {
t.SendMsgToTgbot(adminId, msg, replyMarkup[0])
}
} else {
for _, adminId := range adminIds {
t.SendMsgToTgbot(adminId, msg)
}
}
}
@ -854,8 +857,8 @@ func (t *Tgbot) SendReport() {
info := t.getServerUsage()
t.SendMsgToTgbotAdmins(info)
exhausted := t.getExhausted()
t.SendMsgToTgbotAdmins(exhausted)
t.sendExhaustedToAdmins()
t.notifyExhausted()
backupEnable, err := t.settingService.GetTgBotBackup()
if err == nil && backupEnable {
@ -872,6 +875,15 @@ func (t *Tgbot) SendBackupToAdmins() {
}
}
func (t *Tgbot) sendExhaustedToAdmins() {
if !t.IsRunning() {
return
}
for _, adminId := range adminIds {
t.getExhausted(int64(adminId))
}
}
func (t *Tgbot) getServerUsage() string {
info, ipv4, ipv6 := "", "", ""
info += t.I18nBot("tgbot.messages.hostname", "Hostname=="+hostname)
@ -972,7 +984,8 @@ func (t *Tgbot) getInboundUsages() string {
return info
}
func (t *Tgbot) clientInfoMsg(traffic *xray.ClientTraffic) string {
func (t *Tgbot) clientInfoMsg(traffic *xray.ClientTraffic, printEnabled bool, printOnline bool, printActive bool,
printDate bool, printTraffic bool, printRefreshed bool) string {
now := time.Now().Unix()
expiryTime := ""
@ -1027,18 +1040,30 @@ func (t *Tgbot) clientInfoMsg(traffic *xray.ClientTraffic) string {
output := ""
output += t.I18nBot("tgbot.messages.email", "Email=="+traffic.Email)
output += t.I18nBot("tgbot.messages.enabled", "Enable=="+enabled)
output += t.I18nBot("tgbot.messages.online", "Status=="+status)
output += t.I18nBot("tgbot.messages.active", "Enable=="+active)
if flag {
output += t.I18nBot("tgbot.messages.expireIn", "Time=="+expiryTime)
} else {
output += t.I18nBot("tgbot.messages.expire", "Time=="+expiryTime)
if printEnabled {
output += t.I18nBot("tgbot.messages.enabled", "Enable=="+enabled)
}
if printOnline {
output += t.I18nBot("tgbot.messages.online", "Status=="+status)
}
if printActive {
output += t.I18nBot("tgbot.messages.active", "Enable=="+active)
}
if printDate {
if flag {
output += t.I18nBot("tgbot.messages.expireIn", "Time=="+expiryTime)
} else {
output += t.I18nBot("tgbot.messages.expire", "Time=="+expiryTime)
}
}
if printTraffic {
output += t.I18nBot("tgbot.messages.upload", "Upload=="+common.FormatTraffic(traffic.Up))
output += t.I18nBot("tgbot.messages.download", "Download=="+common.FormatTraffic(traffic.Down))
output += t.I18nBot("tgbot.messages.total", "UpDown=="+common.FormatTraffic((traffic.Up+traffic.Down)), "Total=="+total)
}
if printRefreshed {
output += t.I18nBot("tgbot.messages.refreshedOn", "Time=="+time.Now().Format("2006-01-02 15:04:05"))
}
output += t.I18nBot("tgbot.messages.upload", "Upload=="+common.FormatTraffic(traffic.Up))
output += t.I18nBot("tgbot.messages.download", "Download=="+common.FormatTraffic(traffic.Down))
output += t.I18nBot("tgbot.messages.total", "UpDown=="+common.FormatTraffic((traffic.Up+traffic.Down)), "Total=="+total)
output += t.I18nBot("tgbot.messages.refreshedOn", "Time=="+time.Now().Format("2006-01-02 15:04:05"))
return output
}
@ -1057,24 +1082,24 @@ func (t *Tgbot) getClientUsage(chatId int64, tgUserName string, tgUserID string)
msg := t.I18nBot("tgbot.answers.askToAddUserId", "TgUserID=="+tgUserID)
t.SendMsgToTgbot(chatId, msg)
return
} else {
traffics, err := t.inboundService.GetClientTrafficTgBot(tgUserName)
if err != nil {
logger.Warning(err)
msg := t.I18nBot("tgbot.wentWrong")
t.SendMsgToTgbot(chatId, msg)
return
}
if len(traffics) == 0 {
msg := t.I18nBot("tgbot.answers.askToAddUserName", "TgUserName=="+tgUserName, "TgUserID=="+tgUserID)
t.SendMsgToTgbot(chatId, msg)
return
}
}
traffics, err = t.inboundService.GetClientTrafficTgBot(tgUserName)
}
if err != nil {
logger.Warning(err)
msg := t.I18nBot("tgbot.wentWrong")
t.SendMsgToTgbot(chatId, msg)
return
}
if len(traffics) == 0 {
msg := t.I18nBot("tgbot.answers.askToAddUserName", "TgUserName=="+tgUserName, "TgUserID=="+tgUserID)
t.SendMsgToTgbot(chatId, msg)
return
}
for _, traffic := range traffics {
output := t.clientInfoMsg(traffic)
t.SendMsgToTgbot(chatId, output)
t.searchClient(chatId, traffic.Email, false)
}
t.SendAnswer(chatId, t.I18nBot("tgbot.commands.pleaseChoose"), false)
}
@ -1158,7 +1183,7 @@ func (t *Tgbot) clientTelegramUserInfo(chatId int64, email string, messageID ...
}
}
func (t *Tgbot) searchClient(chatId int64, email string, messageID ...int) {
func (t *Tgbot) searchClient(chatId int64, email string, isAdmin bool, messageID ...int) {
traffic, err := t.inboundService.GetClientTrafficByEmail(email)
if err != nil {
logger.Warning(err)
@ -1172,35 +1197,38 @@ func (t *Tgbot) searchClient(chatId int64, email string, messageID ...int) {
return
}
output := t.clientInfoMsg(traffic)
inlineKeyboard := tu.InlineKeyboard(
tu.InlineKeyboardRow(
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.refresh")).WithCallbackData(t.encodeQuery("client_refresh "+email)),
),
tu.InlineKeyboardRow(
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.resetTraffic")).WithCallbackData(t.encodeQuery("reset_traffic "+email)),
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.limitTraffic")).WithCallbackData(t.encodeQuery("limit_traffic "+email)),
),
tu.InlineKeyboardRow(
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.resetExpire")).WithCallbackData(t.encodeQuery("reset_exp "+email)),
),
tu.InlineKeyboardRow(
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.ipLog")).WithCallbackData(t.encodeQuery("ip_log "+email)),
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.ipLimit")).WithCallbackData(t.encodeQuery("ip_limit "+email)),
),
tu.InlineKeyboardRow(
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.setTGUser")).WithCallbackData(t.encodeQuery("tg_user "+email)),
),
tu.InlineKeyboardRow(
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.toggle")).WithCallbackData(t.encodeQuery("toggle_enable "+email)),
),
)
if len(messageID) > 0 {
t.editMessageTgBot(chatId, messageID[0], output, inlineKeyboard)
output := t.clientInfoMsg(traffic, true, true, true, true, true, true)
if isAdmin {
inlineKeyboard := tu.InlineKeyboard(
tu.InlineKeyboardRow(
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.refresh")).WithCallbackData(t.encodeQuery("client_refresh "+email)),
),
tu.InlineKeyboardRow(
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.resetTraffic")).WithCallbackData(t.encodeQuery("reset_traffic "+email)),
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.limitTraffic")).WithCallbackData(t.encodeQuery("limit_traffic "+email)),
),
tu.InlineKeyboardRow(
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.resetExpire")).WithCallbackData(t.encodeQuery("reset_exp "+email)),
),
tu.InlineKeyboardRow(
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.ipLog")).WithCallbackData(t.encodeQuery("ip_log "+email)),
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.ipLimit")).WithCallbackData(t.encodeQuery("ip_limit "+email)),
),
tu.InlineKeyboardRow(
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.setTGUser")).WithCallbackData(t.encodeQuery("tg_user "+email)),
),
tu.InlineKeyboardRow(
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.toggle")).WithCallbackData(t.encodeQuery("toggle_enable "+email)),
),
)
if len(messageID) > 0 {
t.editMessageTgBot(chatId, messageID[0], output, inlineKeyboard)
} else {
t.SendMsgToTgbot(chatId, output, inlineKeyboard)
}
} else {
t.SendMsgToTgbot(chatId, output, inlineKeyboard)
t.SendMsgToTgbot(chatId, output)
}
}
@ -1231,34 +1259,17 @@ func (t *Tgbot) searchInbound(chatId int64, remark string) {
}
t.SendMsgToTgbot(chatId, info)
for _, traffic := range inbound.ClientStats {
output := t.clientInfoMsg(&traffic)
if len(inbound.ClientStats) > 0 {
output := ""
for _, traffic := range inbound.ClientStats {
output += t.clientInfoMsg(&traffic, true, true, true, true, true, true)
}
t.SendMsgToTgbot(chatId, output)
}
}
}
func (t *Tgbot) searchForClient(chatId int64, query string) {
traffic, err := t.inboundService.SearchClientTraffic(query)
if err != nil {
logger.Warning(err)
msg := t.I18nBot("tgbot.wentWrong")
t.SendMsgToTgbot(chatId, msg)
return
}
if traffic == nil {
msg := t.I18nBot("tgbot.noResult")
t.SendMsgToTgbot(chatId, msg)
return
}
output := t.clientInfoMsg(traffic)
t.SendMsgToTgbot(chatId, output)
}
func (t *Tgbot) getExhausted() string {
func (t *Tgbot) getExhausted(chatId int64) {
trDiff := int64(0)
exDiff := int64(0)
now := time.Now().Unix() * 1000
@ -1308,7 +1319,7 @@ func (t *Tgbot) getExhausted() string {
output += t.I18nBot("tgbot.messages.exhaustedCount", "Type=="+t.I18nBot("tgbot.inbounds"))
output += t.I18nBot("tgbot.messages.disabled", "Disabled=="+strconv.Itoa(len(disabledInbounds)))
output += t.I18nBot("tgbot.messages.depleteSoon", "Deplete=="+strconv.Itoa(len(exhaustedInbounds)))
output += "\r\n \r\n"
output += "\r\n"
if len(exhaustedInbounds) > 0 {
output += t.I18nBot("tgbot.messages.depleteSoon", "Deplete=="+t.I18nBot("tgbot.inbounds"))
@ -1322,26 +1333,113 @@ func (t *Tgbot) getExhausted() string {
} else {
output += t.I18nBot("tgbot.messages.expire", "Time=="+time.Unix((inbound.ExpiryTime/1000), 0).Format("2006-01-02 15:04:05"))
}
output += "\r\n \r\n"
output += "\r\n"
}
}
// Clients
exhaustedCC := len(exhaustedClients)
output += t.I18nBot("tgbot.messages.exhaustedCount", "Type=="+t.I18nBot("tgbot.clients"))
output += t.I18nBot("tgbot.messages.disabled", "Disabled=="+strconv.Itoa(len(disabledClients)))
output += t.I18nBot("tgbot.messages.depleteSoon", "Deplete=="+strconv.Itoa(len(exhaustedClients)))
output += "\r\n \r\n"
output += t.I18nBot("tgbot.messages.depleteSoon", "Deplete=="+strconv.Itoa(exhaustedCC))
output += "\r\n"
if len(exhaustedClients) > 0 {
if exhaustedCC > 0 {
output += t.I18nBot("tgbot.messages.depleteSoon", "Deplete=="+t.I18nBot("tgbot.clients"))
var buttons []telego.InlineKeyboardButton
for _, traffic := range exhaustedClients {
output += t.clientInfoMsg(&traffic)
output += "\r\n \r\n"
output += t.clientInfoMsg(&traffic, true, false, false, true, true, false)
output += "\r\n"
buttons = append(buttons, tu.InlineKeyboardButton(traffic.Email).WithCallbackData(t.encodeQuery("client_get_usage "+traffic.Email)))
}
cols := 0
if exhaustedCC < 11 {
cols = 1
} else {
cols = 2
}
output += t.I18nBot("tgbot.messages.refreshedOn", "Time=="+time.Now().Format("2006-01-02 15:04:05"))
t.SendMsgToTgbot(chatId, output, tu.InlineKeyboard(tu.InlineKeyboardCols(cols, buttons...)...))
} else {
output += t.I18nBot("tgbot.messages.refreshedOn", "Time=="+time.Now().Format("2006-01-02 15:04:05"))
t.SendMsgToTgbot(chatId, output)
}
}
func (t *Tgbot) notifyExhausted() {
trDiff := int64(0)
exDiff := int64(0)
now := time.Now().Unix() * 1000
var disabledClients []xray.ClientTraffic
var exhaustedClients []xray.ClientTraffic
TrafficThreshold, err := t.settingService.GetTrafficDiff()
if err == nil && TrafficThreshold > 0 {
trDiff = int64(TrafficThreshold) * 1073741824
}
ExpireThreshold, err := t.settingService.GetExpireDiff()
if err == nil && ExpireThreshold > 0 {
exDiff = int64(ExpireThreshold) * 86400000
}
inbounds, err := t.inboundService.GetAllInbounds()
if err != nil {
logger.Warning("Unable to load Inbounds", err)
}
return output
for _, inbound := range inbounds {
if inbound.Enable {
if len(inbound.ClientStats) > 0 {
clients, err := t.inboundService.GetClients(inbound)
if err == nil {
var chatIDsDone []int64
for _, client := range clients {
if client.TgID != "" {
//convert tgID to chatID (also convert if it's username)
chatID, err := strconv.ParseInt(client.TgID, 10, 64)
if err != nil {
chatID = tu.Username("@"+strings.Trim(client.TgID, "@")).ID
}
if !slices.Contains(chatIDsDone, chatID) {
traffics, err := t.inboundService.GetClientTrafficTgBot(client.TgID)
if err == nil {
output := t.I18nBot("tgbot.messages.exhaustedCount", "Type=="+t.I18nBot("tgbot.clients"))
for _, traffic := range traffics {
if traffic.Enable {
if (traffic.ExpiryTime > 0 && (traffic.ExpiryTime-now < exDiff)) ||
(traffic.Total > 0 && (traffic.Total-(traffic.Up+traffic.Down) < trDiff)) {
exhaustedClients = append(exhaustedClients, *traffic)
}
} else {
disabledClients = append(disabledClients, *traffic)
}
if len(exhaustedClients) > 0 {
output += t.I18nBot("tgbot.messages.disabled", "Disabled=="+strconv.Itoa(len(disabledClients)))
if len(disabledClients) > 0 {
output += t.I18nBot("tgbot.clients") + ":"
for _, traffic := range disabledClients {
output += " " + traffic.Email
}
output += "\r\n"
}
output += "\r\n"
output += t.I18nBot("tgbot.messages.depleteSoon", "Deplete=="+strconv.Itoa(len(exhaustedClients)))
for _, traffic := range exhaustedClients {
output += t.clientInfoMsg(&traffic, true, false, false, true, true, false)
output += "\r\n"
}
t.SendMsgToTgbot(chatID, output)
}
}
chatIDsDone = append(chatIDsDone, chatID)
}
}
}
}
}
}
}
}
}
func (t *Tgbot) onlineClients(chatId int64, messageID ...int) {
@ -1350,15 +1448,26 @@ func (t *Tgbot) onlineClients(chatId int64, messageID ...int) {
}
onlines := p.GetOnlineClients()
output := t.I18nBot("tgbot.messages.onlinesCount", "Count=="+fmt.Sprint(len(onlines)))
onlinesCount := len(onlines)
output := t.I18nBot("tgbot.messages.onlinesCount", "Count=="+fmt.Sprint(onlinesCount))
keyboard := tu.InlineKeyboard(tu.InlineKeyboardRow(
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.refresh")).WithCallbackData(t.encodeQuery("onlines_refresh"))))
if len(onlines) > 0 {
if onlinesCount > 0 {
var buttons []telego.InlineKeyboardButton
for _, online := range onlines {
keyboard.InlineKeyboard = append(keyboard.InlineKeyboard, tu.InlineKeyboardRow(
tu.InlineKeyboardButton(online).WithCallbackData(t.encodeQuery("client_get_usage "+online))))
buttons = append(buttons, tu.InlineKeyboardButton(online).WithCallbackData(t.encodeQuery("client_get_usage "+online)))
}
cols := 0
if onlinesCount < 21 {
cols = 2
} else if onlinesCount < 61 {
cols = 3
} else {
cols = 4
}
keyboard.InlineKeyboard = append(keyboard.InlineKeyboard, tu.InlineKeyboardCols(cols, buttons...)...)
}
if len(messageID) > 0 {

View file

@ -173,7 +173,7 @@
"setDefaultCert" = "Set Cert from Panel"
"xtlsDesc" = "Xray core needs to be 1.7.5"
"realityDesc" = "Xray core needs to be 1.8.0 or higher."
"telegramDesc" = "use Telegram ID without @ or chat IDs ( you can get it here @userinfobot or use '/id' command in bot )"
"telegramDesc" = "Use Telegram ID with or without @ or chat ID (you can get it here @userinfobot or use '/id' command in bot)"
"subscriptionDesc" = "you can find your sub link on Details, also you can use the same name for several configurations"
"info" = "Info"
"same" = "Same"
@ -459,7 +459,7 @@
"usage" = "❗ Please provide a text to search!"
"getID" = "🆔 Your ID: <code>{{ .ID }}</code>"
"helpAdminCommands" = "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>"
"helpClientCommands" = "To search for statistics, just use the following command:\r\n \r\n<code>/usage [UUID|Password]</code>\r\n \r\nUse UUID for vmess/vless and Password for Trojan."
"helpClientCommands" = "To search for statistics, just use the following command:\r\n \r\n<code>/usage [Email]</code>"
[tgbot.messages]
"cpuThreshold" = "🔴 CPU Load {{ .Percent }}% is more than threshold {{ .Threshold }}%"
@ -558,4 +558,4 @@
"enableSuccess" = "✅ {{ .Email }} : Enabled successfully."
"disableSuccess" = "✅ {{ .Email }} : Disabled successfully."
"askToAddUserId" = "Your configuration is not found!\r\nPlease ask your Admin to use your telegram user id in your configuration(s).\r\n\r\nYour user id: <b>{{ .TgUserID }}</b>"
"askToAddUserName" = "Your configuration is not found!\r\nPlease ask your Admin to use your telegram username or user id in your configuration(s).\r\n\r\nYour username: <b>@{{ .TgUserName }}</b>\r\n\r\nYour user id: <b>{{ .TgUserID }}</b>"
"askToAddUserName" = "Your configuration is not found!\r\nPlease ask your Admin to use your telegram username or user id in your configuration(s).\r\n\r\nYour username: <b>@{{ .TgUserName }}</b>\r\n\r\nYour user id: <code>{{ .TgUserID }}</code>"

View file

@ -173,7 +173,7 @@
"setDefaultCert" = "Establecer certificado desde el panel"
"xtlsDesc" = "La versión del núcleo de Xray debe ser 1.7.5"
"realityDesc" = "La versión del núcleo de Xray debe ser 1.8.0 o superior."
"telegramDesc" = "Utiliza el ID de Telegram sin @ o los IDs de chat (puedes obtenerlo aquí @userinfobot o usando el comando '/id' en el bot)."
"telegramDesc" = "Utiliza el ID de Telegram con o sin @ o los IDs de chat (puedes obtenerlo aquí @userinfobot o usando el comando '/id' en el bot)."
"subscriptionDesc" = "Puedes encontrar tu enlace de suscripción en Detalles, también puedes usar el mismo nombre para varias configuraciones."
"info" = "Info"
"same" = "misma"
@ -459,7 +459,7 @@
"usage" = "❗ ¡Por favor proporciona un texto para buscar!"
"getID" = "🆔 Tu ID: <code>{{ .ID }}</code>"
"helpAdminCommands" = "Buscar un correo electrónico de cliente:\r\n<code>/usage [Email]</code>\r\n \r\nBuscar entradas (con estadísticas de cliente):\r\n<code>/inbound [Nota]</code>"
"helpClientCommands" = "Para buscar estadísticas, simplemente usa el siguiente comando:\r\n \r\n<code>/usage [UUID|Contraseña]</code>\r\n \r\nUsa UUID para vmess/vless y Contraseña para Trojan."
"helpClientCommands" = "Para buscar estadísticas, simplemente usa el siguiente comando:\r\n \r\n<code>/usage [UUID|Contraseña]</code>"
[tgbot.messages]
"cpuThreshold" = "🔴 El uso de CPU {{ .Percent }}% es mayor que el umbral {{ .Threshold }}%"
@ -558,4 +558,4 @@
"enableSuccess" = "✅ {{ .Email }} : Habilitado exitosamente."
"disableSuccess" = "✅ {{ .Email }} : Deshabilitado exitosamente."
"askToAddUserId" = "¡No se encuentra su configuración!\r\nPor favor, pídale a su administrador que use su ID de usuario de Telegram en su(s) configuración(es).\r\n\r\nSu ID de usuario: <b>{{ .TgUserID }}</b>"
"askToAddUserName" = "¡No se encuentra su configuración!\r\nPor favor, pídale a su administrador que use su nombre de usuario o ID de usuario de Telegram en su(s) configuración(es).\r\n\r\nSu nombre de usuario: <b>@{{ .TgUserName }}</b>\r\n\r\nSu ID de usuario: <b>{{ .TgUserID }}</b>"
"askToAddUserName" = "¡No se encuentra su configuración!\r\nPor favor, pídale a su administrador que use su nombre de usuario o ID de usuario de Telegram en su(s) configuración(es).\r\n\r\nSu nombre de usuario: <b>@{{ .TgUserName }}</b>\r\n\r\nSu ID de usuario: <code>{{ .TgUserID }}</code>"

View file

@ -173,7 +173,7 @@
"setDefaultCert" = "استفاده از گواهی پنل"
"xtlsDesc" = "هسته Xray باید 1.7.5 باشد"
"realityDesc" = "هسته Xray باید 1.8.0 و بالاتر باشد"
"telegramDesc" = "از آیدی تلگرام بدون @ یا آیدی چت استفاده کنید (می توانید آن را از اینجا دریافت کنید @userinfobot یا در ربات دستور '/id' را وارد کنید)"
"telegramDesc" = "از آیدی تلگرام با یا بدون @ یا آیدی چت استفاده کنید (می توانید آن را از اینجا دریافت کنید @userinfobot یا در ربات دستور '/id' را وارد کنید)"
"subscriptionDesc" = "می توانید ساب لینک خود را در جزئیات پیدا کنید، همچنین می توانید از همین نام برای چندین کانفیگ استفاده کنید"
"info" = "اطلاعات"
"same" = "همسان"
@ -459,7 +459,7 @@
"usage" = "❗ لطفاً یک متن برای جستجو وارد کنید!"
"getID" = "🆔 شناسه شما: <code>{{ .ID }}</code>"
"helpAdminCommands" = "برای جستجوی ایمیل مشتری:\r\n<code>/usage [ایمیل]</code>\r\n \r\nبرای جستجوی ورودی‌ها (با آمار مشتری):\r\n<code>/inbound [توضیح]</code>"
"helpClientCommands" = "برای جستجوی آمار، فقط از دستور زیر استفاده کنید:\r\n \r\n<code>/usage [UUID|رمز عبور]</code>\r\n \r\nاز UUID برای vmess/vless و از رمز عبور برای Trojan استفاده کنید."
"helpClientCommands" = "برای جستجوی آمار، فقط از دستور زیر استفاده کنید:\r\n \r\n<code>/usage [Email]</code>"
[tgbot.messages]
"cpuThreshold" = "🔴 میزان استفاده از CPU {{ .Percent }}% بیشتر از آستانه {{ .Threshold }}% است."
@ -558,4 +558,4 @@
"enableSuccess" = "✅ {{ .Email }} : با موفقیت فعال شد."
"disableSuccess" = "✅ {{ .Email }} : با موفقیت غیرفعال شد."
"askToAddUserId" = "پیکربندی شما یافت نشد!\r\nلطفاً از مدیر خود بخواهید که شناسه کاربر تلگرام خود را در پیکربندی (های) خود استفاده کند.\r\n\r\nشناسه کاربری شما: <b>{{ .TgUserID }}</b>"
"askToAddUserName" = "پیکربندی شما یافت نشد!\r\nلطفاً از مدیر خود بخواهید که نام کاربری یا شناسه کاربر تلگرام خود را در پیکربندی (های) خود استفاده کند.\r\n\r\nنام کاربری شما: <b>@{{ .TgUserName }}</b>\r\n\r\nشناسه کاربری شما: <b>{{ .TgUserID }}</b>"
"askToAddUserName" = "پیکربندی شما یافت نشد!\r\nلطفاً از مدیر خود بخواهید که نام کاربری یا شناسه کاربر تلگرام خود را در پیکربندی (های) خود استفاده کند.\r\n\r\nنام کاربری شما: <b>@{{ .TgUserName }}</b>\r\n\r\nشناسه کاربری شما: <code>{{ .TgUserID }}</code>"

View file

@ -173,7 +173,7 @@
"setDefaultCert" = "Установить сертификат с панели"
"xtlsDesc" = "Версия Xray должна быть не ниже 1.7.5"
"realityDesc" = "Версия Xray должна быть не ниже 1.8.0"
"telegramDesc" = "Используйте идентификатор Telegram без символа @ или идентификатора чата (можно получить его здесь @userinfobot или использовать команду '/id' в боте)"
"telegramDesc" = "Используйте имя пользователя Telegram с или без @ или ID чата (можно получить его здесь @userinfobot или использовать команду '/id' в боте)"
"subscriptionDesc" = "Вы можете найти свою ссылку подписки в разделе 'Подробнее', также вы можете использовать одно и то же имя для нескольких конфигураций"
"info" = "Информация"
"same" = "Тот же"
@ -459,7 +459,7 @@
"usage" = "❗ Пожалуйста, укажите текст для поиска!"
"getID" = "🆔 Ваш ID: <code>{{ .ID }}</code>"
"helpAdminCommands" = "Поиск по электронной почте клиента:\r\n<code>/usage [Email]</code>\r\n \r\nПоиск входящих соединений (со статистикой клиента):\r\n<code>/inbound [Remark]</code>"
"helpClientCommands" = "Для получения статистики используйте следующую команду:\r\n \r\n<code>/usage [UUID|Password]</code>\r\n \r\nИспользуйте UUID для vmess/vless и пароль для Trojan."
"helpClientCommands" = "Для получения статистики используйте следующую команду:\r\n \r\n<code>/usage [Email]</code>"
[tgbot.messages]
"cpuThreshold" = "🔴 Загрузка процессора составляет {{ .Percent }}%, что превышает пороговое значение {{ .Threshold }}%"
@ -558,4 +558,4 @@
"enableSuccess" = "✅ {{ .Email }}: Включено успешно."
"disableSuccess" = "✅ {{ .Email }}: Отключено успешно."
"askToAddUserId" = "Ваша конфигурация не найдена!\r\nПожалуйста, попросите администратора использовать ваш идентификатор пользователя Telegram в ваших конфигурациях.\r\n\r\nВаш идентификатор пользователя: <b>{{ .TgUserID }}</b>"
"askToAddUserName" = "Ваша конфигурация не найдена!\r\nПожалуйста, попросите администратора использовать ваше имя пользователя или идентификатор пользователя Telegram в ваших конфигурациях.\r\n\r\nВаше имя пользователя: <b>@{{ .TgUserName }}</b>\r\n\r\nВаш идентификатор пользователя: <b>{{ .TgUserID }}</b>"
"askToAddUserName" = "Ваша конфигурация не найдена!\r\nПожалуйста, попросите администратора использовать ваше имя пользователя или идентификатор пользователя Telegram в ваших конфигурациях.\r\n\r\nВаше имя пользователя: <b>@{{ .TgUserName }}</b>\r\n\r\nВаш идентификатор пользователя: <code>{{ .TgUserID }}</code>"

View file

@ -173,7 +173,7 @@
"setDefaultCert" = "Đặt chứng chỉ từ bảng điều khiển"
"xtlsDesc" = "Xray core cần phiên bản 1.7.5"
"realityDesc" = "Xray core cần phiên bản 1.8.0 hoặc cao hơn."
"telegramDesc" = "Sử dụng Telegram ID mà không cần ký hiệu @ hoặc chat IDs (bạn có thể nhận được nó ở đây @userinfobot hoặc sử dụng lệnh '/id' trong bot)"
"telegramDesc" = "Sử dụng ID Telegram có hoặc không có @ hoặc chat IDs (bạn có thể nhận được nó ở đây @userinfobot hoặc sử dụng lệnh '/id' trong bot)"
"subscriptionDesc" = "Bạn có thể tìm liên kết đăng ký của mình trong Chi tiết, cũng như bạn có thể sử dụng cùng tên cho nhiều cấu hình khác nhau"
"info" = "Thông tin"
"same" = "Giống nhau"
@ -459,7 +459,7 @@
"usage" = "❗ Vui lòng cung cấp văn bản để tìm kiếm!"
"getID" = "🆔 ID của bạn: <code>{{ .ID }}</code>"
"helpAdminCommands" = "Tìm kiếm email của khách hàng:\r\n<code>/usage [Email]</code>\r\n \r\nTìm kiếm inbounds (với thống kê của khách hàng):\r\n<code>/inbound [Ghi chú]</code>"
"helpClientCommands" = "Để tìm kiếm thống kê, hãy sử dụng lệnh sau:\r\n \r\n<code>/usage [UUID|Mật khẩu]</code>\r\n \r\nSử dụng UUID cho vmess/vless và Mật khẩu cho Trojan."
"helpClientCommands" = "Để tìm kiếm thống kê, hãy sử dụng lệnh sau:\r\n \r\n<code>/usage [Email]</code>"
[tgbot.messages]
"cpuThreshold" = "🔴 Sử dụng CPU {{ .Percent }}% vượt quá ngưỡng {{ .Threshold }}%"
@ -558,4 +558,4 @@
"enableSuccess" = "✅ {{ .Email }} : Đã Bật Thành Công."
"disableSuccess" = "✅ {{ .Email }} : Đã Tắt Thành Công."
"askToAddUserId" = "Cấu hình của bạn không được tìm thấy!\r\nVui lòng yêu cầu Quản trị viên sử dụng ID người dùng telegram của bạn trong cấu hình của bạn.\r\n\r\nID người dùng của bạn: <b>{{ .TgUserID }}</b>"
"askToAddUserName" = "Cấu hình của bạn không được tìm thấy!\r\nVui lòng yêu cầu Quản trị viên sử dụng tên người dùng hoặc ID người dùng telegram của bạn trong cấu hình của bạn.\r\n\r\nTên người dùng của bạn: <b>@{{ .TgUserName }}</b>\r\n\r\nID người dùng của bạn: <b>{{ .TgUserID }}</b>"
"askToAddUserName" = "Cấu hình của bạn không được tìm thấy!\r\nVui lòng yêu cầu Quản trị viên sử dụng tên người dùng hoặc ID người dùng telegram của bạn trong cấu hình của bạn.\r\n\r\nTên người dùng của bạn: <b>@{{ .TgUserName }}</b>\r\n\r\nID người dùng của bạn: <code>{{ .TgUserID }}</code>"

View file

@ -173,7 +173,7 @@
"setDefaultCert" = "从面板设置证书"
"xtlsDesc" = "Xray核心需要1.7.5"
"realityDesc" = "Xray核心需要1.8.0及以上版本"
"telegramDesc" = "使用 Telegram ID,不包含 @ 符号或聊天 ID可以在 @userinfobot 处获取,或在机器人中使用'/id'命令)"
"telegramDesc" = "使用 Telegram ID(带或不带 @ 符号或聊天 ID可以在 @userinfobot 处获取,或在机器人中使用'/id'命令)"
"subscriptionDesc" = "您可以在详细信息上找到您的子链接,也可以对多个配置使用相同的名称"
"info" = "信息"
"same" = "相同"
@ -459,7 +459,7 @@
"usage" = "❗ 请输入要搜索的文本!"
"getID" = "🆔 您的ID为<code>{{ .ID }}</code>"
"helpAdminCommands" = "搜索客户端邮箱:\r\n<code>/usage [Email]</code>\r\n \r\n搜索入站连接包含客户端统计信息\r\n<code>/inbound [Remark]</code>"
"helpClientCommands" = "要搜索统计信息,请使用以下命令:\r\n \r\n<code>/usage [UUID|Password]</code>\r\n \r\n对于vmess/vless请使用UUID对于Trojan请使用密码。"
"helpClientCommands" = "要搜索统计信息,请使用以下命令:\r\n \r\n<code>/usage [Email]</code>"
[tgbot.messages]
"cpuThreshold" = "🔴 CPU 使用率为 {{ .Percent }}%,超过阈值 {{ .Threshold }}%"
@ -558,4 +558,4 @@
"enableSuccess" = "✅ {{ .Email }}:已成功启用。"
"disableSuccess" = "✅ {{ .Email }}:已成功禁用。"
"askToAddUserId" = "未找到您的配置!\r\n请向管理员询问在您的配置中使用您的 Telegram 用户ID。\r\n\r\n您的用户ID<b>{{ .TgUserID }}</b>"
"askToAddUserName" = "未找到您的配置!\r\n请向管理员询问在您的配置中使用您的 Telegram 用户名或用户ID。\r\n\r\n您的用户名<b>@{{ .TgUserName }}</b>\r\n\r\n您的用户ID<b>{{ .TgUserID }}</b>"
"askToAddUserName" = "未找到您的配置!\r\n请向管理员询问在您的配置中使用您的 Telegram 用户名或用户ID。\r\n\r\n您的用户名<b>@{{ .TgUserName }}</b>\r\n\r\n您的用户ID<code>{{ .TgUserID }}</code>"