mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2025-04-19 21:42:24 +00:00
commit
b13e1d666d
5 changed files with 51 additions and 45 deletions
|
@ -91,7 +91,7 @@ type Client struct {
|
|||
TotalGB int64 `json:"totalGB" form:"totalGB"`
|
||||
ExpiryTime int64 `json:"expiryTime" form:"expiryTime"`
|
||||
Enable bool `json:"enable" form:"enable"`
|
||||
TgID string `json:"tgId" form:"tgId"`
|
||||
TgID int64 `json:"tgId" form:"tgId"`
|
||||
SubID string `json:"subId" form:"subId"`
|
||||
Reset int `json:"reset" form:"reset"`
|
||||
}
|
||||
|
|
4
go.mod
4
go.mod
|
@ -7,12 +7,12 @@ require (
|
|||
github.com/gin-contrib/gzip v1.0.0
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/goccy/go-json v0.10.2
|
||||
github.com/mymmrac/telego v0.29.1
|
||||
github.com/mymmrac/telego v0.29.2
|
||||
github.com/nicksnyder/go-i18n/v2 v2.4.0
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
|
||||
github.com/pelletier/go-toml/v2 v2.2.0
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/shirou/gopsutil/v3 v3.24.2
|
||||
github.com/shirou/gopsutil/v3 v3.24.3
|
||||
github.com/valyala/fasthttp v1.52.0
|
||||
github.com/xtls/xray-core v1.8.10
|
||||
go.uber.org/atomic v1.11.0
|
||||
|
|
9
go.sum
9
go.sum
|
@ -163,8 +163,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
|
|||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mymmrac/telego v0.29.1 h1:nsNnK0mS18OL+unoDjDI6BVfafJBbT8Wtj7rCzEWoM8=
|
||||
github.com/mymmrac/telego v0.29.1/go.mod h1:ZLD1+L2TQRr97NPOCoN1V2w8y9kmFov33OfZ3qT8cF4=
|
||||
github.com/mymmrac/telego v0.29.2 h1:5+fQ/b8d8Ld6ihCJ0OLe1CwUdT3t1sIUl3RaSaSvRJs=
|
||||
github.com/mymmrac/telego v0.29.2/go.mod h1:BsKr+GF9BHqaVaLBwsZeDnfuJcJx2olWuDEtKm4zHMc=
|
||||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
||||
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.4.0 h1:3IcvPOAvnCKwNm0TB0dLDTuawWEj+ax/RERNC+diLMM=
|
||||
|
@ -212,8 +212,8 @@ github.com/savsgio/gotils v0.0.0-20240303185622-093b76447511/go.mod h1:sM7Mt7uEo
|
|||
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb h1:XfLJSPIOUX+osiMraVgIrMR27uMXnRJWGm1+GL8/63U=
|
||||
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shirou/gopsutil/v3 v3.24.2 h1:kcR0erMbLg5/3LcInpw0X/rrPSqq4CDPyI6A6ZRC18Y=
|
||||
github.com/shirou/gopsutil/v3 v3.24.2/go.mod h1:tSg/594BcA+8UdQU2XcW803GWYgdtauFFPgJCJKZlVk=
|
||||
github.com/shirou/gopsutil/v3 v3.24.3 h1:eoUGJSmdfLzJ3mxIhmOAhgKEKgQkeOwKpz1NbhVnuPE=
|
||||
github.com/shirou/gopsutil/v3 v3.24.3/go.mod h1:JpND7O217xa72ewWz9zN2eIIkPWsDN/3pl0H8Qt0uwg=
|
||||
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
||||
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
||||
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
|
||||
|
@ -346,7 +346,6 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
|
|
@ -1186,7 +1186,7 @@ func (s *InboundService) GetClientByEmail(clientEmail string) (*xray.ClientTraff
|
|||
return nil, nil, common.NewError("Client Not Found In Inbound For Email:", clientEmail)
|
||||
}
|
||||
|
||||
func (s *InboundService) SetClientTelegramUserID(trafficId int, tgId string) (bool, error) {
|
||||
func (s *InboundService) SetClientTelegramUserID(trafficId int, tgId int64) (bool, error) {
|
||||
traffic, inbound, err := s.GetClientInboundByTrafficID(trafficId)
|
||||
if err != nil {
|
||||
return false, err
|
||||
|
@ -1687,10 +1687,10 @@ func (s *InboundService) DelDepletedClients(id int) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
func (s *InboundService) GetClientTrafficTgBot(tgId string) ([]*xray.ClientTraffic, error) {
|
||||
func (s *InboundService) GetClientTrafficTgBot(tgId int64) ([]*xray.ClientTraffic, error) {
|
||||
db := database.GetDB()
|
||||
var inbounds []*model.Inbound
|
||||
err := db.Model(model.Inbound{}).Where("settings like ?", fmt.Sprintf(`%%"tgId": "%s"%%`, tgId)).Find(&inbounds).Error
|
||||
err := db.Model(model.Inbound{}).Where("settings like ?", fmt.Sprintf(`%%"tgId": %d%%`, tgId)).Find(&inbounds).Error
|
||||
if err != nil && err != gorm.ErrRecordNotFound {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -39,8 +38,9 @@ var (
|
|||
type LoginStatus byte
|
||||
|
||||
const (
|
||||
LoginSuccess LoginStatus = 1
|
||||
LoginFail LoginStatus = 0
|
||||
LoginSuccess LoginStatus = 1
|
||||
LoginFail LoginStatus = 0
|
||||
EmptyTelegramUserID = int64(0)
|
||||
)
|
||||
|
||||
type Tgbot struct {
|
||||
|
@ -207,21 +207,20 @@ func (t *Tgbot) OnReceive() {
|
|||
botHandler.HandleMessage(func(_ *telego.Bot, message telego.Message) {
|
||||
if message.UsersShared != nil {
|
||||
if checkAdmin(message.From.ID) {
|
||||
userIDsStr := ""
|
||||
for _, userID := range message.UsersShared.UserIDs {
|
||||
userIDsStr += strconv.FormatInt(userID, 10) + " "
|
||||
for _, sharedUser := range message.UsersShared.Users {
|
||||
userID := sharedUser.UserID
|
||||
needRestart, err := t.inboundService.SetClientTelegramUserID(message.UsersShared.RequestID, userID)
|
||||
if needRestart {
|
||||
t.xrayService.SetToNeedRestart()
|
||||
}
|
||||
output := ""
|
||||
if err != nil {
|
||||
output += t.I18nBot("tgbot.messages.selectUserFailed")
|
||||
} else {
|
||||
output += t.I18nBot("tgbot.messages.userSaved")
|
||||
}
|
||||
t.SendMsgToTgbot(message.Chat.ID, output, tu.ReplyKeyboardRemove())
|
||||
}
|
||||
needRestart, err := t.inboundService.SetClientTelegramUserID(message.UsersShared.RequestID, userIDsStr)
|
||||
if needRestart {
|
||||
t.xrayService.SetToNeedRestart()
|
||||
}
|
||||
output := ""
|
||||
if err != nil {
|
||||
output += t.I18nBot("tgbot.messages.selectUserFailed")
|
||||
} else {
|
||||
output += t.I18nBot("tgbot.messages.userSaved")
|
||||
}
|
||||
t.SendMsgToTgbot(message.Chat.ID, output, tu.ReplyKeyboardRemove())
|
||||
} else {
|
||||
t.SendMsgToTgbot(message.Chat.ID, t.I18nBot("tgbot.noResult"), tu.ReplyKeyboardRemove())
|
||||
}
|
||||
|
@ -259,7 +258,9 @@ func (t *Tgbot) answerCommand(message *telego.Message, chatId int64, isAdmin boo
|
|||
if isAdmin {
|
||||
t.searchClient(chatId, commandArgs[0])
|
||||
} else {
|
||||
t.getClientUsage(chatId, strconv.FormatInt(message.From.ID, 10), commandArgs[0])
|
||||
// Convert message.From.ID to int64
|
||||
fromID := int64(message.From.ID)
|
||||
t.getClientUsage(chatId, fromID, commandArgs[0])
|
||||
}
|
||||
} else {
|
||||
msg += t.I18nBot("tgbot.commands.usage")
|
||||
|
@ -726,7 +727,7 @@ func (t *Tgbot) asnwerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool
|
|||
t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
|
||||
return
|
||||
}
|
||||
needRestart, err := t.inboundService.SetClientTelegramUserID(traffic.Id, "")
|
||||
needRestart, err := t.inboundService.SetClientTelegramUserID(traffic.Id, EmptyTelegramUserID)
|
||||
if needRestart {
|
||||
t.xrayService.SetToNeedRestart()
|
||||
}
|
||||
|
@ -783,8 +784,9 @@ func (t *Tgbot) asnwerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool
|
|||
t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.getBanLogs"))
|
||||
t.sendBanLogs(chatId, true)
|
||||
case "client_traffic":
|
||||
tgUserID := callbackQuery.From.ID
|
||||
t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.clientUsage"))
|
||||
t.getClientUsage(chatId, strconv.FormatInt(callbackQuery.From.ID, 10))
|
||||
t.getClientUsage(chatId, tgUserID)
|
||||
case "client_commands":
|
||||
t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.commands"))
|
||||
t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.commands.helpClientCommands"))
|
||||
|
@ -1135,7 +1137,7 @@ func (t *Tgbot) clientInfoMsg(
|
|||
return output
|
||||
}
|
||||
|
||||
func (t *Tgbot) getClientUsage(chatId int64, tgUserID string, email ...string) {
|
||||
func (t *Tgbot) getClientUsage(chatId int64, tgUserID int64, email ...string) {
|
||||
traffics, err := t.inboundService.GetClientTrafficTgBot(tgUserID)
|
||||
if err != nil {
|
||||
logger.Warning(err)
|
||||
|
@ -1145,7 +1147,7 @@ func (t *Tgbot) getClientUsage(chatId int64, tgUserID string, email ...string) {
|
|||
}
|
||||
|
||||
if len(traffics) == 0 {
|
||||
t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.askToAddUserId", "TgUserID=="+tgUserID))
|
||||
t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.askToAddUserId", "TgUserID=="+strconv.FormatInt(tgUserID, 10)))
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -1218,8 +1220,8 @@ func (t *Tgbot) clientTelegramUserInfo(chatId int64, email string, messageID ...
|
|||
return
|
||||
}
|
||||
tgId := "None"
|
||||
if len(client.TgID) > 0 {
|
||||
tgId = client.TgID
|
||||
if client.TgID != 0 {
|
||||
tgId = strconv.FormatInt(client.TgID, 10)
|
||||
}
|
||||
|
||||
output := ""
|
||||
|
@ -1452,24 +1454,20 @@ func (t *Tgbot) notifyExhausted() {
|
|||
logger.Warning("Unable to load Inbounds", err)
|
||||
}
|
||||
|
||||
var chatIDsDone []string
|
||||
var chatIDsDone []int64
|
||||
for _, inbound := range inbounds {
|
||||
if inbound.Enable {
|
||||
if len(inbound.ClientStats) > 0 {
|
||||
clients, err := t.inboundService.GetClients(inbound)
|
||||
if err == nil {
|
||||
for _, client := range clients {
|
||||
if client.TgID != "" {
|
||||
chatID, err := strconv.ParseInt(client.TgID, 10, 64)
|
||||
if err != nil {
|
||||
logger.Warning("TgID is not a number: ", client.TgID)
|
||||
continue
|
||||
}
|
||||
if !slices.Contains(chatIDsDone, client.TgID) && !checkAdmin(chatID) {
|
||||
if client.TgID != 0 {
|
||||
chatID := client.TgID
|
||||
if !int64Contains(chatIDsDone, chatID) && !checkAdmin(chatID) {
|
||||
var disabledClients []xray.ClientTraffic
|
||||
var exhaustedClients []xray.ClientTraffic
|
||||
traffics, err := t.inboundService.GetClientTrafficTgBot(client.TgID)
|
||||
if err == nil && len(traffics) > 0 {
|
||||
if err == nil && len(traffics) > 0 {
|
||||
output := t.I18nBot("tgbot.messages.exhaustedCount", "Type=="+t.I18nBot("tgbot.clients"))
|
||||
for _, traffic := range traffics {
|
||||
if traffic.Enable {
|
||||
|
@ -1498,7 +1496,7 @@ func (t *Tgbot) notifyExhausted() {
|
|||
}
|
||||
t.SendMsgToTgbot(chatID, output)
|
||||
}
|
||||
chatIDsDone = append(chatIDsDone, client.TgID)
|
||||
chatIDsDone = append(chatIDsDone, chatID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1509,6 +1507,15 @@ func (t *Tgbot) notifyExhausted() {
|
|||
}
|
||||
}
|
||||
|
||||
func int64Contains(slice []int64, item int64) bool {
|
||||
for _, s := range slice {
|
||||
if s == item {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (t *Tgbot) onlineClients(chatId int64, messageID ...int) {
|
||||
if !p.IsRunning() {
|
||||
return
|
||||
|
|
Loading…
Reference in a new issue