diff --git a/go.mod b/go.mod index b7ea53e0..931841b3 100644 --- a/go.mod +++ b/go.mod @@ -7,8 +7,8 @@ require ( github.com/gin-contrib/sessions v0.0.4 github.com/gin-gonic/gin v1.9.0 github.com/go-cmd/cmd v1.4.1 - github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 github.com/goccy/go-json v0.10.2 + github.com/mymmrac/telego v0.24.0 github.com/nicksnyder/go-i18n/v2 v2.2.1 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 github.com/pelletier/go-toml/v2 v2.0.7 @@ -24,8 +24,10 @@ require ( require ( github.com/BurntSushi/toml v1.2.1 // indirect + github.com/andybalholm/brotli v1.0.5 // indirect github.com/bytedance/sonic v1.8.8 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/fasthttp/router v1.4.19 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-playground/locales v0.14.1 // indirect @@ -38,6 +40,7 @@ require ( github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.16.5 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a // indirect @@ -47,11 +50,14 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pires/go-proxyproto v0.7.0 // indirect github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect + github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect github.com/shoenig/go-m1cpu v0.1.5 // indirect github.com/tklauser/go-sysconf v0.3.11 // indirect github.com/tklauser/numcpus v0.6.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.47.0 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.8.0 // indirect diff --git a/go.sum b/go.sum index bbccf08b..adde75cf 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,7 @@ github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbi github.com/Workiva/go-datastructures v1.0.53 h1:J6Y/52yX10Xc5JjXmGtWoSSxs3mZnGSaq37xZZh7Yig= github.com/Workiva/go-datastructures v1.0.53/go.mod h1:1yZL+zfsztete+ePzZz/Zb1/t5BnDuE2Ya2MMGhzP6A= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= +github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/antonlindstrom/pgstore v0.0.0-20200229204646-b08ebf1105e0/go.mod h1:2Ti6VUHVxpC0VSmTZzEvpzysnaGAfGBOoMIz5ykPyyw= github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P97fT2CiHkbFQwkK3mjsFAP6zCYV2aXtjw= github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= @@ -18,6 +19,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 h1:y7y0Oa6UawqTFPCDw9JG6pdKt4F9pAhHv0B7FMGaGD0= +github.com/fasthttp/router v1.4.19 h1:RLE539IU/S4kfb4MP56zgP0TIBU9kEg0ID9GpWO0vqk= +github.com/fasthttp/router v1.4.19/go.mod h1:+Fh3YOd8x1+he6ZS+d2iUDBH9MGGZ1xQFUor0DE9rKE= github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= github.com/gaukas/godicttls v0.0.3 h1:YNDIf0d9adcxOijiLrEzpfZGAkNwLRzPaG6OjU7EITk= github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4= @@ -45,8 +48,6 @@ github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn github.com/go-playground/validator/v10 v10.13.0 h1:cFRQdfaSMCOSfGCCLB20MHvuoHb/s5G8L5pu2ppK5AQ= github.com/go-playground/validator/v10 v10.13.0/go.mod h1:dwu7+CG8/CtBiJFZDz4e+5Upb6OLw04gtBYw0mcG/z4= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 h1:wG8n/XJQ07TmjbITcGiUaOtXxdrINDz1b0J1w0SzqDc= -github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1/go.mod h1:A2S0CWkNylc2phvKXWBBdD3K0iGnDBGbzRpISP2zBl8= github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= @@ -81,6 +82,7 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kidstuff/mongostore v0.0.0-20181113001930-e650cd85ee4b/go.mod h1:g2nVr8KZVXJSS97Jo8pJ0jgq29P6H7dG0oplUA86MQw= github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= @@ -105,6 +107,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/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.24.0 h1:0fd+v2/dToL6/DtsnWr+2saK7ZxIgLY+LI9kqJQbPEo= +github.com/mymmrac/telego v0.24.0/go.mod h1:y557P/iMHSaOVDi5Nmy1gNelqrw+jaBMvP9guPaNJsQ= github.com/nicksnyder/go-i18n/v2 v2.2.1 h1:aOzRCdwsJuoExfZhoiXHy4bjruwCMdt5otbYojM/PaA= github.com/nicksnyder/go-i18n/v2 v2.2.1/go.mod h1:fF2++lPHlo+/kPaj3nB0uxtPwzlPm+BlgwGX7MkeGj0= github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU= @@ -133,6 +137,8 @@ github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzG github.com/sagernet/sing v0.2.3 h1:V50MvZ4c3Iij2lYFWPlzL1PyipwSzjGeN9x+Ox89vpk= github.com/sagernet/sing-shadowsocks v0.2.1 h1:FvdLQOqpvxHBJUcUe4fvgiYP2XLLwH5i1DtXQviVEPw= github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo= +github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk= +github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g= github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb h1:XfLJSPIOUX+osiMraVgIrMR27uMXnRJWGm1+GL8/63U= github.com/shirou/gopsutil/v3 v3.23.4 h1:hZwmDxZs7Ewt75DV81r4pFMqbq+di2cbt9FsQBqLD2o= github.com/shirou/gopsutil/v3 v3.23.4/go.mod h1:ZcGxyfzAMRevhUR2+cfhXDH6gQdFYE/t8j1nsU4mPI8= @@ -164,6 +170,10 @@ github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLY github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e h1:5QefA066A1tF8gHIiADmOVOV5LS43gt3ONnlEl3xkwI= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.47.0 h1:y7moDoxYzMooFpT5aHgNgVOQDrS3qlkfiP9mDtGGK9c= +github.com/valyala/fasthttp v1.47.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= github.com/xtls/reality v0.0.0-20230331223127-176a94313eda h1:psRJD2RrZbnI0OWyHvXfgYCPqlRM5q5SPDcjDoDBWhE= github.com/xtls/xray-core v1.8.1 h1:iSTTqXj82ZdwC1ah+eV331X4JTcnrDz+WuKuB/EB3P4= github.com/xtls/xray-core v1.8.1/go.mod h1:AXxSso0MZwUE4NhRocCfHCg73BtJ+T2dSpQVo1Cg9VM= diff --git a/web/service/inbound.go b/web/service/inbound.go index 7e838b5f..57df0b9e 100644 --- a/web/service/inbound.go +++ b/web/service/inbound.go @@ -673,6 +673,21 @@ func (s *InboundService) DelClientIPs(tx *gorm.DB, email string) error { return tx.Where("client_email = ?", email).Delete(model.InboundClientIps{}).Error } +func (s *InboundService) GetClientInboundByTrafficID(trafficId int) (traffic *xray.ClientTraffic, inbound *model.Inbound, err error) { + db := database.GetDB() + var traffics []*xray.ClientTraffic + err = db.Model(xray.ClientTraffic{}).Where("id = ?", trafficId).Find(&traffics).Error + if err != nil { + logger.Warning(err) + return nil, nil, err + } + if len(traffics) > 0 { + inbound, err = s.GetInbound(traffics[0].InboundId) + return traffics[0], inbound, err + } + return nil, nil, nil +} + func (s *InboundService) GetClientInboundByEmail(email string) (traffic *xray.ClientTraffic, inbound *model.Inbound, err error) { db := database.GetDB() var traffics []*xray.ClientTraffic @@ -688,6 +703,85 @@ func (s *InboundService) GetClientInboundByEmail(email string) (traffic *xray.Cl return nil, nil, nil } +func (s *InboundService) GetClientByEmail(clientEmail string) (*xray.ClientTraffic, *model.Client, error) { + traffic, inbound, err := s.GetClientInboundByEmail(clientEmail) + if err != nil { + return nil, nil, err + } + if inbound == nil { + return nil, nil, common.NewError("Inbound Not Found For Email:", clientEmail) + } + + clients, err := s.getClients(inbound) + if err != nil { + return nil, nil, err + } + + for _, client := range clients { + if client.Email == clientEmail { + return traffic, &client, nil + } + } + + return nil, nil, common.NewError("Client Not Found In Inbound For Email:", clientEmail) +} + +func (s *InboundService) SetClientTelegramUserID(trafficId int, tgId string) error { + traffic, inbound, err := s.GetClientInboundByTrafficID(trafficId) + if err != nil { + return err + } + if inbound == nil { + return common.NewError("Inbound Not Found For Traffic ID:", trafficId) + } + + clientEmail := traffic.Email + + oldClients, err := s.getClients(inbound) + if err != nil { + return err + } + + clientId := "" + + for _, oldClient := range oldClients { + if oldClient.Email == clientEmail { + if inbound.Protocol == "trojan" { + clientId = oldClient.Password + } else { + clientId = oldClient.ID + } + break + } + } + + if len(clientId) == 0 { + return common.NewError("Client Not Found For Email:", clientEmail) + } + + var settings map[string]interface{} + err = json.Unmarshal([]byte(inbound.Settings), &settings) + if err != nil { + return err + } + clients := settings["clients"].([]interface{}) + var newClients []interface{} + for client_index := range clients { + c := clients[client_index].(map[string]interface{}) + if c["email"] == clientEmail { + c["tgId"] = tgId + newClients = append(newClients, interface{}(c)) + } + } + settings["clients"] = newClients + modifiedSettings, err := json.MarshalIndent(settings, "", " ") + if err != nil { + return err + } + inbound.Settings = string(modifiedSettings) + return s.UpdateInboundClient(inbound, clientId) +} + func (s *InboundService) ToggleClientEnableByEmail(clientEmail string) (bool, error) { _, inbound, err := s.GetClientInboundByEmail(clientEmail) if err != nil { diff --git a/web/service/tgbot.go b/web/service/tgbot.go index 108af567..973ee97f 100644 --- a/web/service/tgbot.go +++ b/web/service/tgbot.go @@ -13,10 +13,13 @@ import ( "x-ui/util/common" "x-ui/xray" - tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" + "github.com/mymmrac/telego" + th "github.com/mymmrac/telego/telegohandler" + tu "github.com/mymmrac/telego/telegoutil" ) -var bot *tgbotapi.BotAPI +var bot *telego.Bot +var botHandler *th.BotHandler var adminIds []int64 var isRunning bool @@ -61,12 +64,11 @@ func (t *Tgbot) Start() error { adminIds = append(adminIds, int64(id)) } - bot, err = tgbotapi.NewBotAPI(tgBottoken) + bot, err = telego.NewBot(tgBottoken) if err != nil { fmt.Println("Get tgbot's api error:", err) return err } - bot.Debug = false // listen for TG bot income messages if !isRunning { @@ -83,38 +85,61 @@ func (t *Tgbot) IsRunnging() bool { } func (t *Tgbot) Stop() { - bot.StopReceivingUpdates() + botHandler.Stop() + bot.StopLongPolling() logger.Info("Stop Telegram receiver ...") isRunning = false adminIds = nil } func (t *Tgbot) OnReceive() { - u := tgbotapi.NewUpdate(0) - u.Timeout = 10 + params := telego.GetUpdatesParams{ + Timeout: 10, + } - updates := bot.GetUpdatesChan(u) + updates, _ := bot.UpdatesViaLongPolling(¶ms) - for update := range updates { - tgId := update.FromChat().ID - chatId := update.FromChat().ChatConfig().ChatID - isAdmin := checkAdmin(tgId) - if update.Message == nil { - if update.CallbackQuery != nil { - t.asnwerCallback(update.CallbackQuery, isAdmin) - } - } else { - if update.Message.IsCommand() { - t.answerCommand(update.Message, chatId, isAdmin) + botHandler, _ = th.NewBotHandler(bot, updates) + + botHandler.HandleMessage(func(bot *telego.Bot, message telego.Message) { + t.SendMsgToTgbot(message.Chat.ID, "Custom Keyboard Closed!", tu.ReplyKeyboardRemove()) + }, th.TextEqual("❌ Close Keyboard")) + + 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()) + + 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()) + + botHandler.Start() } -func (t *Tgbot) answerCommand(message *tgbotapi.Message, chatId int64, isAdmin bool) { +func (t *Tgbot) answerCommand(message *telego.Message, chatId int64, isAdmin bool) { msg := "" + + command, commandArgs := tu.ParseCommand(message.Text) + // Extract the command from the Message. - switch message.Command() { + switch command { case "help": msg = "This bot is providing you some specefic data from the server.\n\n Please choose:" case "start": @@ -127,18 +152,18 @@ func (t *Tgbot) answerCommand(message *tgbotapi.Message, chatId int64, isAdmin b case "status": msg = "bot is ok ✅" case "usage": - if len(message.CommandArguments()) > 1 { + if len(commandArgs) > 0 { if isAdmin { - t.searchClient(chatId, message.CommandArguments()) + t.searchClient(chatId, commandArgs[0]) } else { - t.searchForClient(chatId, message.CommandArguments()) + t.searchForClient(chatId, commandArgs[0]) } } else { msg = "❗Please provide a text for search!" } case "inbound": - if isAdmin { - t.searchInbound(chatId, message.CommandArguments()) + if isAdmin && len(commandArgs) > 0 { + t.searchInbound(chatId, commandArgs[0]) } else { msg = "❗ Unknown command" } @@ -148,7 +173,9 @@ func (t *Tgbot) answerCommand(message *tgbotapi.Message, chatId int64, isAdmin b t.SendAnswer(chatId, msg, isAdmin) } -func (t *Tgbot) asnwerCallback(callbackQuery *tgbotapi.CallbackQuery, isAdmin bool) { +func (t *Tgbot) asnwerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool) { + + chatId := callbackQuery.Message.Chat.ID if isAdmin { dataArray := strings.Split(callbackQuery.Data, " ") @@ -156,62 +183,68 @@ func (t *Tgbot) asnwerCallback(callbackQuery *tgbotapi.CallbackQuery, isAdmin bo email := dataArray[1] switch dataArray[0] { case "client_refresh": - t.sendCallbackAnswerTgBot(callbackQuery.ID, fmt.Sprintf("✅ %s : Client Refreshed successfully.", email)) - t.searchClient(callbackQuery.From.ID, email, callbackQuery.Message.MessageID) + t.sendCallbackAnswerTgBot(callbackQuery.ID, fmt.Sprintf("✅ %s : Client refreshed successfully.", email)) + t.searchClient(chatId, email, callbackQuery.Message.MessageID) case "client_cancel": t.sendCallbackAnswerTgBot(callbackQuery.ID, fmt.Sprintf("❌ %s : Operation canceled.", email)) - t.searchClient(callbackQuery.From.ID, email, callbackQuery.Message.MessageID) + t.searchClient(chatId, email, callbackQuery.Message.MessageID) case "ips_refresh": - t.sendCallbackAnswerTgBot(callbackQuery.ID, fmt.Sprintf("✅ %s : IPs Refreshed successfully.", email)) - t.searchClientIps(callbackQuery.From.ID, email, callbackQuery.Message.MessageID) + t.sendCallbackAnswerTgBot(callbackQuery.ID, fmt.Sprintf("✅ %s : IPs refreshed successfully.", email)) + t.searchClientIps(chatId, email, callbackQuery.Message.MessageID) case "ips_cancel": t.sendCallbackAnswerTgBot(callbackQuery.ID, fmt.Sprintf("❌ %s : Operation canceled.", email)) - t.searchClientIps(callbackQuery.From.ID, email, callbackQuery.Message.MessageID) + t.searchClientIps(chatId, email, callbackQuery.Message.MessageID) + 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) case "reset_traffic": - var inlineKeyboard = tgbotapi.NewInlineKeyboardMarkup( - tgbotapi.NewInlineKeyboardRow( - tgbotapi.NewInlineKeyboardButtonData("❌ Cancel Reset", "client_cancel "+email), + inlineKeyboard := tu.InlineKeyboard( + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("❌ Cancel Reset").WithCallbackData("client_cancel "+email), ), - tgbotapi.NewInlineKeyboardRow( - tgbotapi.NewInlineKeyboardButtonData("✅ Confirm Reset Traffic?", "reset_traffic_c "+email), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("✅ Confirm Reset Traffic?").WithCallbackData("reset_traffic_c "+email), ), ) - t.editMessageCallbackTgBot(callbackQuery.From.ID, callbackQuery.Message.MessageID, inlineKeyboard) + t.editMessageCallbackTgBot(chatId, callbackQuery.Message.MessageID, inlineKeyboard) case "reset_traffic_c": err := t.inboundService.ResetClientTrafficByEmail(email) if err == nil { t.xrayService.SetToNeedRestart() t.sendCallbackAnswerTgBot(callbackQuery.ID, fmt.Sprintf("✅ %s : Traffic reset successfully.", email)) - t.searchClient(callbackQuery.From.ID, email, callbackQuery.Message.MessageID) + t.searchClient(chatId, email, callbackQuery.Message.MessageID) } else { t.sendCallbackAnswerTgBot(callbackQuery.ID, "❗ Error in Operation.") } case "reset_exp": - var inlineKeyboard = tgbotapi.NewInlineKeyboardMarkup( - tgbotapi.NewInlineKeyboardRow( - tgbotapi.NewInlineKeyboardButtonData("❌ Cancel Reset", "client_cancel "+email), + var inlineKeyboard = tu.InlineKeyboard( + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("❌ Cancel Reset").WithCallbackData("client_cancel "+email), ), - tgbotapi.NewInlineKeyboardRow( - tgbotapi.NewInlineKeyboardButtonData("♾ Unlimited", "reset_exp_c "+email+" 0"), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("♾ Unlimited").WithCallbackData("reset_exp_c "+email+" 0"), ), - tgbotapi.NewInlineKeyboardRow( - tgbotapi.NewInlineKeyboardButtonData("1 Month", "reset_exp_c "+email+" 30"), - tgbotapi.NewInlineKeyboardButtonData("2 Months", "reset_exp_c "+email+" 60"), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("1 Month").WithCallbackData("reset_exp_c "+email+" 30"), + tu.InlineKeyboardButton("2 Months").WithCallbackData("reset_exp_c "+email+" 60"), ), - tgbotapi.NewInlineKeyboardRow( - tgbotapi.NewInlineKeyboardButtonData("3 Months", "reset_exp_c "+email+" 90"), - tgbotapi.NewInlineKeyboardButtonData("6 Months", "reset_exp_c "+email+" 180"), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("3 Months").WithCallbackData("reset_exp_c "+email+" 90"), + tu.InlineKeyboardButton("6 Months").WithCallbackData("reset_exp_c "+email+" 180"), ), - tgbotapi.NewInlineKeyboardRow( - tgbotapi.NewInlineKeyboardButtonData("9 Months", "reset_exp_c "+email+" 270"), - tgbotapi.NewInlineKeyboardButtonData("12 Months", "reset_exp_c "+email+" 360"), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("9 Months").WithCallbackData("reset_exp_c "+email+" 270"), + tu.InlineKeyboardButton("12 Months").WithCallbackData("reset_exp_c "+email+" 360"), ), - tgbotapi.NewInlineKeyboardRow( - tgbotapi.NewInlineKeyboardButtonData("10 Days", "reset_exp_c "+email+" 10"), - tgbotapi.NewInlineKeyboardButtonData("20 Days", "reset_exp_c "+email+" 20"), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("10 Days").WithCallbackData("reset_exp_c "+email+" 10"), + tu.InlineKeyboardButton("20 Days").WithCallbackData("reset_exp_c "+email+" 20"), ), ) - t.editMessageCallbackTgBot(callbackQuery.From.ID, callbackQuery.Message.MessageID, inlineKeyboard) + t.editMessageCallbackTgBot(chatId, callbackQuery.Message.MessageID, inlineKeyboard) case "reset_exp_c": if len(dataArray) == 3 { days, err := strconv.Atoi(dataArray[2]) @@ -224,41 +257,41 @@ func (t *Tgbot) asnwerCallback(callbackQuery *tgbotapi.CallbackQuery, isAdmin bo if err == nil { t.xrayService.SetToNeedRestart() t.sendCallbackAnswerTgBot(callbackQuery.ID, fmt.Sprintf("✅ %s : Expire days reset successfully.", email)) - t.searchClient(callbackQuery.From.ID, email, callbackQuery.Message.MessageID) + t.searchClient(chatId, email, callbackQuery.Message.MessageID) return } } } t.sendCallbackAnswerTgBot(callbackQuery.ID, "❗ Error in Operation.") - t.searchClient(callbackQuery.From.ID, email, callbackQuery.Message.MessageID) + t.searchClient(chatId, email, callbackQuery.Message.MessageID) case "ip_limit": - var inlineKeyboard = tgbotapi.NewInlineKeyboardMarkup( - tgbotapi.NewInlineKeyboardRow( - tgbotapi.NewInlineKeyboardButtonData("❌ Cancel IP Limit", "client_cancel "+email), + inlineKeyboard := tu.InlineKeyboard( + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("❌ Cancel IP Limit").WithCallbackData("client_cancel "+email), ), - tgbotapi.NewInlineKeyboardRow( - tgbotapi.NewInlineKeyboardButtonData("♾ Unlimited", "ip_limit_c "+email+" 0"), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("♾ Unlimited").WithCallbackData("ip_limit_c "+email+" 0"), ), - tgbotapi.NewInlineKeyboardRow( - tgbotapi.NewInlineKeyboardButtonData("1", "ip_limit_c "+email+" 1"), - tgbotapi.NewInlineKeyboardButtonData("2", "ip_limit_c "+email+" 2"), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("1").WithCallbackData("ip_limit_c "+email+" 1"), + tu.InlineKeyboardButton("2").WithCallbackData("ip_limit_c "+email+" 2"), ), - tgbotapi.NewInlineKeyboardRow( - tgbotapi.NewInlineKeyboardButtonData("3", "ip_limit_c "+email+" 3"), - tgbotapi.NewInlineKeyboardButtonData("4", "ip_limit_c "+email+" 4"), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("3").WithCallbackData("ip_limit_c "+email+" 3"), + tu.InlineKeyboardButton("4").WithCallbackData("ip_limit_c "+email+" 4"), ), - tgbotapi.NewInlineKeyboardRow( - tgbotapi.NewInlineKeyboardButtonData("5", "ip_limit_c "+email+" 5"), - tgbotapi.NewInlineKeyboardButtonData("6", "ip_limit_c "+email+" 6"), - tgbotapi.NewInlineKeyboardButtonData("7", "ip_limit_c "+email+" 7"), + 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"), ), - tgbotapi.NewInlineKeyboardRow( - tgbotapi.NewInlineKeyboardButtonData("8", "ip_limit_c "+email+" 8"), - tgbotapi.NewInlineKeyboardButtonData("9", "ip_limit_c "+email+" 9"), - tgbotapi.NewInlineKeyboardButtonData("10", "ip_limit_c "+email+" 10"), + 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"), ), ) - t.editMessageCallbackTgBot(callbackQuery.From.ID, callbackQuery.Message.MessageID, inlineKeyboard) + t.editMessageCallbackTgBot(chatId, callbackQuery.Message.MessageID, inlineKeyboard) case "ip_limit_c": if len(dataArray) == 3 { count, err := strconv.Atoi(dataArray[2]) @@ -267,34 +300,60 @@ func (t *Tgbot) asnwerCallback(callbackQuery *tgbotapi.CallbackQuery, isAdmin bo if err == nil { t.xrayService.SetToNeedRestart() t.sendCallbackAnswerTgBot(callbackQuery.ID, fmt.Sprintf("✅ %s : IP limit %d saved successfully.", email, count)) - t.searchClient(callbackQuery.From.ID, email, callbackQuery.Message.MessageID) + t.searchClient(chatId, email, callbackQuery.Message.MessageID) return } } } t.sendCallbackAnswerTgBot(callbackQuery.ID, "❗ Error in Operation.") - t.searchClient(callbackQuery.From.ID, email, callbackQuery.Message.MessageID) + t.searchClient(chatId, email, callbackQuery.Message.MessageID) case "clear_ips": - var inlineKeyboard = tgbotapi.NewInlineKeyboardMarkup( - tgbotapi.NewInlineKeyboardRow( - tgbotapi.NewInlineKeyboardButtonData("❌ Cancel", "ips_cancel "+email), + inlineKeyboard := tu.InlineKeyboard( + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("❌ Cancel").WithCallbackData("ips_cancel "+email), ), - tgbotapi.NewInlineKeyboardRow( - tgbotapi.NewInlineKeyboardButtonData("✅ Confirm Clear IPs?", "clear_ips_c "+email), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("✅ Confirm Clear IPs?").WithCallbackData("clear_ips_c "+email), ), ) - t.editMessageCallbackTgBot(callbackQuery.From.ID, callbackQuery.Message.MessageID, inlineKeyboard) + t.editMessageCallbackTgBot(chatId, callbackQuery.Message.MessageID, inlineKeyboard) case "clear_ips_c": err := t.inboundService.ClearClientIps(email) if err == nil { t.sendCallbackAnswerTgBot(callbackQuery.ID, fmt.Sprintf("✅ %s : IPs cleared successfully.", email)) - t.searchClientIps(callbackQuery.From.ID, email, callbackQuery.Message.MessageID) + t.searchClientIps(chatId, email, callbackQuery.Message.MessageID) } else { t.sendCallbackAnswerTgBot(callbackQuery.ID, "❗ Error in Operation.") } case "ip_log": t.sendCallbackAnswerTgBot(callbackQuery.ID, fmt.Sprintf("✅ %s : Get IP Log.", email)) - t.searchClientIps(callbackQuery.From.ID, email) + t.searchClientIps(chatId, email) + case "tg_user": + t.sendCallbackAnswerTgBot(callbackQuery.ID, fmt.Sprintf("✅ %s : Get Telegram User Info.", email)) + t.clientTelegramUserInfo(chatId, email) + 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.") + } case "toggle_enable": enabled, err := t.inboundService.ToggleClientEnableByEmail(email) if err == nil { @@ -304,7 +363,7 @@ func (t *Tgbot) asnwerCallback(callbackQuery *tgbotapi.CallbackQuery, isAdmin bo } else { t.sendCallbackAnswerTgBot(callbackQuery.ID, fmt.Sprintf("✅ %s : Disabled successfully.", email)) } - t.searchClient(callbackQuery.From.ID, email, callbackQuery.Message.MessageID) + t.searchClient(chatId, email, callbackQuery.Message.MessageID) } else { t.sendCallbackAnswerTgBot(callbackQuery.ID, "❗ Error in Operation.") } @@ -315,26 +374,23 @@ func (t *Tgbot) asnwerCallback(callbackQuery *tgbotapi.CallbackQuery, isAdmin bo // Respond to the callback query, telling Telegram to show the user // a message with the data received. - callback := tgbotapi.NewCallback(callbackQuery.ID, callbackQuery.Data) - if _, err := bot.Request(callback); err != nil { - logger.Warning(err) - } + t.sendCallbackAnswerTgBot(callbackQuery.ID, callbackQuery.Data) switch callbackQuery.Data { case "get_usage": - t.SendMsgToTgbot(callbackQuery.From.ID, t.getServerUsage()) + t.SendMsgToTgbot(chatId, t.getServerUsage()) case "inbounds": - t.SendMsgToTgbot(callbackQuery.From.ID, t.getInboundUsages()) + t.SendMsgToTgbot(chatId, t.getInboundUsages()) case "deplete_soon": - t.SendMsgToTgbot(callbackQuery.From.ID, t.getExhausted()) + t.SendMsgToTgbot(chatId, t.getExhausted()) case "get_backup": - t.sendBackup(callbackQuery.From.ID) + t.sendBackup(chatId) case "client_traffic": - t.getClientUsage(callbackQuery.From.ID, callbackQuery.From.UserName, strconv.FormatInt(callbackQuery.From.ID, 10)) + t.getClientUsage(chatId, callbackQuery.From.Username, strconv.FormatInt(callbackQuery.From.ID, 10)) case "client_commands": - t.SendMsgToTgbot(callbackQuery.From.ID, "To search for statistics, just use folowing command:\r\n \r\n/usage [UID|Password]\r\n \r\nUse UID for vmess/vless and Password for Trojan.") + t.SendMsgToTgbot(chatId, "To search for statistics, just use folowing command:\r\n \r\n/usage [UID|Password]\r\n \r\nUse UID for vmess/vless and Password for Trojan.") case "commands": - t.SendMsgToTgbot(callbackQuery.From.ID, "Search for a client email:\r\n/usage email\r\n \r\nSearch for inbounds (with client stats):\r\n/inbound [remark]") + t.SendMsgToTgbot(chatId, "Search for a client email:\r\n/usage email\r\n \r\nSearch for inbounds (with client stats):\r\n/inbound [remark]") } } @@ -348,39 +404,42 @@ func checkAdmin(tgId int64) bool { } func (t *Tgbot) SendAnswer(chatId int64, msg string, isAdmin bool) { - var numericKeyboard = tgbotapi.NewInlineKeyboardMarkup( - tgbotapi.NewInlineKeyboardRow( - tgbotapi.NewInlineKeyboardButtonData("Server Usage", "get_usage"), - tgbotapi.NewInlineKeyboardButtonData("Get DB Backup", "get_backup"), + numericKeyboard := tu.InlineKeyboard( + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("Server Usage").WithCallbackData("get_usage"), + tu.InlineKeyboardButton("Get DB Backup").WithCallbackData("get_backup"), ), - tgbotapi.NewInlineKeyboardRow( - tgbotapi.NewInlineKeyboardButtonData("Get Inbounds", "inbounds"), - tgbotapi.NewInlineKeyboardButtonData("Deplete soon", "deplete_soon"), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("Get Inbounds").WithCallbackData("inbounds"), + tu.InlineKeyboardButton("Deplete soon").WithCallbackData("deplete_soon"), ), - tgbotapi.NewInlineKeyboardRow( - tgbotapi.NewInlineKeyboardButtonData("Commands", "commands"), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("Commands").WithCallbackData("commands"), ), ) - var numericKeyboardClient = tgbotapi.NewInlineKeyboardMarkup( - tgbotapi.NewInlineKeyboardRow( - tgbotapi.NewInlineKeyboardButtonData("Get Usage", "client_traffic"), - tgbotapi.NewInlineKeyboardButtonData("Commands", "client_commands"), + numericKeyboardClient := tu.InlineKeyboard( + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("Get Usage").WithCallbackData("client_traffic"), + tu.InlineKeyboardButton("Commands").WithCallbackData("client_commands"), ), ) - msgConfig := tgbotapi.NewMessage(chatId, msg) - msgConfig.ParseMode = "HTML" - if isAdmin { - msgConfig.ReplyMarkup = numericKeyboard - } else { - msgConfig.ReplyMarkup = numericKeyboardClient + params := telego.SendMessageParams{ + ChatID: tu.ID(chatId), + Text: msg, + ParseMode: "HTML", } - _, err := bot.Send(msgConfig) + if isAdmin { + params.ReplyMarkup = numericKeyboard + } else { + params.ReplyMarkup = numericKeyboardClient + } + _, err := bot.SendMessage(¶ms) if err != nil { logger.Warning("Error sending telegram message :", err) } } -func (t *Tgbot) SendMsgToTgbot(tgid int64, msg string, inlineKeyboard ...tgbotapi.InlineKeyboardMarkup) { +func (t *Tgbot) SendMsgToTgbot(chatId int64, msg string, replyMarkup ...telego.ReplyMarkup) { if !isRunning { return } @@ -402,12 +461,15 @@ func (t *Tgbot) SendMsgToTgbot(tgid int64, msg string, inlineKeyboard ...tgbotap allMessages = append(allMessages, msg) } for _, message := range allMessages { - info := tgbotapi.NewMessage(tgid, message) - info.ParseMode = "HTML" - if len(inlineKeyboard) > 0 { - info.ReplyMarkup = inlineKeyboard[0] + params := telego.SendMessageParams{ + ChatID: tu.ID(chatId), + Text: message, + ParseMode: "HTML", } - _, err := bot.Send(info) + if len(replyMarkup) > 0 { + params.ReplyMarkup = replyMarkup[0] + } + _, err := bot.SendMessage(¶ms) if err != nil { logger.Warning("Error sending telegram message :", err) } @@ -589,12 +651,12 @@ func (t *Tgbot) searchClientIps(chatId int64, email string, messageID ...int) { ips = "No IP Record" } output := fmt.Sprintf("📧 Email: %s\r\n🔢 IPs: \r\n%s\r\n", email, ips) - var inlineKeyboard = tgbotapi.NewInlineKeyboardMarkup( - tgbotapi.NewInlineKeyboardRow( - tgbotapi.NewInlineKeyboardButtonData("🔄 Refresh", "ips_refresh "+email), + inlineKeyboard := tu.InlineKeyboard( + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("🔄 Refresh").WithCallbackData("ips_refresh "+email), ), - tgbotapi.NewInlineKeyboardRow( - tgbotapi.NewInlineKeyboardButtonData("❌ Clear IPs", "clear_ips "+email), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("❌ Clear IPs").WithCallbackData("clear_ips "+email), ), ) if len(messageID) > 0 { @@ -604,6 +666,52 @@ func (t *Tgbot) searchClientIps(chatId int64, email string, messageID ...int) { } } +func (t *Tgbot) clientTelegramUserInfo(chatId int64, email string, messageID ...int) { + 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 + } + tdId := "None" + if len(client.TgID) > 0 { + tdId = client.TgID + } + 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), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("❌ Remove Telegram User").WithCallbackData("tgid_remove "+email), + ), + ) + 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().WithResizeKeyboard() + t.SendMsgToTgbot(chatId, "👤 Select a telegram user:", keyboard) + } +} + func (t *Tgbot) searchClient(chatId int64, email string, messageID ...int) { traffic, err := t.inboundService.GetClientTrafficByEmail(email) if err != nil { @@ -634,22 +742,25 @@ func (t *Tgbot) searchClient(chatId int64, email string, messageID ...int) { 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) - var inlineKeyboard = tgbotapi.NewInlineKeyboardMarkup( - tgbotapi.NewInlineKeyboardRow( - tgbotapi.NewInlineKeyboardButtonData("🔄 Refresh", "client_refresh "+email), + inlineKeyboard := tu.InlineKeyboard( + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("🔄 Refresh").WithCallbackData("client_refresh "+email), ), - tgbotapi.NewInlineKeyboardRow( - tgbotapi.NewInlineKeyboardButtonData("📈 Reset Traffic", "reset_traffic "+email), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("📈 Reset Traffic").WithCallbackData("reset_traffic "+email), ), - tgbotapi.NewInlineKeyboardRow( - tgbotapi.NewInlineKeyboardButtonData("📅 Reset Expire Days", "reset_exp "+email), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("📅 Reset Expire Days").WithCallbackData("reset_exp "+email), ), - tgbotapi.NewInlineKeyboardRow( - tgbotapi.NewInlineKeyboardButtonData("🔢 IP Log", "ip_log "+email), - tgbotapi.NewInlineKeyboardButtonData("🔢 IP Limit", "ip_limit "+email), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("🔢 IP Log").WithCallbackData("ip_log "+email), + tu.InlineKeyboardButton("🔢 IP Limit").WithCallbackData("ip_limit "+email), ), - tgbotapi.NewInlineKeyboardRow( - tgbotapi.NewInlineKeyboardButtonData("🔘 Enable / Disable", "toggle_enable "+email), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("👤 Set Telegram User").WithCallbackData("tg_user "+email), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("🔘 Enable / Disable").WithCallbackData("toggle_enable "+email), ), ) if len(messageID) > 0 { @@ -818,41 +929,81 @@ func (t *Tgbot) getExhausted() string { func (t *Tgbot) sendBackup(chatId int64) { sendingTime := time.Now().Format("2006-01-02 15:04:05") t.SendMsgToTgbot(chatId, "Backup time: "+sendingTime) - file := tgbotapi.FilePath(config.GetDBPath()) - msg := tgbotapi.NewDocument(chatId, file) - _, err := bot.Send(msg) + 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) if err != nil { logger.Warning("Error in uploading backup: ", err) } - file = tgbotapi.FilePath(xray.GetConfigPath()) - msg = tgbotapi.NewDocument(chatId, file) - _, err = bot.Send(msg) + 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) if err != nil { logger.Warning("Error in uploading config.json: ", err) } } func (t *Tgbot) sendCallbackAnswerTgBot(id string, message string) { - callback := tgbotapi.NewCallback(id, message) - if _, err := bot.Request(callback); err != nil { + params := telego.AnswerCallbackQueryParams{ + CallbackQueryID: id, + Text: message, + } + if err := bot.AnswerCallbackQuery(¶ms); err != nil { logger.Warning(err) } } -func (t *Tgbot) editMessageCallbackTgBot(chatId int64, messageID int, inlineKeyboard tgbotapi.InlineKeyboardMarkup) { - edit := tgbotapi.NewEditMessageReplyMarkup(chatId, messageID, inlineKeyboard) - if _, err := bot.Request(edit); err != nil { +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(¶ms); err != nil { logger.Warning(err) } } -func (t *Tgbot) editMessageTgBot(chatId int64, messageID int, text string, inlineKeyboard ...tgbotapi.InlineKeyboardMarkup) { - edit := tgbotapi.NewEditMessageText(chatId, messageID, text) - edit.ParseMode = "HTML" +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", + } if len(inlineKeyboard) > 0 { - edit.ReplyMarkup = &inlineKeyboard[0] + params.ReplyMarkup = inlineKeyboard[0] } - if _, err := bot.Request(edit); err != nil { + if _, err := bot.EditMessageText(¶ms); err != nil { logger.Warning(err) } } + +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 + } +}