2023-03-17 19:07:49 +03:00
package service
import (
"fmt"
"net"
"os"
"strconv"
"strings"
"time"
"x-ui/config"
"x-ui/database/model"
"x-ui/logger"
"x-ui/util/common"
"x-ui/xray"
2023-05-14 18:20:01 +03:00
"github.com/mymmrac/telego"
th "github.com/mymmrac/telego/telegohandler"
tu "github.com/mymmrac/telego/telegoutil"
2023-03-17 19:07:49 +03:00
)
2023-05-14 18:20:01 +03:00
var bot * telego . Bot
var botHandler * th . BotHandler
2023-03-17 19:07:49 +03:00
var adminIds [ ] int64
var isRunning bool
type LoginStatus byte
const (
LoginSuccess LoginStatus = 1
LoginFail LoginStatus = 0
)
type Tgbot struct {
inboundService InboundService
settingService SettingService
serverService ServerService
2023-05-05 02:17:26 +03:00
xrayService XrayService
2023-03-17 19:07:49 +03:00
lastStatus * Status
}
func ( t * Tgbot ) NewTgbot ( ) * Tgbot {
return new ( Tgbot )
}
func ( t * Tgbot ) Start ( ) error {
tgBottoken , err := t . settingService . GetTgBotToken ( )
if err != nil || tgBottoken == "" {
logger . Warning ( "Get TgBotToken failed:" , err )
return err
}
tgBotid , err := t . settingService . GetTgBotChatId ( )
if err != nil {
logger . Warning ( "Get GetTgBotChatId failed:" , err )
return err
}
for _ , adminId := range strings . Split ( tgBotid , "," ) {
id , err := strconv . Atoi ( adminId )
if err != nil {
logger . Warning ( "Failed to get IDs from GetTgBotChatId:" , err )
return err
}
adminIds = append ( adminIds , int64 ( id ) )
}
2023-05-14 18:20:01 +03:00
bot , err = telego . NewBot ( tgBottoken )
2023-03-17 19:07:49 +03:00
if err != nil {
fmt . Println ( "Get tgbot's api error:" , err )
return err
}
// listen for TG bot income messages
if ! isRunning {
logger . Info ( "Starting Telegram receiver ..." )
go t . OnReceive ( )
isRunning = true
}
return nil
}
func ( t * Tgbot ) IsRunnging ( ) bool {
return isRunning
}
func ( t * Tgbot ) Stop ( ) {
2023-05-14 18:20:01 +03:00
botHandler . Stop ( )
bot . StopLongPolling ( )
2023-03-17 19:07:49 +03:00
logger . Info ( "Stop Telegram receiver ..." )
isRunning = false
adminIds = nil
}
func ( t * Tgbot ) OnReceive ( ) {
2023-05-14 18:20:01 +03:00
params := telego . GetUpdatesParams {
Timeout : 10 ,
2023-03-17 19:07:49 +03:00
}
2023-05-14 18:20:01 +03:00
updates , _ := bot . UpdatesViaLongPolling ( & params )
botHandler , _ = th . NewBotHandler ( bot , updates )
2023-05-14 21:37:49 +03:00
botHandler . HandleMessage ( func ( bot * telego . Bot , message telego . Message ) {
t . SendMsgToTgbot ( message . Chat . ID , "Custom Keyboard Closed!" , tu . ReplyKeyboardRemove ( ) )
} , th . TextEqual ( "❌ Close Keyboard" ) )
2023-05-14 18:20:01 +03:00
botHandler . HandleMessage ( func ( bot * telego . Bot , message telego . Message ) {
t . answerCommand ( & message , message . Chat . ID , checkAdmin ( message . From . ID ) )
} , th . AnyCommand ( ) )
botHandler . HandleCallbackQuery ( func ( bot * telego . Bot , query telego . CallbackQuery ) {
t . asnwerCallback ( & query , checkAdmin ( query . From . ID ) )
} , th . AnyCallbackQueryWithMessage ( ) )
2023-05-14 21:37:49 +03:00
botHandler . HandleMessage ( func ( bot * telego . Bot , message telego . Message ) {
if message . UserShared != nil {
if checkAdmin ( message . From . ID ) {
err := t . inboundService . SetClientTelegramUserID ( message . UserShared . RequestID , strconv . FormatInt ( message . UserShared . UserID , 10 ) )
var output string
if err != nil {
output = "❌ Error in user selection!"
} else {
output = "✅ Telegram User saved."
}
t . SendMsgToTgbot ( message . Chat . ID , output , tu . ReplyKeyboardRemove ( ) )
} else {
t . SendMsgToTgbot ( message . Chat . ID , "No result!" , tu . ReplyKeyboardRemove ( ) )
}
}
} , th . AnyMessage ( ) )
2023-05-14 18:20:01 +03:00
botHandler . Start ( )
2023-03-17 19:07:49 +03:00
}
2023-05-14 18:20:01 +03:00
func ( t * Tgbot ) answerCommand ( message * telego . Message , chatId int64 , isAdmin bool ) {
2023-03-17 19:07:49 +03:00
msg := ""
2023-05-14 18:20:01 +03:00
command , commandArgs := tu . ParseCommand ( message . Text )
2023-03-17 19:07:49 +03:00
// Extract the command from the Message.
2023-05-14 18:20:01 +03:00
switch command {
2023-03-17 19:07:49 +03:00
case "help" :
msg = "This bot is providing you some specefic data from the server.\n\n Please choose:"
case "start" :
msg = "Hello <i>" + message . From . FirstName + "</i> 👋"
if isAdmin {
hostname , _ := os . Hostname ( )
msg += "\nWelcome to <b>" + hostname + "</b> management bot"
}
msg += "\n\nI can do some magics for you, please choose:"
case "status" :
msg = "bot is ok ✅"
case "usage" :
2023-05-14 18:20:01 +03:00
if len ( commandArgs ) > 0 {
2023-03-24 16:10:56 +03:00
if isAdmin {
2023-05-14 18:20:01 +03:00
t . searchClient ( chatId , commandArgs [ 0 ] )
2023-03-24 16:10:56 +03:00
} else {
2023-05-14 18:20:01 +03:00
t . searchForClient ( chatId , commandArgs [ 0 ] )
2023-03-24 16:10:56 +03:00
}
2023-03-17 19:07:49 +03:00
} else {
2023-03-24 16:10:56 +03:00
msg = "❗Please provide a text for search!"
2023-03-17 19:07:49 +03:00
}
2023-03-24 16:44:26 +03:00
case "inbound" :
2023-05-14 18:20:01 +03:00
if isAdmin && len ( commandArgs ) > 0 {
t . searchInbound ( chatId , commandArgs [ 0 ] )
2023-03-24 16:44:26 +03:00
} else {
msg = "❗ Unknown command"
}
2023-03-17 19:07:49 +03:00
default :
msg = "❗ Unknown command"
}
t . SendAnswer ( chatId , msg , isAdmin )
}
2023-05-14 18:20:01 +03:00
func ( t * Tgbot ) asnwerCallback ( callbackQuery * telego . CallbackQuery , isAdmin bool ) {
chatId := callbackQuery . Message . Chat . ID
2023-05-05 00:46:43 +03:00
if isAdmin {
dataArray := strings . Split ( callbackQuery . Data , " " )
if len ( dataArray ) >= 2 && len ( dataArray [ 1 ] ) > 0 {
email := dataArray [ 1 ]
switch dataArray [ 0 ] {
2023-05-05 17:50:56 +03:00
case "client_refresh" :
2023-05-14 22:13:23 +03:00
t . sendCallbackAnswerTgBot ( callbackQuery . ID , fmt . Sprintf ( "✅ %s : Client refreshed successfully." , email ) )
2023-05-14 18:20:01 +03:00
t . searchClient ( chatId , email , callbackQuery . Message . MessageID )
2023-05-05 17:50:56 +03:00
case "client_cancel" :
2023-05-05 00:46:43 +03:00
t . sendCallbackAnswerTgBot ( callbackQuery . ID , fmt . Sprintf ( "❌ %s : Operation canceled." , email ) )
2023-05-14 18:20:01 +03:00
t . searchClient ( chatId , email , callbackQuery . Message . MessageID )
2023-05-05 17:50:56 +03:00
case "ips_refresh" :
2023-05-14 22:13:23 +03:00
t . sendCallbackAnswerTgBot ( callbackQuery . ID , fmt . Sprintf ( "✅ %s : IPs refreshed successfully." , email ) )
2023-05-14 18:20:01 +03:00
t . searchClientIps ( chatId , email , callbackQuery . Message . MessageID )
2023-05-05 17:50:56 +03:00
case "ips_cancel" :
t . sendCallbackAnswerTgBot ( callbackQuery . ID , fmt . Sprintf ( "❌ %s : Operation canceled." , email ) )
2023-05-14 18:20:01 +03:00
t . searchClientIps ( chatId , email , callbackQuery . Message . MessageID )
2023-05-14 22:13:23 +03:00
case "tgid_refresh" :
t . sendCallbackAnswerTgBot ( callbackQuery . ID , fmt . Sprintf ( "✅ %s : Client's Telegram User refreshed successfully." , email ) )
t . clientTelegramUserInfo ( chatId , email , callbackQuery . Message . MessageID )
case "tgid_cancel" :
t . sendCallbackAnswerTgBot ( callbackQuery . ID , fmt . Sprintf ( "❌ %s : Operation canceled." , email ) )
t . clientTelegramUserInfo ( chatId , email , callbackQuery . Message . MessageID )
2023-05-05 00:46:43 +03:00
case "reset_traffic" :
2023-05-14 18:20:01 +03:00
inlineKeyboard := tu . InlineKeyboard (
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "❌ Cancel Reset" ) . WithCallbackData ( "client_cancel " + email ) ,
2023-05-05 00:46:43 +03:00
) ,
2023-05-14 18:20:01 +03:00
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "✅ Confirm Reset Traffic?" ) . WithCallbackData ( "reset_traffic_c " + email ) ,
2023-05-05 00:46:43 +03:00
) ,
)
2023-05-14 18:20:01 +03:00
t . editMessageCallbackTgBot ( chatId , callbackQuery . Message . MessageID , inlineKeyboard )
2023-05-05 15:32:16 +03:00
case "reset_traffic_c" :
2023-05-05 04:04:39 +03:00
err := t . inboundService . ResetClientTrafficByEmail ( email )
if err == nil {
2023-05-05 02:17:26 +03:00
t . xrayService . SetToNeedRestart ( )
t . sendCallbackAnswerTgBot ( callbackQuery . ID , fmt . Sprintf ( "✅ %s : Traffic reset successfully." , email ) )
2023-05-14 18:20:01 +03:00
t . searchClient ( chatId , email , callbackQuery . Message . MessageID )
2023-05-05 02:17:26 +03:00
} else {
t . sendCallbackAnswerTgBot ( callbackQuery . ID , "❗ Error in Operation." )
}
2023-05-05 15:32:16 +03:00
case "reset_exp" :
2023-05-14 18:20:01 +03:00
var inlineKeyboard = tu . InlineKeyboard (
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "❌ Cancel Reset" ) . WithCallbackData ( "client_cancel " + email ) ,
2023-05-05 00:46:43 +03:00
) ,
2023-05-14 18:20:01 +03:00
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "♾ Unlimited" ) . WithCallbackData ( "reset_exp_c " + email + " 0" ) ,
2023-05-05 01:18:37 +03:00
) ,
2023-05-14 18:20:01 +03:00
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "1 Month" ) . WithCallbackData ( "reset_exp_c " + email + " 30" ) ,
tu . InlineKeyboardButton ( "2 Months" ) . WithCallbackData ( "reset_exp_c " + email + " 60" ) ,
2023-05-05 00:46:43 +03:00
) ,
2023-05-14 18:20:01 +03:00
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "3 Months" ) . WithCallbackData ( "reset_exp_c " + email + " 90" ) ,
tu . InlineKeyboardButton ( "6 Months" ) . WithCallbackData ( "reset_exp_c " + email + " 180" ) ,
2023-05-05 00:46:43 +03:00
) ,
2023-05-14 18:20:01 +03:00
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "9 Months" ) . WithCallbackData ( "reset_exp_c " + email + " 270" ) ,
tu . InlineKeyboardButton ( "12 Months" ) . WithCallbackData ( "reset_exp_c " + email + " 360" ) ,
2023-05-05 00:46:43 +03:00
) ,
2023-05-14 18:20:01 +03:00
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "10 Days" ) . WithCallbackData ( "reset_exp_c " + email + " 10" ) ,
tu . InlineKeyboardButton ( "20 Days" ) . WithCallbackData ( "reset_exp_c " + email + " 20" ) ,
2023-05-05 00:46:43 +03:00
) ,
)
2023-05-14 18:20:01 +03:00
t . editMessageCallbackTgBot ( chatId , callbackQuery . Message . MessageID , inlineKeyboard )
2023-05-05 15:32:16 +03:00
case "reset_exp_c" :
2023-05-05 04:04:39 +03:00
if len ( dataArray ) == 3 {
days , err := strconv . Atoi ( dataArray [ 2 ] )
if err == nil {
2023-05-05 01:18:37 +03:00
var date int64 = 0
if days > 0 {
date = int64 ( - ( days * 24 * 60 * 60000 ) )
}
2023-05-05 04:04:39 +03:00
err := t . inboundService . ResetClientExpiryTimeByEmail ( email , date )
if err == nil {
2023-05-05 02:17:26 +03:00
t . xrayService . SetToNeedRestart ( )
t . sendCallbackAnswerTgBot ( callbackQuery . ID , fmt . Sprintf ( "✅ %s : Expire days reset successfully." , email ) )
2023-05-14 18:20:01 +03:00
t . searchClient ( chatId , email , callbackQuery . Message . MessageID )
2023-05-05 04:04:39 +03:00
return
2023-05-05 02:17:26 +03:00
}
2023-05-05 00:46:43 +03:00
}
}
2023-05-05 04:04:39 +03:00
t . sendCallbackAnswerTgBot ( callbackQuery . ID , "❗ Error in Operation." )
2023-05-14 18:20:01 +03:00
t . searchClient ( chatId , email , callbackQuery . Message . MessageID )
2023-05-05 17:50:56 +03:00
case "ip_limit" :
2023-05-14 18:20:01 +03:00
inlineKeyboard := tu . InlineKeyboard (
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "❌ Cancel IP Limit" ) . WithCallbackData ( "client_cancel " + email ) ,
2023-05-05 17:50:56 +03:00
) ,
2023-05-14 18:20:01 +03:00
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "♾ Unlimited" ) . WithCallbackData ( "ip_limit_c " + email + " 0" ) ,
2023-05-05 17:50:56 +03:00
) ,
2023-05-14 18:20:01 +03:00
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "1" ) . WithCallbackData ( "ip_limit_c " + email + " 1" ) ,
tu . InlineKeyboardButton ( "2" ) . WithCallbackData ( "ip_limit_c " + email + " 2" ) ,
2023-05-05 17:50:56 +03:00
) ,
2023-05-14 18:20:01 +03:00
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "3" ) . WithCallbackData ( "ip_limit_c " + email + " 3" ) ,
tu . InlineKeyboardButton ( "4" ) . WithCallbackData ( "ip_limit_c " + email + " 4" ) ,
2023-05-05 17:50:56 +03:00
) ,
2023-05-14 18:20:01 +03:00
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "5" ) . WithCallbackData ( "ip_limit_c " + email + " 5" ) ,
tu . InlineKeyboardButton ( "6" ) . WithCallbackData ( "ip_limit_c " + email + " 6" ) ,
tu . InlineKeyboardButton ( "7" ) . WithCallbackData ( "ip_limit_c " + email + " 7" ) ,
2023-05-05 17:50:56 +03:00
) ,
2023-05-14 18:20:01 +03:00
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "8" ) . WithCallbackData ( "ip_limit_c " + email + " 8" ) ,
tu . InlineKeyboardButton ( "9" ) . WithCallbackData ( "ip_limit_c " + email + " 9" ) ,
tu . InlineKeyboardButton ( "10" ) . WithCallbackData ( "ip_limit_c " + email + " 10" ) ,
2023-05-05 17:50:56 +03:00
) ,
)
2023-05-14 18:20:01 +03:00
t . editMessageCallbackTgBot ( chatId , callbackQuery . Message . MessageID , inlineKeyboard )
2023-05-05 17:50:56 +03:00
case "ip_limit_c" :
if len ( dataArray ) == 3 {
count , err := strconv . Atoi ( dataArray [ 2 ] )
if err == nil {
err := t . inboundService . ResetClientIpLimitByEmail ( email , count )
if err == nil {
t . xrayService . SetToNeedRestart ( )
t . sendCallbackAnswerTgBot ( callbackQuery . ID , fmt . Sprintf ( "✅ %s : IP limit %d saved successfully." , email , count ) )
2023-05-14 18:20:01 +03:00
t . searchClient ( chatId , email , callbackQuery . Message . MessageID )
2023-05-05 17:50:56 +03:00
return
}
}
}
t . sendCallbackAnswerTgBot ( callbackQuery . ID , "❗ Error in Operation." )
2023-05-14 18:20:01 +03:00
t . searchClient ( chatId , email , callbackQuery . Message . MessageID )
2023-05-05 17:50:56 +03:00
case "clear_ips" :
2023-05-14 18:20:01 +03:00
inlineKeyboard := tu . InlineKeyboard (
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "❌ Cancel" ) . WithCallbackData ( "ips_cancel " + email ) ,
2023-05-05 17:50:56 +03:00
) ,
2023-05-14 18:20:01 +03:00
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "✅ Confirm Clear IPs?" ) . WithCallbackData ( "clear_ips_c " + email ) ,
2023-05-05 17:50:56 +03:00
) ,
)
2023-05-14 18:20:01 +03:00
t . editMessageCallbackTgBot ( chatId , callbackQuery . Message . MessageID , inlineKeyboard )
2023-05-05 17:50:56 +03:00
case "clear_ips_c" :
err := t . inboundService . ClearClientIps ( email )
if err == nil {
t . sendCallbackAnswerTgBot ( callbackQuery . ID , fmt . Sprintf ( "✅ %s : IPs cleared successfully." , email ) )
2023-05-14 18:20:01 +03:00
t . searchClientIps ( chatId , email , callbackQuery . Message . MessageID )
2023-05-05 17:50:56 +03:00
} else {
t . sendCallbackAnswerTgBot ( callbackQuery . ID , "❗ Error in Operation." )
}
case "ip_log" :
2023-05-05 19:37:47 +03:00
t . sendCallbackAnswerTgBot ( callbackQuery . ID , fmt . Sprintf ( "✅ %s : Get IP Log." , email ) )
2023-05-14 18:20:01 +03:00
t . searchClientIps ( chatId , email )
2023-05-14 21:37:49 +03:00
case "tg_user" :
t . sendCallbackAnswerTgBot ( callbackQuery . ID , fmt . Sprintf ( "✅ %s : Get Telegram User Info." , email ) )
t . clientTelegramUserInfo ( chatId , email )
2023-05-14 22:13:23 +03:00
case "tgid_remove" :
inlineKeyboard := tu . InlineKeyboard (
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "❌ Cancel" ) . WithCallbackData ( "tgid_cancel " + email ) ,
) ,
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "✅ Confirm Remove Telegram User?" ) . WithCallbackData ( "tgid_remove_c " + email ) ,
) ,
)
t . editMessageCallbackTgBot ( chatId , callbackQuery . Message . MessageID , inlineKeyboard )
case "tgid_remove_c" :
traffic , err := t . inboundService . GetClientTrafficByEmail ( email )
if err != nil || traffic == nil {
t . sendCallbackAnswerTgBot ( callbackQuery . ID , "❗ Error in Operation." )
return
}
err = t . inboundService . SetClientTelegramUserID ( traffic . Id , "" )
if err == nil {
t . sendCallbackAnswerTgBot ( callbackQuery . ID , fmt . Sprintf ( "✅ %s : Telegram User removed successfully." , email ) )
t . clientTelegramUserInfo ( chatId , email , callbackQuery . Message . MessageID )
} else {
t . sendCallbackAnswerTgBot ( callbackQuery . ID , "❗ Error in Operation." )
}
2023-05-05 17:50:56 +03:00
case "toggle_enable" :
2023-05-05 19:20:40 +03:00
enabled , err := t . inboundService . ToggleClientEnableByEmail ( email )
2023-05-05 17:50:56 +03:00
if err == nil {
t . xrayService . SetToNeedRestart ( )
2023-05-05 19:20:40 +03:00
if enabled {
2023-05-05 17:50:56 +03:00
t . sendCallbackAnswerTgBot ( callbackQuery . ID , fmt . Sprintf ( "✅ %s : Enabled successfully." , email ) )
} else {
t . sendCallbackAnswerTgBot ( callbackQuery . ID , fmt . Sprintf ( "✅ %s : Disabled successfully." , email ) )
}
2023-05-14 18:20:01 +03:00
t . searchClient ( chatId , email , callbackQuery . Message . MessageID )
2023-05-05 17:50:56 +03:00
} else {
t . sendCallbackAnswerTgBot ( callbackQuery . ID , "❗ Error in Operation." )
}
2023-05-05 00:46:43 +03:00
}
return
}
}
2023-03-17 19:07:49 +03:00
// Respond to the callback query, telling Telegram to show the user
// a message with the data received.
2023-05-14 18:20:01 +03:00
t . sendCallbackAnswerTgBot ( callbackQuery . ID , callbackQuery . Data )
2023-03-17 19:07:49 +03:00
switch callbackQuery . Data {
case "get_usage" :
2023-05-14 18:20:01 +03:00
t . SendMsgToTgbot ( chatId , t . getServerUsage ( ) )
2023-03-17 19:07:49 +03:00
case "inbounds" :
2023-05-14 18:20:01 +03:00
t . SendMsgToTgbot ( chatId , t . getInboundUsages ( ) )
2023-04-09 22:43:18 +03:00
case "deplete_soon" :
2023-05-14 18:20:01 +03:00
t . SendMsgToTgbot ( chatId , t . getExhausted ( ) )
2023-03-17 19:07:49 +03:00
case "get_backup" :
2023-05-14 18:20:01 +03:00
t . sendBackup ( chatId )
2023-03-17 19:07:49 +03:00
case "client_traffic" :
2023-05-14 18:20:01 +03:00
t . getClientUsage ( chatId , callbackQuery . From . Username , strconv . FormatInt ( callbackQuery . From . ID , 10 ) )
2023-03-17 19:07:49 +03:00
case "client_commands" :
2023-05-14 18:20:01 +03:00
t . SendMsgToTgbot ( chatId , "To search for statistics, just use folowing command:\r\n \r\n<code>/usage [UID|Password]</code>\r\n \r\nUse UID for vmess/vless and Password for Trojan." )
2023-03-17 19:07:49 +03:00
case "commands" :
2023-05-14 18:20:01 +03:00
t . SendMsgToTgbot ( chatId , "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>" )
2023-03-17 19:07:49 +03:00
}
}
func checkAdmin ( tgId int64 ) bool {
for _ , adminId := range adminIds {
if adminId == tgId {
return true
}
}
return false
}
func ( t * Tgbot ) SendAnswer ( chatId int64 , msg string , isAdmin bool ) {
2023-05-14 18:20:01 +03:00
numericKeyboard := tu . InlineKeyboard (
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "Server Usage" ) . WithCallbackData ( "get_usage" ) ,
tu . InlineKeyboardButton ( "Get DB Backup" ) . WithCallbackData ( "get_backup" ) ,
2023-03-17 19:07:49 +03:00
) ,
2023-05-14 18:20:01 +03:00
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "Get Inbounds" ) . WithCallbackData ( "inbounds" ) ,
tu . InlineKeyboardButton ( "Deplete soon" ) . WithCallbackData ( "deplete_soon" ) ,
2023-03-17 19:07:49 +03:00
) ,
2023-05-14 18:20:01 +03:00
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "Commands" ) . WithCallbackData ( "commands" ) ,
2023-03-17 19:07:49 +03:00
) ,
)
2023-05-14 18:20:01 +03:00
numericKeyboardClient := tu . InlineKeyboard (
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "Get Usage" ) . WithCallbackData ( "client_traffic" ) ,
tu . InlineKeyboardButton ( "Commands" ) . WithCallbackData ( "client_commands" ) ,
2023-03-17 19:07:49 +03:00
) ,
)
2023-05-14 18:20:01 +03:00
params := telego . SendMessageParams {
ChatID : tu . ID ( chatId ) ,
Text : msg ,
ParseMode : "HTML" ,
}
2023-03-17 19:07:49 +03:00
if isAdmin {
2023-05-14 18:20:01 +03:00
params . ReplyMarkup = numericKeyboard
2023-03-17 19:07:49 +03:00
} else {
2023-05-14 18:20:01 +03:00
params . ReplyMarkup = numericKeyboardClient
2023-03-17 19:07:49 +03:00
}
2023-05-14 18:20:01 +03:00
_ , err := bot . SendMessage ( & params )
2023-03-17 19:07:49 +03:00
if err != nil {
logger . Warning ( "Error sending telegram message :" , err )
}
}
2023-05-14 21:37:49 +03:00
func ( t * Tgbot ) SendMsgToTgbot ( chatId int64 , msg string , replyMarkup ... telego . ReplyMarkup ) {
2023-05-13 13:01:46 +03:00
if ! isRunning {
return
}
2023-03-17 19:07:49 +03:00
var allMessages [ ] string
limit := 2000
// paging message if it is big
if len ( msg ) > limit {
messages := strings . Split ( msg , "\r\n \r\n" )
lastIndex := - 1
for _ , message := range messages {
if ( len ( allMessages ) == 0 ) || ( len ( allMessages [ lastIndex ] ) + len ( message ) > limit ) {
allMessages = append ( allMessages , message )
lastIndex ++
} else {
allMessages [ lastIndex ] += "\r\n \r\n" + message
}
}
} else {
allMessages = append ( allMessages , msg )
}
for _ , message := range allMessages {
2023-05-14 18:20:01 +03:00
params := telego . SendMessageParams {
ChatID : tu . ID ( chatId ) ,
Text : message ,
ParseMode : "HTML" ,
}
2023-05-14 21:37:49 +03:00
if len ( replyMarkup ) > 0 {
params . ReplyMarkup = replyMarkup [ 0 ]
2023-05-05 00:46:43 +03:00
}
2023-05-14 18:20:01 +03:00
_ , err := bot . SendMessage ( & params )
2023-03-17 19:07:49 +03:00
if err != nil {
logger . Warning ( "Error sending telegram message :" , err )
}
time . Sleep ( 500 * time . Millisecond )
}
}
func ( t * Tgbot ) SendMsgToTgbotAdmins ( msg string ) {
for _ , adminId := range adminIds {
t . SendMsgToTgbot ( adminId , msg )
}
}
func ( t * Tgbot ) SendReport ( ) {
runTime , err := t . settingService . GetTgbotRuntime ( )
if err == nil && len ( runTime ) > 0 {
t . SendMsgToTgbotAdmins ( "🕰 Scheduled reports: " + runTime + "\r\nDate-Time: " + time . Now ( ) . Format ( "2006-01-02 15:04:05" ) )
}
info := t . getServerUsage ( )
t . SendMsgToTgbotAdmins ( info )
exhausted := t . getExhausted ( )
t . SendMsgToTgbotAdmins ( exhausted )
backupEnable , err := t . settingService . GetTgBotBackup ( )
if err == nil && backupEnable {
for _ , adminId := range adminIds {
t . sendBackup ( int64 ( adminId ) )
}
}
}
func ( t * Tgbot ) getServerUsage ( ) string {
var info string
//get hostname
name , err := os . Hostname ( )
if err != nil {
logger . Error ( "get hostname error:" , err )
name = ""
}
info = fmt . Sprintf ( "💻 Hostname: %s\r\n" , name )
2023-03-24 16:44:26 +03:00
info += fmt . Sprintf ( "🚀X-UI Version: %s\r\n" , config . GetVersion ( ) )
2023-03-17 19:07:49 +03:00
//get ip address
var ip string
var ipv6 string
netInterfaces , err := net . Interfaces ( )
if err != nil {
logger . Error ( "net.Interfaces failed, err:" , err . Error ( ) )
info += "🌐 IP: Unknown\r\n \r\n"
} else {
for i := 0 ; i < len ( netInterfaces ) ; i ++ {
if ( netInterfaces [ i ] . Flags & net . FlagUp ) != 0 {
addrs , _ := netInterfaces [ i ] . Addrs ( )
for _ , address := range addrs {
if ipnet , ok := address . ( * net . IPNet ) ; ok && ! ipnet . IP . IsLoopback ( ) {
if ipnet . IP . To4 ( ) != nil {
ip += ipnet . IP . String ( ) + " "
} else if ipnet . IP . To16 ( ) != nil && ! ipnet . IP . IsLinkLocalUnicast ( ) {
ipv6 += ipnet . IP . String ( ) + " "
}
}
}
}
}
info += fmt . Sprintf ( "🌐IP: %s\r\n🌐IPv6: %s\r\n" , ip , ipv6 )
}
// get latest status of server
t . lastStatus = t . serverService . GetStatus ( t . lastStatus )
info += fmt . Sprintf ( "🔌Server Uptime: %d days\r\n" , int ( t . lastStatus . Uptime / 86400 ) )
info += fmt . Sprintf ( "📈Server Load: %.1f, %.1f, %.1f\r\n" , t . lastStatus . Loads [ 0 ] , t . lastStatus . Loads [ 1 ] , t . lastStatus . Loads [ 2 ] )
info += fmt . Sprintf ( "📋Server Memory: %s/%s\r\n" , common . FormatTraffic ( int64 ( t . lastStatus . Mem . Current ) ) , common . FormatTraffic ( int64 ( t . lastStatus . Mem . Total ) ) )
info += fmt . Sprintf ( "🔹TcpCount: %d\r\n" , t . lastStatus . TcpCount )
info += fmt . Sprintf ( "🔸UdpCount: %d\r\n" , t . lastStatus . UdpCount )
info += fmt . Sprintf ( "🚦Traffic: %s (↑%s,↓%s)\r\n" , common . FormatTraffic ( int64 ( t . lastStatus . NetTraffic . Sent + t . lastStatus . NetTraffic . Recv ) ) , common . FormatTraffic ( int64 ( t . lastStatus . NetTraffic . Sent ) ) , common . FormatTraffic ( int64 ( t . lastStatus . NetTraffic . Recv ) ) )
info += fmt . Sprintf ( "ℹ Xray status: %s" , t . lastStatus . Xray . State )
return info
}
func ( t * Tgbot ) UserLoginNotify ( username string , ip string , time string , status LoginStatus ) {
if username == "" || ip == "" || time == "" {
logger . Warning ( "UserLoginNotify failed,invalid info" )
return
}
var msg string
// Get hostname
name , err := os . Hostname ( )
if err != nil {
logger . Warning ( "get hostname error:" , err )
return
}
if status == LoginSuccess {
msg = fmt . Sprintf ( "✅ Successfully logged-in to the panel\r\nHostname:%s\r\n" , name )
} else if status == LoginFail {
msg = fmt . Sprintf ( "❗ Login to the panel was unsuccessful\r\nHostname:%s\r\n" , name )
}
msg += fmt . Sprintf ( "⏰ Time:%s\r\n" , time )
msg += fmt . Sprintf ( "🆔 Username:%s\r\n" , username )
msg += fmt . Sprintf ( "🌐 IP:%s\r\n" , ip )
t . SendMsgToTgbotAdmins ( msg )
}
func ( t * Tgbot ) getInboundUsages ( ) string {
info := ""
// get traffic
inbouds , err := t . inboundService . GetAllInbounds ( )
if err != nil {
logger . Warning ( "GetAllInbounds run failed:" , err )
info += "❌ Failed to get inbounds"
} else {
// NOTE:If there no any sessions here,need to notify here
// TODO:Sub-node push, automatic conversion format
for _ , inbound := range inbouds {
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" ) )
}
}
}
return info
}
2023-05-05 17:50:56 +03:00
func ( t * Tgbot ) getClientUsage ( chatId int64 , tgUserName string , tgUserID string ) {
2023-05-06 02:06:46 +03:00
traffics , err := t . inboundService . GetClientTrafficTgBot ( tgUserID )
if err != nil {
logger . Warning ( err )
msg := "❌ Something went wrong!"
2023-04-09 22:43:18 +03:00
t . SendMsgToTgbot ( chatId , msg )
return
}
2023-05-06 02:06:46 +03:00
if len ( traffics ) == 0 {
if len ( tgUserName ) == 0 {
msg := "Your configuration is not found!\nPlease ask your Admin to use your telegram user id in your configuration(s).\n\nYour user id: <b>" + tgUserID + "</b>"
t . SendMsgToTgbot ( chatId , msg )
return
}
traffics , err = t . inboundService . GetClientTrafficTgBot ( tgUserName )
2023-05-05 17:50:56 +03:00
}
2023-03-17 19:07:49 +03:00
if err != nil {
logger . Warning ( err )
msg := "❌ Something went wrong!"
t . SendMsgToTgbot ( chatId , msg )
return
}
if len ( traffics ) == 0 {
2023-05-06 02:06:46 +03:00
msg := "Your configuration is not found!\nPlease ask your Admin to use your telegram username or user id in your configuration(s).\n\nYour username: <b>@" + tgUserName + "</b>\n\nYour user id: <b>" + tgUserID + "</b>"
2023-03-17 19:07:49 +03:00
t . SendMsgToTgbot ( chatId , msg )
2023-04-09 22:43:18 +03:00
return
2023-03-17 19:07:49 +03:00
}
for _ , traffic := range traffics {
expiryTime := ""
if traffic . ExpiryTime == 0 {
expiryTime = "♾Unlimited"
2023-04-09 22:43:18 +03:00
} else if traffic . ExpiryTime < 0 {
expiryTime = fmt . Sprintf ( "%d days" , traffic . ExpiryTime / - 86400000 )
2023-03-17 19:07:49 +03:00
} 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 )
}
t . SendAnswer ( chatId , "Please choose:" , false )
}
2023-05-05 17:50:56 +03:00
func ( t * Tgbot ) searchClientIps ( chatId int64 , email string , messageID ... int ) {
ips , err := t . inboundService . GetInboundClientIps ( email )
if err != nil || len ( ips ) == 0 {
ips = "No IP Record"
}
2023-05-05 19:37:47 +03:00
output := fmt . Sprintf ( "📧 Email: %s\r\n🔢 IPs: \r\n%s\r\n" , email , ips )
2023-05-14 18:20:01 +03:00
inlineKeyboard := tu . InlineKeyboard (
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "🔄 Refresh" ) . WithCallbackData ( "ips_refresh " + email ) ,
2023-05-05 17:50:56 +03:00
) ,
2023-05-14 18:20:01 +03:00
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "❌ Clear IPs" ) . WithCallbackData ( "clear_ips " + email ) ,
2023-05-05 17:50:56 +03:00
) ,
)
if len ( messageID ) > 0 {
t . editMessageTgBot ( chatId , messageID [ 0 ] , output , inlineKeyboard )
} else {
t . SendMsgToTgbot ( chatId , output , inlineKeyboard )
}
}
2023-05-14 22:13:23 +03:00
func ( t * Tgbot ) clientTelegramUserInfo ( chatId int64 , email string , messageID ... int ) {
2023-05-14 21:37:49 +03:00
traffic , client , err := t . inboundService . GetClientByEmail ( email )
if err != nil {
logger . Warning ( err )
msg := "❌ Something went wrong!"
t . SendMsgToTgbot ( chatId , msg )
return
}
if client == nil {
msg := "No result!"
t . SendMsgToTgbot ( chatId , msg )
return
}
2023-05-14 22:13:23 +03:00
tdId := "None"
if len ( client . TgID ) > 0 {
tdId = client . TgID
2023-05-14 21:37:49 +03:00
}
2023-05-14 22:13:23 +03:00
output := fmt . Sprintf ( "📧 Email: %s\r\n👤 Telegram User: %s\r\n" , email , tdId )
inlineKeyboard := tu . InlineKeyboard (
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "🔄 Refresh" ) . WithCallbackData ( "tgid_refresh " + email ) ,
2023-05-14 21:37:49 +03:00
) ,
2023-05-14 22:13:23 +03:00
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "❌ Remove Telegram User" ) . WithCallbackData ( "tgid_remove " + email ) ,
2023-05-14 21:37:49 +03:00
) ,
2023-05-14 22:13:23 +03:00
)
if len ( messageID ) > 0 {
t . editMessageTgBot ( chatId , messageID [ 0 ] , output , inlineKeyboard )
} else {
t . SendMsgToTgbot ( chatId , output , inlineKeyboard )
requestUser := telego . KeyboardButtonRequestUser {
RequestID : int32 ( traffic . Id ) ,
UserIsBot : false ,
}
keyboard := tu . Keyboard (
tu . KeyboardRow (
tu . KeyboardButton ( "👤 Select Telegram User" ) . WithRequestUser ( & requestUser ) ,
) ,
tu . KeyboardRow (
tu . KeyboardButton ( "❌ Close Keyboard" ) ,
) ,
) . WithIsPersistent ( )
t . SendMsgToTgbot ( chatId , "👤 Select a telegram user:" , keyboard )
}
2023-05-14 21:37:49 +03:00
}
2023-05-05 00:46:43 +03:00
func ( t * Tgbot ) searchClient ( chatId int64 , email string , messageID ... int ) {
2023-04-25 14:08:35 +03:00
traffic , err := t . inboundService . GetClientTrafficByEmail ( email )
2023-03-17 19:07:49 +03:00
if err != nil {
logger . Warning ( err )
msg := "❌ Something went wrong!"
t . SendMsgToTgbot ( chatId , msg )
return
}
2023-04-25 14:08:35 +03:00
if traffic == nil {
2023-03-17 19:07:49 +03:00
msg := "No result!"
t . SendMsgToTgbot ( chatId , msg )
return
}
2023-04-25 14:08:35 +03:00
expiryTime := ""
if traffic . ExpiryTime == 0 {
expiryTime = "♾Unlimited"
} else if traffic . ExpiryTime < 0 {
expiryTime = fmt . Sprintf ( "%d days" , traffic . ExpiryTime / - 86400000 )
} 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 ) )
2023-03-17 19:07:49 +03:00
}
2023-04-25 14:08:35 +03:00
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 )
2023-05-14 18:20:01 +03:00
inlineKeyboard := tu . InlineKeyboard (
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "🔄 Refresh" ) . WithCallbackData ( "client_refresh " + email ) ,
2023-05-05 01:18:37 +03:00
) ,
2023-05-14 18:20:01 +03:00
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "📈 Reset Traffic" ) . WithCallbackData ( "reset_traffic " + email ) ,
2023-05-05 00:46:43 +03:00
) ,
2023-05-14 18:20:01 +03:00
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "📅 Reset Expire Days" ) . WithCallbackData ( "reset_exp " + email ) ,
2023-05-05 00:46:43 +03:00
) ,
2023-05-14 18:20:01 +03:00
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "🔢 IP Log" ) . WithCallbackData ( "ip_log " + email ) ,
tu . InlineKeyboardButton ( "🔢 IP Limit" ) . WithCallbackData ( "ip_limit " + email ) ,
2023-05-05 17:50:56 +03:00
) ,
2023-05-14 21:37:49 +03:00
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "👤 Set Telegram User" ) . WithCallbackData ( "tg_user " + email ) ,
) ,
2023-05-14 18:20:01 +03:00
tu . InlineKeyboardRow (
tu . InlineKeyboardButton ( "🔘 Enable / Disable" ) . WithCallbackData ( "toggle_enable " + email ) ,
2023-05-05 17:50:56 +03:00
) ,
2023-05-05 00:46:43 +03:00
)
if len ( messageID ) > 0 {
t . editMessageTgBot ( chatId , messageID [ 0 ] , output , inlineKeyboard )
} else {
t . SendMsgToTgbot ( chatId , output , inlineKeyboard )
}
2023-03-17 19:07:49 +03:00
}
2023-03-24 16:44:26 +03:00
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"
2023-04-09 22:43:18 +03:00
} else if traffic . ExpiryTime < 0 {
expiryTime = fmt . Sprintf ( "%d days" , traffic . ExpiryTime / - 86400000 )
2023-03-24 16:44:26 +03:00
} 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 )
}
}
}
2023-03-17 19:07:49 +03:00
func ( t * Tgbot ) searchForClient ( chatId int64 , query string ) {
traffic , err := t . inboundService . SearchClientTraffic ( query )
if err != nil {
logger . Warning ( err )
msg := "❌ Something went wrong!"
t . SendMsgToTgbot ( chatId , msg )
return
}
if traffic == nil {
msg := "No result!"
t . SendMsgToTgbot ( chatId , msg )
return
}
expiryTime := ""
if traffic . ExpiryTime == 0 {
expiryTime = "♾Unlimited"
2023-04-09 22:43:18 +03:00
} else if traffic . ExpiryTime < 0 {
expiryTime = fmt . Sprintf ( "%d days" , traffic . ExpiryTime / - 86400000 )
2023-03-17 19:07:49 +03:00
} 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 ) getExhausted ( ) string {
trDiff := int64 ( 0 )
exDiff := int64 ( 0 )
now := time . Now ( ) . Unix ( ) * 1000
var exhaustedInbounds [ ] model . Inbound
var exhaustedClients [ ] xray . ClientTraffic
var disabledInbounds [ ] model . Inbound
var disabledClients [ ] xray . ClientTraffic
output := ""
2023-04-09 22:43:18 +03:00
TrafficThreshold , err := t . settingService . GetTrafficDiff ( )
2023-03-17 19:07:49 +03:00
if err == nil && TrafficThreshold > 0 {
trDiff = int64 ( TrafficThreshold ) * 1073741824
}
2023-04-09 22:43:18 +03:00
ExpireThreshold , err := t . settingService . GetExpireDiff ( )
2023-03-17 19:07:49 +03:00
if err == nil && ExpireThreshold > 0 {
2023-04-09 22:43:18 +03:00
exDiff = int64 ( ExpireThreshold ) * 86400000
2023-03-17 19:07:49 +03:00
}
inbounds , err := t . inboundService . GetAllInbounds ( )
if err != nil {
logger . Warning ( "Unable to load Inbounds" , err )
}
for _ , inbound := range inbounds {
if inbound . Enable {
2023-03-24 16:20:10 +03:00
if ( inbound . ExpiryTime > 0 && ( inbound . ExpiryTime - now < exDiff ) ) ||
2023-04-10 00:25:47 +03:00
( inbound . Total > 0 && ( inbound . Total - ( inbound . Up + inbound . Down ) < trDiff ) ) {
2023-03-17 19:07:49 +03:00
exhaustedInbounds = append ( exhaustedInbounds , * inbound )
}
if len ( inbound . ClientStats ) > 0 {
for _ , client := range inbound . ClientStats {
if client . Enable {
2023-03-24 16:20:10 +03:00
if ( client . ExpiryTime > 0 && ( client . ExpiryTime - now < exDiff ) ) ||
2023-04-10 00:25:47 +03:00
( client . Total > 0 && ( client . Total - ( client . Up + client . Down ) < trDiff ) ) {
2023-03-17 19:07:49 +03:00
exhaustedClients = append ( exhaustedClients , client )
}
} else {
disabledClients = append ( disabledClients , client )
}
}
}
} else {
disabledInbounds = append ( disabledInbounds , * inbound )
}
}
2023-04-09 22:43:18 +03:00
output += fmt . Sprintf ( "Exhausted Inbounds count:\r\n🛑 Disabled: %d\r\n🔜 Deplete soon: %d\r\n \r\n" , len ( disabledInbounds ) , len ( exhaustedInbounds ) )
2023-03-24 16:20:10 +03:00
if len ( exhaustedInbounds ) > 0 {
2023-03-17 19:07:49 +03:00
output += "Exhausted Inbounds:\r\n"
for _ , inbound := range exhaustedInbounds {
output += fmt . Sprintf ( "📍Inbound:%s\r\nPort:%d\r\nTraffic: %s (↑%s,↓%s)\r\n" , inbound . Remark , inbound . Port , common . FormatTraffic ( ( inbound . Up + inbound . Down ) ) , common . FormatTraffic ( inbound . Up ) , common . FormatTraffic ( inbound . Down ) )
if inbound . ExpiryTime == 0 {
output += "Expire date: ♾Unlimited\r\n \r\n"
} else {
output += fmt . Sprintf ( "Expire date:%s\r\n \r\n" , time . Unix ( ( inbound . ExpiryTime / 1000 ) , 0 ) . Format ( "2006-01-02 15:04:05" ) )
}
}
}
2023-04-09 22:43:18 +03:00
output += fmt . Sprintf ( "Exhausted Clients count:\r\n🛑 Exhausted: %d\r\n🔜 Deplete soon: %d\r\n \r\n" , len ( disabledClients ) , len ( exhaustedClients ) )
2023-03-24 16:20:10 +03:00
if len ( exhaustedClients ) > 0 {
2023-03-17 19:07:49 +03:00
output += "Exhausted Clients:\r\n"
for _ , traffic := range exhaustedClients {
expiryTime := ""
if traffic . ExpiryTime == 0 {
expiryTime = "♾Unlimited"
2023-04-09 22:43:18 +03:00
} else if traffic . ExpiryTime < 0 {
expiryTime += fmt . Sprintf ( "%d days" , traffic . ExpiryTime / - 86400000 )
2023-03-17 19:07:49 +03:00
} 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 ) )
}
2023-03-24 16:20:10 +03:00
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 date: %s\r\n \r\n" ,
2023-03-17 19:07:49 +03:00
traffic . Enable , traffic . Email , common . FormatTraffic ( traffic . Up ) , common . FormatTraffic ( traffic . Down ) , common . FormatTraffic ( ( traffic . Up + traffic . Down ) ) ,
total , expiryTime )
}
}
return output
}
func ( t * Tgbot ) sendBackup ( chatId int64 ) {
sendingTime := time . Now ( ) . Format ( "2006-01-02 15:04:05" )
t . SendMsgToTgbot ( chatId , "Backup time: " + sendingTime )
2023-05-14 18:20:01 +03:00
file , err := os . Open ( config . GetDBPath ( ) )
if err != nil {
logger . Warning ( "Error in opening db file for backup: " , err )
}
document := tu . Document (
tu . ID ( chatId ) ,
tu . File ( file ) ,
)
_ , err = bot . SendDocument ( document )
2023-03-17 19:07:49 +03:00
if err != nil {
logger . Warning ( "Error in uploading backup: " , err )
}
2023-05-14 18:20:01 +03:00
file , err = os . Open ( xray . GetConfigPath ( ) )
if err != nil {
logger . Warning ( "Error in opening config.json file for backup: " , err )
}
document = tu . Document (
tu . ID ( chatId ) ,
tu . File ( file ) ,
)
_ , err = bot . SendDocument ( document )
2023-03-24 16:44:26 +03:00
if err != nil {
logger . Warning ( "Error in uploading config.json: " , err )
}
2023-03-17 19:07:49 +03:00
}
2023-05-05 00:46:43 +03:00
func ( t * Tgbot ) sendCallbackAnswerTgBot ( id string , message string ) {
2023-05-14 18:20:01 +03:00
params := telego . AnswerCallbackQueryParams {
CallbackQueryID : id ,
Text : message ,
}
if err := bot . AnswerCallbackQuery ( & params ) ; err != nil {
2023-05-05 00:46:43 +03:00
logger . Warning ( err )
}
}
2023-05-14 18:20:01 +03:00
func ( t * Tgbot ) editMessageCallbackTgBot ( chatId int64 , messageID int , inlineKeyboard * telego . InlineKeyboardMarkup ) {
params := telego . EditMessageReplyMarkupParams {
ChatID : tu . ID ( chatId ) ,
MessageID : messageID ,
ReplyMarkup : inlineKeyboard ,
}
if _ , err := bot . EditMessageReplyMarkup ( & params ) ; err != nil {
2023-05-05 00:46:43 +03:00
logger . Warning ( err )
}
}
2023-05-14 18:20:01 +03:00
func ( t * Tgbot ) editMessageTgBot ( chatId int64 , messageID int , text string , inlineKeyboard ... * telego . InlineKeyboardMarkup ) {
params := telego . EditMessageTextParams {
ChatID : tu . ID ( chatId ) ,
MessageID : messageID ,
Text : text ,
ParseMode : "HTML" ,
}
2023-05-05 00:46:43 +03:00
if len ( inlineKeyboard ) > 0 {
2023-05-14 18:20:01 +03:00
params . ReplyMarkup = inlineKeyboard [ 0 ]
2023-05-05 00:46:43 +03:00
}
2023-05-14 18:20:01 +03:00
if _ , err := bot . EditMessageText ( & params ) ; err != nil {
2023-05-05 00:46:43 +03:00
logger . Warning ( err )
}
}
2023-05-14 18:20:01 +03:00
func fromChat ( u * telego . Update ) * telego . Chat {
switch {
case u . Message != nil :
return & u . Message . Chat
case u . EditedMessage != nil :
return & u . EditedMessage . Chat
case u . ChannelPost != nil :
return & u . ChannelPost . Chat
case u . EditedChannelPost != nil :
return & u . EditedChannelPost . Chat
case u . CallbackQuery != nil :
return & u . CallbackQuery . Message . Chat
default :
return nil
}
}