tgbot_router.go 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376
  1. package tgbot
  2. import (
  3. "context"
  4. "fmt"
  5. "html"
  6. "slices"
  7. "strconv"
  8. "strings"
  9. "time"
  10. "github.com/mhsanaei/3x-ui/v3/internal/logger"
  11. "github.com/mymmrac/telego"
  12. th "github.com/mymmrac/telego/telegohandler"
  13. tu "github.com/mymmrac/telego/telegoutil"
  14. )
  15. // recoverBotPanic must be deferred by every bot handler entry point: telego's
  16. // dispatch has no recovery of its own, so one bad update would kill the panel.
  17. func recoverBotPanic() {
  18. if r := recover(); r != nil {
  19. logger.Error("Recovered panic in Telegram bot handler:", r)
  20. }
  21. }
  22. // runBotHandler runs a bot handler on a worker slot and recovers panics: a bad
  23. // callback must not take down the whole panel, the way a cron panic would not.
  24. func runBotHandler(fn func()) {
  25. messageWorkerPool <- struct{}{}
  26. defer func() { <-messageWorkerPool }()
  27. defer recoverBotPanic()
  28. fn()
  29. }
  30. // chooseInboundClient fetches the inbound once and reuses the row: the inline
  31. // keyboard outlives the inbound, so a stale tap must answer an error, not panic.
  32. func (t *Tgbot) chooseInboundClient(callbackQuery *telego.CallbackQuery, chatId int64, inboundID int, action string) {
  33. inbound, err := t.inboundService.GetInbound(inboundID)
  34. if err != nil {
  35. logger.Warning("chooseInboundClient GetInbound failed:", err)
  36. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.getInboundsFailed"))
  37. return
  38. }
  39. clientsKB, err := t.getInboundClientsFor(inbound, action)
  40. if err != nil {
  41. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  42. return
  43. }
  44. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.chooseClient", "Inbound=="+inbound.Remark), clientsKB)
  45. }
  46. // OnReceive starts the message receiving loop for the Telegram bot.
  47. func (t *Tgbot) OnReceive() {
  48. params := telego.GetUpdatesParams{
  49. Timeout: 20, // Reduced timeout to detect connection issues faster
  50. }
  51. // Strict singleton: never start a second long-polling loop.
  52. tgBotMutex.Lock()
  53. if botCancel != nil || isRunning {
  54. tgBotMutex.Unlock()
  55. logger.Warning("TgBot OnReceive called while already running; ignoring.")
  56. return
  57. }
  58. ctx, cancel := context.WithCancel(context.Background())
  59. botCancel = cancel
  60. isRunning = true
  61. // Add to WaitGroup before releasing the lock so StopBot() can't return
  62. // before this receiver goroutine is accounted for.
  63. botWG.Add(1)
  64. tgBotMutex.Unlock()
  65. // Get updates channel using the context with shorter timeout for better error recovery
  66. updates, _ := bot.UpdatesViaLongPolling(ctx, &params)
  67. go func() {
  68. defer botWG.Done()
  69. h, _ := th.NewBotHandler(bot, updates)
  70. tgBotMutex.Lock()
  71. botHandler = h
  72. tgBotMutex.Unlock()
  73. h.HandleMessage(func(ctx *th.Context, message telego.Message) error {
  74. defer recoverBotPanic()
  75. userStateMgr.clear(message.Chat.ID)
  76. t.SendMsgToTgbot(message.Chat.ID, t.I18nBot("tgbot.keyboardClosed"), tu.ReplyKeyboardRemove())
  77. return nil
  78. }, th.TextEqual(t.I18nBot("tgbot.buttons.closeKeyboard")))
  79. h.HandleMessage(func(ctx *th.Context, message telego.Message) error {
  80. defer recoverBotPanic()
  81. if !t.isCommandForCurrentBot(&message) {
  82. return nil
  83. }
  84. // Use goroutine with worker pool for concurrent command processing
  85. go runBotHandler(func() {
  86. userStateMgr.clear(message.Chat.ID)
  87. t.answerCommand(&message, message.Chat.ID, checkAdmin(message.From.ID))
  88. })
  89. return nil
  90. }, th.AnyCommand())
  91. h.HandleCallbackQuery(func(ctx *th.Context, query telego.CallbackQuery) error {
  92. // Use goroutine with worker pool for concurrent callback processing
  93. go runBotHandler(func() {
  94. userStateMgr.clear(query.Message.GetChat().ID)
  95. t.answerCallback(&query, checkAdmin(query.From.ID))
  96. })
  97. return nil
  98. }, th.AnyCallbackQueryWithMessage())
  99. h.HandleMessage(func(ctx *th.Context, message telego.Message) error {
  100. defer recoverBotPanic()
  101. userStateMgr.maybePrune(time.Hour)
  102. if userState, exists := userStateMgr.get(message.Chat.ID); exists {
  103. switch userState {
  104. case "awaiting_email":
  105. if client_Email == strings.TrimSpace(message.Text) {
  106. t.SendMsgToTgbotDeleteAfter(message.Chat.ID, t.I18nBot("tgbot.messages.using_default_value"), 3, tu.ReplyKeyboardRemove())
  107. userStateMgr.clear(message.Chat.ID)
  108. return nil
  109. }
  110. client_Email = strings.TrimSpace(message.Text)
  111. if t.isSingleWord(client_Email) {
  112. userStateMgr.set(message.Chat.ID, "awaiting_email")
  113. cancel_btn_markup := tu.InlineKeyboard(
  114. tu.InlineKeyboardRow(
  115. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"),
  116. ),
  117. )
  118. t.SendMsgToTgbot(message.Chat.ID, t.I18nBot("tgbot.messages.incorrect_input"), cancel_btn_markup)
  119. } else {
  120. t.SendMsgToTgbotDeleteAfter(message.Chat.ID, t.I18nBot("tgbot.messages.received_email"), 3, tu.ReplyKeyboardRemove())
  121. userStateMgr.clear(message.Chat.ID)
  122. t.addClient(message.Chat.ID, t.BuildClientDraftMessage())
  123. }
  124. case "awaiting_comment":
  125. if client_Comment == strings.TrimSpace(message.Text) {
  126. t.SendMsgToTgbotDeleteAfter(message.Chat.ID, t.I18nBot("tgbot.messages.using_default_value"), 3, tu.ReplyKeyboardRemove())
  127. userStateMgr.clear(message.Chat.ID)
  128. return nil
  129. }
  130. client_Comment = strings.TrimSpace(message.Text)
  131. t.SendMsgToTgbotDeleteAfter(message.Chat.ID, t.I18nBot("tgbot.messages.received_comment"), 3, tu.ReplyKeyboardRemove())
  132. userStateMgr.clear(message.Chat.ID)
  133. t.addClient(message.Chat.ID, t.BuildClientDraftMessage())
  134. case "awaiting_tg_id":
  135. input := strings.TrimSpace(message.Text)
  136. if input == "" || input == "-" || strings.EqualFold(input, "none") {
  137. client_TgID = ""
  138. t.SendMsgToTgbotDeleteAfter(message.Chat.ID, t.I18nBot("tgbot.messages.using_default_value"), 3, tu.ReplyKeyboardRemove())
  139. userStateMgr.clear(message.Chat.ID)
  140. t.addClient(message.Chat.ID, t.BuildClientDraftMessage())
  141. return nil
  142. }
  143. if _, err := strconv.ParseInt(input, 10, 64); err != nil {
  144. cancel_btn_markup := tu.InlineKeyboard(
  145. tu.InlineKeyboardRow(
  146. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"),
  147. ),
  148. )
  149. t.SendMsgToTgbot(message.Chat.ID, t.I18nBot("tgbot.messages.incorrect_input"), cancel_btn_markup)
  150. return nil
  151. }
  152. client_TgID = input
  153. t.SendMsgToTgbotDeleteAfter(message.Chat.ID, t.I18nBot("tgbot.messages.userSaved"), 3, tu.ReplyKeyboardRemove())
  154. userStateMgr.clear(message.Chat.ID)
  155. t.addClient(message.Chat.ID, t.BuildClientDraftMessage())
  156. }
  157. } else {
  158. if message.UsersShared != nil {
  159. if checkAdmin(message.From.ID) {
  160. for _, sharedUser := range message.UsersShared.Users {
  161. userID := sharedUser.UserID
  162. needRestart, err := t.clientService.SetClientTelegramUserID(&t.inboundService, message.UsersShared.RequestID, userID)
  163. if needRestart {
  164. t.xrayService.SetToNeedRestart()
  165. }
  166. output := ""
  167. if err != nil {
  168. output += t.I18nBot("tgbot.messages.selectUserFailed")
  169. } else {
  170. output += t.I18nBot("tgbot.messages.userSaved")
  171. }
  172. t.SendMsgToTgbot(message.Chat.ID, output, tu.ReplyKeyboardRemove())
  173. }
  174. } else {
  175. t.SendMsgToTgbot(message.Chat.ID, t.I18nBot("tgbot.noResult"), tu.ReplyKeyboardRemove())
  176. }
  177. }
  178. }
  179. return nil
  180. }, th.AnyMessage())
  181. _ = h.Start()
  182. }()
  183. }
  184. // answerCommand processes incoming command messages from Telegram users.
  185. func (t *Tgbot) answerCommand(message *telego.Message, chatId int64, isAdmin bool) {
  186. msg, onlyMessage := "", false
  187. command, _, commandArgs := tu.ParseCommand(message.Text)
  188. // Helper function to handle unknown commands.
  189. handleUnknownCommand := func() {
  190. msg += t.I18nBot("tgbot.commands.unknown")
  191. }
  192. // Handle the command.
  193. switch command {
  194. case "help":
  195. msg += t.I18nBot("tgbot.commands.help")
  196. msg += t.I18nBot("tgbot.commands.pleaseChoose")
  197. case "start":
  198. msg += t.I18nBot("tgbot.commands.start", "Firstname=="+html.EscapeString(message.From.FirstName))
  199. if isAdmin {
  200. msg += t.I18nBot("tgbot.commands.welcome", "Hostname=="+hostname)
  201. }
  202. msg += "\n\n" + t.I18nBot("tgbot.commands.pleaseChoose")
  203. case "status":
  204. onlyMessage = true
  205. msg += t.I18nBot("tgbot.commands.status")
  206. case "id":
  207. onlyMessage = true
  208. msg += t.I18nBot("tgbot.commands.getID", "ID=="+strconv.FormatInt(message.From.ID, 10))
  209. case "usage":
  210. onlyMessage = true
  211. if len(commandArgs) > 0 {
  212. if isAdmin {
  213. t.searchClient(chatId, commandArgs[0])
  214. } else {
  215. t.getClientUsage(chatId, message.From.ID, commandArgs[0])
  216. }
  217. } else {
  218. msg += t.I18nBot("tgbot.commands.usage")
  219. }
  220. case "inbound":
  221. onlyMessage = true
  222. if isAdmin && len(commandArgs) > 0 {
  223. t.searchInbound(chatId, commandArgs[0])
  224. } else {
  225. handleUnknownCommand()
  226. }
  227. case "restart":
  228. onlyMessage = true
  229. if isAdmin {
  230. if len(commandArgs) == 0 {
  231. if t.xrayService.IsXrayRunning() {
  232. err := t.xrayService.RestartXray(true)
  233. if err != nil {
  234. msg += t.I18nBot("tgbot.commands.restartFailed", "Error=="+err.Error())
  235. } else {
  236. msg += t.I18nBot("tgbot.commands.restartSuccess")
  237. }
  238. } else {
  239. msg += t.I18nBot("tgbot.commands.xrayNotRunning")
  240. }
  241. } else {
  242. handleUnknownCommand()
  243. msg += t.I18nBot("tgbot.commands.restartUsage")
  244. }
  245. } else {
  246. handleUnknownCommand()
  247. }
  248. case "clearall":
  249. onlyMessage = true
  250. if isAdmin {
  251. inlineKeyboard := tu.InlineKeyboard(
  252. tu.InlineKeyboardRow(
  253. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancelReset")).WithCallbackData(t.encodeQuery("reset_all_traffics_cancel")),
  254. ),
  255. tu.InlineKeyboardRow(
  256. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.confirmResetTraffic")).WithCallbackData(t.encodeQuery("reset_all_traffics_c")),
  257. ),
  258. )
  259. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.messages.AreYouSure"), inlineKeyboard)
  260. } else {
  261. handleUnknownCommand()
  262. }
  263. default:
  264. handleUnknownCommand()
  265. }
  266. if msg != "" {
  267. t.sendResponse(chatId, msg, onlyMessage, isAdmin)
  268. }
  269. }
  270. func (t *Tgbot) isCommandForCurrentBot(message *telego.Message) bool {
  271. return isCommandForBot(message.Text, botUsername())
  272. }
  273. func botUsername() string {
  274. if bot == nil {
  275. return ""
  276. }
  277. return bot.Username()
  278. }
  279. func isCommandForBot(text string, username string) bool {
  280. _, commandUsername, _ := tu.ParseCommand(text)
  281. return commandUsername == "" || username == "" || strings.EqualFold(commandUsername, username)
  282. }
  283. // answerCallback processes callback queries from inline keyboards.
  284. func (t *Tgbot) answerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool) {
  285. chatId := callbackQuery.Message.GetChat().ID
  286. if isAdmin {
  287. // get query from hash storage
  288. decodedQuery, err := t.decodeQuery(callbackQuery.Data)
  289. if err != nil {
  290. // A button older than the 20-minute hash window is the common case
  291. // here; the answer clears it, the message outlives a failed send.
  292. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.noQuery"))
  293. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.noQuery"))
  294. return
  295. }
  296. dataArray := strings.Split(decodedQuery, " ")
  297. if len(dataArray) >= 2 && len(dataArray[1]) > 0 {
  298. email := dataArray[1]
  299. switch dataArray[0] {
  300. case "get_clients_for_sub":
  301. inboundIdInt, err := strconv.Atoi(dataArray[1])
  302. if err != nil {
  303. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  304. return
  305. }
  306. t.chooseInboundClient(callbackQuery, chatId, inboundIdInt, "client_sub_links")
  307. case "get_clients_for_individual":
  308. inboundIdInt, err := strconv.Atoi(dataArray[1])
  309. if err != nil {
  310. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  311. return
  312. }
  313. t.chooseInboundClient(callbackQuery, chatId, inboundIdInt, "client_individual_links")
  314. case "get_clients_for_qr":
  315. inboundIdInt, err := strconv.Atoi(dataArray[1])
  316. if err != nil {
  317. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  318. return
  319. }
  320. t.chooseInboundClient(callbackQuery, chatId, inboundIdInt, "client_qr_links")
  321. case "client_sub_links":
  322. t.sendClientSubLinks(chatId, email)
  323. return
  324. case "client_individual_links":
  325. t.sendClientIndividualLinks(chatId, email)
  326. return
  327. case "client_qr_links":
  328. t.sendClientQRLinks(chatId, email)
  329. return
  330. case "client_get_usage":
  331. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.messages.email", "Email=="+email))
  332. t.searchClient(chatId, email)
  333. case "client_refresh":
  334. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.clientRefreshSuccess", "Email=="+email))
  335. t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
  336. case "client_cancel":
  337. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.canceled", "Email=="+email))
  338. t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
  339. case "ips_refresh":
  340. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.IpRefreshSuccess", "Email=="+email))
  341. t.searchClientIps(chatId, email, callbackQuery.Message.GetMessageID())
  342. case "ips_cancel":
  343. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.canceled", "Email=="+email))
  344. t.searchClientIps(chatId, email, callbackQuery.Message.GetMessageID())
  345. case "tgid_refresh":
  346. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.TGIdRefreshSuccess", "Email=="+email))
  347. t.clientTelegramUserInfo(chatId, email, callbackQuery.Message.GetMessageID())
  348. case "tgid_cancel":
  349. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.canceled", "Email=="+email))
  350. t.clientTelegramUserInfo(chatId, email, callbackQuery.Message.GetMessageID())
  351. case "reset_traffic":
  352. inlineKeyboard := tu.InlineKeyboard(
  353. tu.InlineKeyboardRow(
  354. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancelReset")).WithCallbackData(t.encodeQuery("client_cancel "+email)),
  355. ),
  356. tu.InlineKeyboardRow(
  357. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.confirmResetTraffic")).WithCallbackData(t.encodeQuery("reset_traffic_c "+email)),
  358. ),
  359. )
  360. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  361. case "reset_traffic_c":
  362. err := t.inboundService.ResetClientTrafficByEmail(email)
  363. if err == nil {
  364. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.resetTrafficSuccess", "Email=="+email))
  365. t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
  366. } else {
  367. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  368. }
  369. case "limit_traffic":
  370. inlineKeyboard := tu.InlineKeyboard(
  371. tu.InlineKeyboardRow(
  372. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData(t.encodeQuery("client_cancel "+email)),
  373. ),
  374. tu.InlineKeyboardRow(
  375. tu.InlineKeyboardButton(t.I18nBot("tgbot.unlimited")).WithCallbackData(t.encodeQuery("limit_traffic_c "+email+" 0")),
  376. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.custom")).WithCallbackData(t.encodeQuery("limit_traffic_in "+email+" 0")),
  377. ),
  378. tu.InlineKeyboardRow(
  379. tu.InlineKeyboardButton("1 GB").WithCallbackData(t.encodeQuery("limit_traffic_c "+email+" 1")),
  380. tu.InlineKeyboardButton("5 GB").WithCallbackData(t.encodeQuery("limit_traffic_c "+email+" 5")),
  381. tu.InlineKeyboardButton("10 GB").WithCallbackData(t.encodeQuery("limit_traffic_c "+email+" 10")),
  382. ),
  383. tu.InlineKeyboardRow(
  384. tu.InlineKeyboardButton("20 GB").WithCallbackData(t.encodeQuery("limit_traffic_c "+email+" 20")),
  385. tu.InlineKeyboardButton("30 GB").WithCallbackData(t.encodeQuery("limit_traffic_c "+email+" 30")),
  386. tu.InlineKeyboardButton("40 GB").WithCallbackData(t.encodeQuery("limit_traffic_c "+email+" 40")),
  387. ),
  388. tu.InlineKeyboardRow(
  389. tu.InlineKeyboardButton("50 GB").WithCallbackData(t.encodeQuery("limit_traffic_c "+email+" 50")),
  390. tu.InlineKeyboardButton("60 GB").WithCallbackData(t.encodeQuery("limit_traffic_c "+email+" 60")),
  391. tu.InlineKeyboardButton("80 GB").WithCallbackData(t.encodeQuery("limit_traffic_c "+email+" 80")),
  392. ),
  393. tu.InlineKeyboardRow(
  394. tu.InlineKeyboardButton("100 GB").WithCallbackData(t.encodeQuery("limit_traffic_c "+email+" 100")),
  395. tu.InlineKeyboardButton("150 GB").WithCallbackData(t.encodeQuery("limit_traffic_c "+email+" 150")),
  396. tu.InlineKeyboardButton("200 GB").WithCallbackData(t.encodeQuery("limit_traffic_c "+email+" 200")),
  397. ),
  398. )
  399. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  400. case "limit_traffic_c":
  401. if len(dataArray) == 3 {
  402. limitTraffic, err := strconv.Atoi(dataArray[2])
  403. if err == nil {
  404. needRestart, err := t.clientService.ResetClientTrafficLimitByEmail(&t.inboundService, email, limitTraffic)
  405. if needRestart {
  406. t.xrayService.SetToNeedRestart()
  407. }
  408. if err == nil {
  409. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.setTrafficLimitSuccess", "Email=="+email))
  410. t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
  411. return
  412. }
  413. }
  414. }
  415. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  416. t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
  417. case "limit_traffic_in":
  418. if len(dataArray) >= 3 {
  419. oldInputNumber, err := strconv.Atoi(dataArray[2])
  420. inputNumber := oldInputNumber
  421. if err == nil {
  422. if len(dataArray) == 4 {
  423. num, err := strconv.Atoi(dataArray[3])
  424. if err == nil {
  425. inputNumber = updateNumericInput(inputNumber, num)
  426. }
  427. if inputNumber == oldInputNumber {
  428. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation"))
  429. return
  430. }
  431. if inputNumber >= 999999 {
  432. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  433. return
  434. }
  435. }
  436. inlineKeyboard := t.numericKeypad(numericKeypadSpec{dataBase: "limit_traffic", dataArgs: email + " ", cancelData: "client_cancel " + email, confirmLabelKey: "tgbot.buttons.confirmNumberAdd"}, inputNumber)
  437. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  438. return
  439. }
  440. }
  441. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  442. t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
  443. case "add_client_limit_traffic_c":
  444. limitTraffic, _ := strconv.ParseInt(dataArray[1], 10, 64)
  445. client_TotalGB = limitTraffic * 1024 * 1024 * 1024
  446. messageId := callbackQuery.Message.GetMessageID()
  447. message_text := t.BuildClientDraftMessage()
  448. t.addClient(callbackQuery.Message.GetChat().ID, message_text, messageId)
  449. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation"))
  450. case "add_client_limit_traffic_in":
  451. if len(dataArray) >= 2 {
  452. oldInputNumber, err := strconv.Atoi(dataArray[1])
  453. inputNumber := oldInputNumber
  454. if err == nil {
  455. if len(dataArray) == 3 {
  456. num, err := strconv.Atoi(dataArray[2])
  457. if err == nil {
  458. inputNumber = updateNumericInput(inputNumber, num)
  459. }
  460. if inputNumber == oldInputNumber {
  461. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation"))
  462. return
  463. }
  464. if inputNumber >= 999999 {
  465. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  466. return
  467. }
  468. }
  469. inlineKeyboard := t.numericKeypad(numericKeypadSpec{dataBase: "add_client_limit_traffic", cancelData: "add_client_default_traffic_exp", confirmLabelKey: "tgbot.buttons.confirmNumberAdd"}, inputNumber)
  470. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  471. return
  472. }
  473. }
  474. case "reset_exp":
  475. inlineKeyboard := tu.InlineKeyboard(
  476. tu.InlineKeyboardRow(
  477. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancelReset")).WithCallbackData(t.encodeQuery("client_cancel "+email)),
  478. ),
  479. tu.InlineKeyboardRow(
  480. tu.InlineKeyboardButton(t.I18nBot("tgbot.unlimited")).WithCallbackData(t.encodeQuery("reset_exp_c "+email+" 0")),
  481. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.custom")).WithCallbackData(t.encodeQuery("reset_exp_in "+email+" 0")),
  482. ),
  483. tu.InlineKeyboardRow(
  484. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 7 "+t.I18nBot("tgbot.days")).WithCallbackData(t.encodeQuery("reset_exp_c "+email+" 7")),
  485. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 10 "+t.I18nBot("tgbot.days")).WithCallbackData(t.encodeQuery("reset_exp_c "+email+" 10")),
  486. ),
  487. tu.InlineKeyboardRow(
  488. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 14 "+t.I18nBot("tgbot.days")).WithCallbackData(t.encodeQuery("reset_exp_c "+email+" 14")),
  489. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 20 "+t.I18nBot("tgbot.days")).WithCallbackData(t.encodeQuery("reset_exp_c "+email+" 20")),
  490. ),
  491. tu.InlineKeyboardRow(
  492. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 1 "+t.I18nBot("tgbot.month")).WithCallbackData(t.encodeQuery("reset_exp_c "+email+" 30")),
  493. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 3 "+t.I18nBot("tgbot.months")).WithCallbackData(t.encodeQuery("reset_exp_c "+email+" 90")),
  494. ),
  495. tu.InlineKeyboardRow(
  496. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 6 "+t.I18nBot("tgbot.months")).WithCallbackData(t.encodeQuery("reset_exp_c "+email+" 180")),
  497. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 12 "+t.I18nBot("tgbot.months")).WithCallbackData(t.encodeQuery("reset_exp_c "+email+" 365")),
  498. ),
  499. )
  500. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  501. case "reset_exp_c":
  502. if len(dataArray) == 3 {
  503. days, err := strconv.ParseInt(dataArray[2], 10, 64)
  504. if err == nil {
  505. var date int64
  506. if days > 0 {
  507. traffic, err := t.inboundService.GetClientTrafficByEmail(email)
  508. if err != nil {
  509. logger.Warning(err)
  510. msg := t.I18nBot("tgbot.wentWrong")
  511. t.SendMsgToTgbot(chatId, msg)
  512. return
  513. }
  514. if traffic == nil {
  515. msg := t.I18nBot("tgbot.noResult")
  516. t.SendMsgToTgbot(chatId, msg)
  517. return
  518. }
  519. if traffic.ExpiryTime > 0 {
  520. if traffic.ExpiryTime-time.Now().Unix()*1000 < 0 {
  521. date = -(days * 24 * 60 * 60000)
  522. } else {
  523. date = traffic.ExpiryTime + days*24*60*60000
  524. }
  525. } else {
  526. date = traffic.ExpiryTime - days*24*60*60000
  527. }
  528. }
  529. needRestart, err := t.clientService.ResetClientExpiryTimeByEmail(&t.inboundService, email, date)
  530. if needRestart {
  531. t.xrayService.SetToNeedRestart()
  532. }
  533. if err == nil {
  534. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.expireResetSuccess", "Email=="+email))
  535. t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
  536. return
  537. }
  538. }
  539. }
  540. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  541. t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
  542. case "reset_exp_in":
  543. if len(dataArray) >= 3 {
  544. oldInputNumber, err := strconv.Atoi(dataArray[2])
  545. inputNumber := oldInputNumber
  546. if err == nil {
  547. if len(dataArray) == 4 {
  548. num, err := strconv.Atoi(dataArray[3])
  549. if err == nil {
  550. inputNumber = updateNumericInput(inputNumber, num)
  551. }
  552. if inputNumber == oldInputNumber {
  553. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation"))
  554. return
  555. }
  556. if inputNumber >= 999999 {
  557. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  558. return
  559. }
  560. }
  561. inlineKeyboard := t.numericKeypad(numericKeypadSpec{dataBase: "reset_exp", dataArgs: email + " ", cancelData: "client_cancel " + email, confirmLabelKey: "tgbot.buttons.confirmNumber"}, inputNumber)
  562. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  563. return
  564. }
  565. }
  566. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  567. t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
  568. case "add_client_reset_exp_c":
  569. client_ExpiryTime = 0
  570. days, _ := strconv.ParseInt(dataArray[1], 10, 64)
  571. var date int64
  572. if client_ExpiryTime > 0 {
  573. if client_ExpiryTime-time.Now().Unix()*1000 < 0 {
  574. date = -(days * 24 * 60 * 60000)
  575. } else {
  576. date = client_ExpiryTime + days*24*60*60000
  577. }
  578. } else {
  579. date = client_ExpiryTime - days*24*60*60000
  580. }
  581. client_ExpiryTime = date
  582. messageId := callbackQuery.Message.GetMessageID()
  583. message_text := t.BuildClientDraftMessage()
  584. t.addClient(callbackQuery.Message.GetChat().ID, message_text, messageId)
  585. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation"))
  586. case "add_client_reset_exp_in":
  587. if len(dataArray) >= 2 {
  588. oldInputNumber, err := strconv.Atoi(dataArray[1])
  589. inputNumber := oldInputNumber
  590. if err == nil {
  591. if len(dataArray) == 3 {
  592. num, err := strconv.Atoi(dataArray[2])
  593. if err == nil {
  594. inputNumber = updateNumericInput(inputNumber, num)
  595. }
  596. if inputNumber == oldInputNumber {
  597. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation"))
  598. return
  599. }
  600. if inputNumber >= 999999 {
  601. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  602. return
  603. }
  604. }
  605. inlineKeyboard := t.numericKeypad(numericKeypadSpec{dataBase: "add_client_reset_exp", cancelData: "add_client_default_traffic_exp", confirmLabelKey: "tgbot.buttons.confirmNumberAdd"}, inputNumber)
  606. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  607. return
  608. }
  609. }
  610. case "ip_limit":
  611. inlineKeyboard := tu.InlineKeyboard(
  612. tu.InlineKeyboardRow(
  613. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancelIpLimit")).WithCallbackData(t.encodeQuery("client_cancel "+email)),
  614. ),
  615. tu.InlineKeyboardRow(
  616. tu.InlineKeyboardButton(t.I18nBot("tgbot.unlimited")).WithCallbackData(t.encodeQuery("ip_limit_c "+email+" 0")),
  617. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.custom")).WithCallbackData(t.encodeQuery("ip_limit_in "+email+" 0")),
  618. ),
  619. tu.InlineKeyboardRow(
  620. tu.InlineKeyboardButton("1").WithCallbackData(t.encodeQuery("ip_limit_c "+email+" 1")),
  621. tu.InlineKeyboardButton("2").WithCallbackData(t.encodeQuery("ip_limit_c "+email+" 2")),
  622. ),
  623. tu.InlineKeyboardRow(
  624. tu.InlineKeyboardButton("3").WithCallbackData(t.encodeQuery("ip_limit_c "+email+" 3")),
  625. tu.InlineKeyboardButton("4").WithCallbackData(t.encodeQuery("ip_limit_c "+email+" 4")),
  626. ),
  627. tu.InlineKeyboardRow(
  628. tu.InlineKeyboardButton("5").WithCallbackData(t.encodeQuery("ip_limit_c "+email+" 5")),
  629. tu.InlineKeyboardButton("6").WithCallbackData(t.encodeQuery("ip_limit_c "+email+" 6")),
  630. tu.InlineKeyboardButton("7").WithCallbackData(t.encodeQuery("ip_limit_c "+email+" 7")),
  631. ),
  632. tu.InlineKeyboardRow(
  633. tu.InlineKeyboardButton("8").WithCallbackData(t.encodeQuery("ip_limit_c "+email+" 8")),
  634. tu.InlineKeyboardButton("9").WithCallbackData(t.encodeQuery("ip_limit_c "+email+" 9")),
  635. tu.InlineKeyboardButton("10").WithCallbackData(t.encodeQuery("ip_limit_c "+email+" 10")),
  636. ),
  637. )
  638. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  639. case "ip_limit_c":
  640. if len(dataArray) == 3 {
  641. count, err := strconv.Atoi(dataArray[2])
  642. if err == nil {
  643. needRestart, err := t.clientService.ResetClientIpLimitByEmail(&t.inboundService, email, count)
  644. if needRestart {
  645. t.xrayService.SetToNeedRestart()
  646. }
  647. if err == nil {
  648. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.resetIpSuccess", "Email=="+email, "Count=="+strconv.Itoa(count)))
  649. t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
  650. return
  651. }
  652. }
  653. }
  654. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  655. t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
  656. case "ip_limit_in":
  657. if len(dataArray) >= 3 {
  658. oldInputNumber, err := strconv.Atoi(dataArray[2])
  659. inputNumber := oldInputNumber
  660. if err == nil {
  661. if len(dataArray) == 4 {
  662. num, err := strconv.Atoi(dataArray[3])
  663. if err == nil {
  664. inputNumber = updateNumericInput(inputNumber, num)
  665. }
  666. if inputNumber == oldInputNumber {
  667. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation"))
  668. return
  669. }
  670. if inputNumber >= 999999 {
  671. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  672. return
  673. }
  674. }
  675. inlineKeyboard := t.numericKeypad(numericKeypadSpec{dataBase: "ip_limit", dataArgs: email + " ", cancelData: "client_cancel " + email, confirmLabelKey: "tgbot.buttons.confirmNumber"}, inputNumber)
  676. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  677. return
  678. }
  679. }
  680. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  681. t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
  682. case "add_client_ip_limit_c":
  683. if len(dataArray) == 2 {
  684. count, _ := strconv.Atoi(dataArray[1])
  685. client_LimitIP = count
  686. }
  687. messageId := callbackQuery.Message.GetMessageID()
  688. message_text := t.BuildClientDraftMessage()
  689. t.addClient(callbackQuery.Message.GetChat().ID, message_text, messageId)
  690. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation"))
  691. case "add_client_ip_limit_in":
  692. if len(dataArray) >= 2 {
  693. oldInputNumber, err := strconv.Atoi(dataArray[1])
  694. inputNumber := oldInputNumber
  695. if err == nil {
  696. if len(dataArray) == 3 {
  697. num, err := strconv.Atoi(dataArray[2])
  698. if err == nil {
  699. inputNumber = updateNumericInput(inputNumber, num)
  700. }
  701. if inputNumber == oldInputNumber {
  702. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation"))
  703. return
  704. }
  705. if inputNumber >= 999999 {
  706. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  707. return
  708. }
  709. }
  710. inlineKeyboard := t.numericKeypad(numericKeypadSpec{dataBase: "add_client_ip_limit", cancelData: "add_client_default_ip_limit", confirmLabelKey: "tgbot.buttons.confirmNumber"}, inputNumber)
  711. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  712. return
  713. }
  714. }
  715. case "clear_ips":
  716. inlineKeyboard := tu.InlineKeyboard(
  717. tu.InlineKeyboardRow(
  718. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData(t.encodeQuery("ips_cancel "+email)),
  719. ),
  720. tu.InlineKeyboardRow(
  721. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.confirmClearIps")).WithCallbackData(t.encodeQuery("clear_ips_c "+email)),
  722. ),
  723. )
  724. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  725. case "clear_ips_c":
  726. err := t.inboundService.ClearClientIps(email)
  727. if err == nil {
  728. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.clearIpSuccess", "Email=="+email))
  729. t.searchClientIps(chatId, email, callbackQuery.Message.GetMessageID())
  730. } else {
  731. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  732. }
  733. case "ip_log":
  734. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.getIpLog", "Email=="+email))
  735. t.searchClientIps(chatId, email)
  736. case "tg_user":
  737. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.getUserInfo", "Email=="+email))
  738. t.clientTelegramUserInfo(chatId, email)
  739. case "tgid_remove":
  740. inlineKeyboard := tu.InlineKeyboard(
  741. tu.InlineKeyboardRow(
  742. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData(t.encodeQuery("tgid_cancel "+email)),
  743. ),
  744. tu.InlineKeyboardRow(
  745. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.confirmRemoveTGUser")).WithCallbackData(t.encodeQuery("tgid_remove_c "+email)),
  746. ),
  747. )
  748. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  749. case "tgid_remove_c":
  750. traffic, err := t.inboundService.GetClientTrafficByEmail(email)
  751. if err != nil || traffic == nil {
  752. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  753. return
  754. }
  755. needRestart, err := t.clientService.SetClientTelegramUserID(&t.inboundService, traffic.Id, EmptyTelegramUserID)
  756. if needRestart {
  757. t.xrayService.SetToNeedRestart()
  758. }
  759. if err == nil {
  760. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.removedTGUserSuccess", "Email=="+email))
  761. t.clientTelegramUserInfo(chatId, email, callbackQuery.Message.GetMessageID())
  762. } else {
  763. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  764. }
  765. case "toggle_enable":
  766. inlineKeyboard := tu.InlineKeyboard(
  767. tu.InlineKeyboardRow(
  768. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData(t.encodeQuery("client_cancel "+email)),
  769. ),
  770. tu.InlineKeyboardRow(
  771. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.confirmToggle")).WithCallbackData(t.encodeQuery("toggle_enable_c "+email)),
  772. ),
  773. )
  774. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  775. case "toggle_enable_c":
  776. enabled, needRestart, err := t.clientService.ToggleClientEnableByEmail(&t.inboundService, email)
  777. if needRestart {
  778. t.xrayService.SetToNeedRestart()
  779. }
  780. if err == nil {
  781. if enabled {
  782. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.enableSuccess", "Email=="+email))
  783. } else {
  784. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.disableSuccess", "Email=="+email))
  785. }
  786. t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
  787. } else {
  788. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  789. }
  790. case "get_clients":
  791. inboundId := dataArray[1]
  792. inboundIdInt, err := strconv.Atoi(inboundId)
  793. if err != nil {
  794. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  795. return
  796. }
  797. inbound, err := t.inboundService.GetInbound(inboundIdInt)
  798. if err != nil {
  799. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  800. return
  801. }
  802. clients, err := t.getInboundClients(inboundIdInt)
  803. if err != nil {
  804. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  805. return
  806. }
  807. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.chooseClient", "Inbound=="+inbound.Remark), clients)
  808. case "add_client_to":
  809. client_Email = t.randomLowerAndNum(8)
  810. client_LimitIP = 0
  811. client_TotalGB = 0
  812. client_ExpiryTime = 0
  813. client_Enable = true
  814. client_TgID = ""
  815. client_SubID = t.randomLowerAndNum(16)
  816. client_Comment = ""
  817. client_Reset = 0
  818. inboundId := dataArray[1]
  819. inboundIdInt, err := strconv.Atoi(inboundId)
  820. if err != nil {
  821. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  822. return
  823. }
  824. receiver_inbound_ID = inboundIdInt
  825. receiver_inbound_IDs = []int{inboundIdInt}
  826. t.addClient(callbackQuery.Message.GetChat().ID, t.BuildClientDraftMessage())
  827. case "add_client_toggle_attach":
  828. inboundIdStr := dataArray[1]
  829. inboundIdInt, err := strconv.Atoi(inboundIdStr)
  830. if err != nil {
  831. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  832. return
  833. }
  834. found := -1
  835. for i, id := range receiver_inbound_IDs {
  836. if id == inboundIdInt {
  837. found = i
  838. break
  839. }
  840. }
  841. if found >= 0 {
  842. receiver_inbound_IDs = append(receiver_inbound_IDs[:found], receiver_inbound_IDs[found+1:]...)
  843. } else {
  844. receiver_inbound_IDs = append(receiver_inbound_IDs, inboundIdInt)
  845. }
  846. picker, err := t.getInboundsAttachPicker()
  847. if err != nil {
  848. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  849. return
  850. }
  851. t.editMessageCallbackTgBot(callbackQuery.Message.GetChat().ID, callbackQuery.Message.GetMessageID(), picker)
  852. default:
  853. // An unknown action with arguments is still a tap, and an
  854. // unanswered tap spins until Telegram times it out.
  855. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  856. }
  857. return
  858. } else {
  859. switch callbackQuery.Data {
  860. case "get_inbounds":
  861. inbounds, err := t.getInbounds()
  862. if err != nil {
  863. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  864. return
  865. }
  866. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.allClients"))
  867. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.chooseInbound"), inbounds)
  868. case "admin_client_sub_links":
  869. inbounds, err := t.getInboundsFor("get_clients_for_sub")
  870. if err != nil {
  871. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  872. return
  873. }
  874. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.chooseInbound"), inbounds)
  875. case "admin_client_individual_links":
  876. inbounds, err := t.getInboundsFor("get_clients_for_individual")
  877. if err != nil {
  878. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  879. return
  880. }
  881. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.chooseInbound"), inbounds)
  882. case "admin_client_qr_links":
  883. inbounds, err := t.getInboundsFor("get_clients_for_qr")
  884. if err != nil {
  885. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  886. return
  887. }
  888. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.chooseInbound"), inbounds)
  889. }
  890. }
  891. }
  892. if !isAdmin {
  893. // encodeQuery hashes any payload past 64 chars, so a long email's button
  894. // must be decoded before the gate can see which client it names.
  895. if decoded, err := t.decodeQuery(callbackQuery.Data); err == nil {
  896. callbackQuery.Data = decoded
  897. }
  898. if !isClientSelfCallback(callbackQuery.Data) {
  899. return
  900. }
  901. }
  902. switch callbackQuery.Data {
  903. case "get_usage":
  904. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.serverUsage"))
  905. t.getServerUsage(chatId)
  906. case "usage_refresh":
  907. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation"))
  908. t.getServerUsage(chatId, callbackQuery.Message.GetMessageID())
  909. case "inbounds":
  910. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.getInbounds"))
  911. t.SendMsgToTgbot(chatId, t.getInboundUsages())
  912. case "deplete_soon":
  913. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.depleteSoon"))
  914. t.getExhausted(chatId)
  915. case "get_backup":
  916. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.dbBackup"))
  917. t.sendBackup(chatId)
  918. case "get_banlogs":
  919. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.getBanLogs"))
  920. t.sendBanLogs(chatId, true)
  921. case "client_traffic":
  922. tgUserID := callbackQuery.From.ID
  923. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.clientUsage"))
  924. t.getClientUsage(chatId, tgUserID)
  925. case "client_commands":
  926. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.commands"))
  927. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.commands.helpClientCommands"))
  928. case "client_sub_links":
  929. // show user's own clients to choose one for sub links
  930. tgUserID := callbackQuery.From.ID
  931. traffics, err := t.inboundService.GetClientTrafficTgBot(tgUserID)
  932. if err != nil {
  933. // fallback to message
  934. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.errorOperation")+"\r\n"+err.Error())
  935. return
  936. }
  937. if len(traffics) == 0 {
  938. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.askToAddUserId", "TgUserID=="+strconv.FormatInt(tgUserID, 10)))
  939. return
  940. }
  941. var buttons []telego.InlineKeyboardButton
  942. for _, tr := range traffics {
  943. buttons = append(buttons, tu.InlineKeyboardButton(tr.Email).WithCallbackData(t.encodeQuery("client_sub_links "+tr.Email)))
  944. }
  945. cols := 1
  946. if len(buttons) >= 6 {
  947. cols = 2
  948. }
  949. keyboard := tu.InlineKeyboardGrid(tu.InlineKeyboardCols(cols, buttons...))
  950. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.commands.pleaseChoose"), keyboard)
  951. case "client_individual_links":
  952. // show user's clients to choose for individual links
  953. tgUserID := callbackQuery.From.ID
  954. traffics, err := t.inboundService.GetClientTrafficTgBot(tgUserID)
  955. if err != nil {
  956. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.errorOperation")+"\r\n"+err.Error())
  957. return
  958. }
  959. if len(traffics) == 0 {
  960. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.askToAddUserId", "TgUserID=="+strconv.FormatInt(tgUserID, 10)))
  961. return
  962. }
  963. var buttons2 []telego.InlineKeyboardButton
  964. for _, tr := range traffics {
  965. buttons2 = append(buttons2, tu.InlineKeyboardButton(tr.Email).WithCallbackData(t.encodeQuery("client_individual_links "+tr.Email)))
  966. }
  967. cols2 := 1
  968. if len(buttons2) >= 6 {
  969. cols2 = 2
  970. }
  971. keyboard2 := tu.InlineKeyboardGrid(tu.InlineKeyboardCols(cols2, buttons2...))
  972. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.commands.pleaseChoose"), keyboard2)
  973. case "client_qr_links":
  974. // show user's clients to choose for QR codes
  975. tgUserID := callbackQuery.From.ID
  976. traffics, err := t.inboundService.GetClientTrafficTgBot(tgUserID)
  977. if err != nil {
  978. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.errorOccurred")+"\r\n"+err.Error())
  979. return
  980. }
  981. if len(traffics) == 0 {
  982. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.askToAddUserId", "TgUserID=="+strconv.FormatInt(tgUserID, 10)))
  983. return
  984. }
  985. var buttons3 []telego.InlineKeyboardButton
  986. for _, tr := range traffics {
  987. buttons3 = append(buttons3, tu.InlineKeyboardButton(tr.Email).WithCallbackData(t.encodeQuery("client_qr_links "+tr.Email)))
  988. }
  989. cols3 := 1
  990. if len(buttons3) >= 6 {
  991. cols3 = 2
  992. }
  993. keyboard3 := tu.InlineKeyboardGrid(tu.InlineKeyboardCols(cols3, buttons3...))
  994. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.commands.pleaseChoose"), keyboard3)
  995. case "onlines":
  996. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.onlines"))
  997. t.onlineClients(chatId)
  998. case "onlines_refresh":
  999. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation"))
  1000. t.onlineClients(chatId, callbackQuery.Message.GetMessageID())
  1001. case "commands":
  1002. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.commands"))
  1003. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.commands.helpAdminCommands"))
  1004. case "add_client":
  1005. client_Email = t.randomLowerAndNum(8)
  1006. client_LimitIP = 0
  1007. client_TotalGB = 0
  1008. client_ExpiryTime = 0
  1009. client_Enable = true
  1010. client_TgID = ""
  1011. client_SubID = t.randomLowerAndNum(16)
  1012. client_Comment = ""
  1013. client_Reset = 0
  1014. inbounds, err := t.getInboundsAddClient()
  1015. if err != nil {
  1016. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  1017. return
  1018. }
  1019. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.addClient"))
  1020. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.chooseInbound"), inbounds)
  1021. case "add_client_ch_default_email":
  1022. t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
  1023. userStateMgr.set(chatId, "awaiting_email")
  1024. cancel_btn_markup := tu.InlineKeyboard(
  1025. tu.InlineKeyboardRow(
  1026. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"),
  1027. ),
  1028. )
  1029. prompt_message := t.I18nBot("tgbot.messages.email_prompt", "ClientEmail=="+html.EscapeString(client_Email))
  1030. t.SendMsgToTgbot(chatId, prompt_message, cancel_btn_markup)
  1031. case "add_client_ch_default_comment":
  1032. t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
  1033. userStateMgr.set(chatId, "awaiting_comment")
  1034. cancel_btn_markup := tu.InlineKeyboard(
  1035. tu.InlineKeyboardRow(
  1036. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"),
  1037. ),
  1038. )
  1039. prompt_message := t.I18nBot("tgbot.messages.comment_prompt", "ClientComment=="+html.EscapeString(client_Comment))
  1040. t.SendMsgToTgbot(chatId, prompt_message, cancel_btn_markup)
  1041. case "add_client_ch_default_tg_id":
  1042. t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
  1043. userStateMgr.set(chatId, "awaiting_tg_id")
  1044. cancel_btn_markup := tu.InlineKeyboard(
  1045. tu.InlineKeyboardRow(
  1046. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"),
  1047. ),
  1048. )
  1049. current := client_TgID
  1050. if current == "" {
  1051. current = "—"
  1052. }
  1053. t.SendMsgToTgbot(chatId, fmt.Sprintf("Send the Telegram user id (numeric) to attach to this client, or send <code>-</code> / <code>none</code> to clear.\nCurrent: <code>%s</code>", html.EscapeString(current)), cancel_btn_markup)
  1054. case "add_client_ch_default_traffic":
  1055. inlineKeyboard := tu.InlineKeyboard(
  1056. tu.InlineKeyboardRow(
  1057. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData(t.encodeQuery("add_client_default_traffic_exp")),
  1058. ),
  1059. tu.InlineKeyboardRow(
  1060. tu.InlineKeyboardButton(t.I18nBot("tgbot.unlimited")).WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 0")),
  1061. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.custom")).WithCallbackData(t.encodeQuery("add_client_limit_traffic_in 0")),
  1062. ),
  1063. tu.InlineKeyboardRow(
  1064. tu.InlineKeyboardButton("1 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 1")),
  1065. tu.InlineKeyboardButton("5 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 5")),
  1066. tu.InlineKeyboardButton("10 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 10")),
  1067. ),
  1068. tu.InlineKeyboardRow(
  1069. tu.InlineKeyboardButton("20 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 20")),
  1070. tu.InlineKeyboardButton("30 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 30")),
  1071. tu.InlineKeyboardButton("40 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 40")),
  1072. ),
  1073. tu.InlineKeyboardRow(
  1074. tu.InlineKeyboardButton("50 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 50")),
  1075. tu.InlineKeyboardButton("60 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 60")),
  1076. tu.InlineKeyboardButton("80 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 80")),
  1077. ),
  1078. tu.InlineKeyboardRow(
  1079. tu.InlineKeyboardButton("100 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 100")),
  1080. tu.InlineKeyboardButton("150 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 150")),
  1081. tu.InlineKeyboardButton("200 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 200")),
  1082. ),
  1083. )
  1084. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  1085. case "add_client_ch_default_exp":
  1086. inlineKeyboard := tu.InlineKeyboard(
  1087. tu.InlineKeyboardRow(
  1088. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData(t.encodeQuery("add_client_default_traffic_exp")),
  1089. ),
  1090. tu.InlineKeyboardRow(
  1091. tu.InlineKeyboardButton(t.I18nBot("tgbot.unlimited")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 0")),
  1092. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.custom")).WithCallbackData(t.encodeQuery("add_client_reset_exp_in 0")),
  1093. ),
  1094. tu.InlineKeyboardRow(
  1095. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 7 "+t.I18nBot("tgbot.days")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 7")),
  1096. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 10 "+t.I18nBot("tgbot.days")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 10")),
  1097. ),
  1098. tu.InlineKeyboardRow(
  1099. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 14 "+t.I18nBot("tgbot.days")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 14")),
  1100. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 20 "+t.I18nBot("tgbot.days")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 20")),
  1101. ),
  1102. tu.InlineKeyboardRow(
  1103. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 1 "+t.I18nBot("tgbot.month")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 30")),
  1104. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 3 "+t.I18nBot("tgbot.months")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 90")),
  1105. ),
  1106. tu.InlineKeyboardRow(
  1107. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 6 "+t.I18nBot("tgbot.months")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 180")),
  1108. tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 12 "+t.I18nBot("tgbot.months")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 365")),
  1109. ),
  1110. )
  1111. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  1112. case "add_client_ch_default_ip_limit":
  1113. inlineKeyboard := tu.InlineKeyboard(
  1114. tu.InlineKeyboardRow(
  1115. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData(t.encodeQuery("add_client_default_ip_limit")),
  1116. ),
  1117. tu.InlineKeyboardRow(
  1118. tu.InlineKeyboardButton(t.I18nBot("tgbot.unlimited")).WithCallbackData(t.encodeQuery("add_client_ip_limit_c 0")),
  1119. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.custom")).WithCallbackData(t.encodeQuery("add_client_ip_limit_in 0")),
  1120. ),
  1121. tu.InlineKeyboardRow(
  1122. tu.InlineKeyboardButton("1").WithCallbackData(t.encodeQuery("add_client_ip_limit_c 1")),
  1123. tu.InlineKeyboardButton("2").WithCallbackData(t.encodeQuery("add_client_ip_limit_c 2")),
  1124. ),
  1125. tu.InlineKeyboardRow(
  1126. tu.InlineKeyboardButton("3").WithCallbackData(t.encodeQuery("add_client_ip_limit_c 3")),
  1127. tu.InlineKeyboardButton("4").WithCallbackData(t.encodeQuery("add_client_ip_limit_c 4")),
  1128. ),
  1129. tu.InlineKeyboardRow(
  1130. tu.InlineKeyboardButton("5").WithCallbackData(t.encodeQuery("add_client_ip_limit_c 5")),
  1131. tu.InlineKeyboardButton("6").WithCallbackData(t.encodeQuery("add_client_ip_limit_c 6")),
  1132. tu.InlineKeyboardButton("7").WithCallbackData(t.encodeQuery("add_client_ip_limit_c 7")),
  1133. ),
  1134. tu.InlineKeyboardRow(
  1135. tu.InlineKeyboardButton("8").WithCallbackData(t.encodeQuery("add_client_ip_limit_c 8")),
  1136. tu.InlineKeyboardButton("9").WithCallbackData(t.encodeQuery("add_client_ip_limit_c 9")),
  1137. tu.InlineKeyboardButton("10").WithCallbackData(t.encodeQuery("add_client_ip_limit_c 10")),
  1138. ),
  1139. )
  1140. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
  1141. case "add_client_default_info":
  1142. t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
  1143. t.SendMsgToTgbotDeleteAfter(chatId, t.I18nBot("tgbot.messages.using_default_value"), 3, tu.ReplyKeyboardRemove())
  1144. userStateMgr.clear(chatId)
  1145. t.addClient(chatId, t.BuildClientDraftMessage())
  1146. case "add_client_cancel":
  1147. userStateMgr.clear(chatId)
  1148. receiver_inbound_ID = 0
  1149. receiver_inbound_IDs = nil
  1150. t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
  1151. t.SendMsgToTgbotDeleteAfter(chatId, t.I18nBot("tgbot.messages.cancel"), 3, tu.ReplyKeyboardRemove())
  1152. case "add_client_default_traffic_exp":
  1153. messageId := callbackQuery.Message.GetMessageID()
  1154. message_text := t.BuildClientDraftMessage()
  1155. t.addClient(chatId, message_text, messageId)
  1156. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.canceled", "Email=="+client_Email))
  1157. case "add_client_default_ip_limit":
  1158. messageId := callbackQuery.Message.GetMessageID()
  1159. message_text := t.BuildClientDraftMessage()
  1160. t.addClient(chatId, message_text, messageId)
  1161. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.canceled", "Email=="+client_Email))
  1162. case "add_client_attach_more":
  1163. picker, err := t.getInboundsAttachPicker()
  1164. if err != nil {
  1165. t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
  1166. return
  1167. }
  1168. t.SendMsgToTgbot(chatId, "Pick inbound(s) to attach:", picker)
  1169. case "add_client_attach_done":
  1170. if receiver_inbound_ID == 0 && len(receiver_inbound_IDs) > 0 {
  1171. receiver_inbound_ID = receiver_inbound_IDs[0]
  1172. }
  1173. if receiver_inbound_ID == 0 {
  1174. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.getInboundsFailed"))
  1175. return
  1176. }
  1177. message_text := t.BuildClientDraftMessage()
  1178. t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
  1179. t.addClient(chatId, message_text)
  1180. case "add_client_submit_disable":
  1181. client_Enable = false
  1182. _, err := t.SubmitAddClient()
  1183. if err != nil {
  1184. errorMessage := fmt.Sprintf("%v", err)
  1185. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.messages.error_add_client", "error=="+errorMessage), tu.ReplyKeyboardRemove())
  1186. } else {
  1187. t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
  1188. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.successfulOperation"), tu.ReplyKeyboardRemove())
  1189. t.sendClientIndividualLinks(chatId, client_Email)
  1190. t.sendClientQRLinks(chatId, client_Email)
  1191. receiver_inbound_ID = 0
  1192. receiver_inbound_IDs = nil
  1193. }
  1194. case "add_client_submit_enable":
  1195. client_Enable = true
  1196. _, err := t.SubmitAddClient()
  1197. if err != nil {
  1198. errorMessage := fmt.Sprintf("%v", err)
  1199. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.messages.error_add_client", "error=="+errorMessage), tu.ReplyKeyboardRemove())
  1200. } else {
  1201. t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
  1202. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.successfulOperation"), tu.ReplyKeyboardRemove())
  1203. t.sendClientIndividualLinks(chatId, client_Email)
  1204. t.sendClientQRLinks(chatId, client_Email)
  1205. receiver_inbound_ID = 0
  1206. receiver_inbound_IDs = nil
  1207. }
  1208. case "reset_all_traffics_cancel":
  1209. t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
  1210. t.SendMsgToTgbotDeleteAfter(chatId, t.I18nBot("tgbot.messages.cancel"), 1, tu.ReplyKeyboardRemove())
  1211. case "reset_all_traffics":
  1212. inlineKeyboard := tu.InlineKeyboard(
  1213. tu.InlineKeyboardRow(
  1214. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancelReset")).WithCallbackData(t.encodeQuery("reset_all_traffics_cancel")),
  1215. ),
  1216. tu.InlineKeyboardRow(
  1217. tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.confirmResetTraffic")).WithCallbackData(t.encodeQuery("reset_all_traffics_c")),
  1218. ),
  1219. )
  1220. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.messages.AreYouSure"), inlineKeyboard)
  1221. case "reset_all_traffics_c":
  1222. t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
  1223. emails, err := t.inboundService.GetAllEmails()
  1224. if err != nil {
  1225. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.errorOperation"), tu.ReplyKeyboardRemove())
  1226. return
  1227. }
  1228. // One report per tap, not one message per client: a large panel would
  1229. // otherwise burst past Telegram's rate limit. SendMsgToTgbot pages it.
  1230. var report strings.Builder
  1231. for _, email := range emails {
  1232. if err := t.inboundService.ResetClientTrafficByEmail(email); err == nil {
  1233. report.WriteString(t.I18nBot("tgbot.messages.SuccessResetTraffic", "ClientEmail=="+email))
  1234. } else {
  1235. report.WriteString(t.I18nBot("tgbot.messages.FailedResetTraffic", "ClientEmail=="+email, "ErrorMessage=="+err.Error()))
  1236. }
  1237. report.WriteString("\r\n\r\n")
  1238. }
  1239. report.WriteString(t.I18nBot("tgbot.messages.FinishProcess"))
  1240. // Escaped whole: one stray "<" in a remark or email otherwise makes
  1241. // Telegram reject the page it landed on, losing ~15 clients at once.
  1242. t.SendMsgToTgbot(chatId, html.EscapeString(report.String()), tu.ReplyKeyboardRemove())
  1243. case "get_sorted_traffic_usage_report":
  1244. t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
  1245. emails, err := t.inboundService.GetAllEmails()
  1246. if err != nil {
  1247. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.errorOperation"), tu.ReplyKeyboardRemove())
  1248. return
  1249. }
  1250. validEmails, missingEmails, err := t.inboundService.FilterAndSortClientEmails(emails)
  1251. if err != nil {
  1252. t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.errorOperation"), tu.ReplyKeyboardRemove())
  1253. return
  1254. }
  1255. // Batched for the same reason as the reset report above: one message
  1256. // per client hits Telegram's rate limit on a large panel.
  1257. var report strings.Builder
  1258. for _, email := range validEmails {
  1259. traffic, err := t.inboundService.GetClientTrafficByEmail(email)
  1260. if err != nil {
  1261. logger.Warning(err)
  1262. report.WriteString(t.I18nBot("tgbot.wentWrong"))
  1263. report.WriteString("\r\n\r\n")
  1264. continue
  1265. }
  1266. if traffic == nil {
  1267. report.WriteString(t.I18nBot("tgbot.noResult"))
  1268. report.WriteString("\r\n\r\n")
  1269. continue
  1270. }
  1271. report.WriteString(t.clientInfoMsg(traffic, false, false, false, false, true, false))
  1272. report.WriteString("\r\n\r\n")
  1273. }
  1274. for _, email := range missingEmails {
  1275. fmt.Fprintf(&report, "📧 %s\r\n%s\r\n\r\n", email, t.I18nBot("tgbot.noResult"))
  1276. }
  1277. if report.Len() > 0 {
  1278. t.SendMsgToTgbot(chatId, html.EscapeString(report.String()), tu.ReplyKeyboardRemove())
  1279. }
  1280. default:
  1281. action, email, ok := splitClientLinkCallback(callbackQuery.Data)
  1282. if !ok {
  1283. // Nothing matched: an unknown button still has to be answered, or it
  1284. // keeps spinning until Telegram times the callback out.
  1285. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  1286. return
  1287. }
  1288. // The keyboard outlives the chat it was sent to, so the email in it
  1289. // cannot authorise itself: a non-admin only reaches their own clients.
  1290. if !isAdmin && !t.clientOwnedByTgUser(callbackQuery.From.ID, email) {
  1291. t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
  1292. return
  1293. }
  1294. switch action {
  1295. case "client_sub_links":
  1296. t.sendClientSubLinks(chatId, email)
  1297. case "client_individual_links":
  1298. t.sendClientIndividualLinks(chatId, email)
  1299. case "client_qr_links":
  1300. t.sendClientQRLinks(chatId, email)
  1301. }
  1302. }
  1303. }
  1304. // checkAdmin checks if the given Telegram ID is an admin.
  1305. func checkAdmin(tgId int64) bool {
  1306. return slices.Contains(adminSnapshot(), tgId)
  1307. }
  1308. // isClientSelfCallback reports whether a callback is per-user rather than
  1309. // admin-only; the caller still has to prove the client is its own.
  1310. func isClientSelfCallback(data string) bool {
  1311. switch data {
  1312. case "client_traffic", "client_commands", "client_sub_links",
  1313. "client_individual_links", "client_qr_links":
  1314. return true
  1315. }
  1316. _, _, ok := splitClientLinkCallback(data)
  1317. return ok
  1318. }
  1319. // splitClientLinkCallback splits "<action> <email>" for the per-client link
  1320. // callbacks; ok is false for every other data.
  1321. func splitClientLinkCallback(data string) (action, email string, ok bool) {
  1322. for _, candidate := range []string{"client_sub_links", "client_individual_links", "client_qr_links"} {
  1323. if rest, found := strings.CutPrefix(data, candidate+" "); found && rest != "" {
  1324. return candidate, rest, true
  1325. }
  1326. }
  1327. return "", "", false
  1328. }