tgbot.go 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907
  1. package service
  2. import (
  3. "fmt"
  4. "net"
  5. "os"
  6. "strconv"
  7. "strings"
  8. "time"
  9. "x-ui/config"
  10. "x-ui/database/model"
  11. "x-ui/logger"
  12. "x-ui/util/common"
  13. "x-ui/xray"
  14. "github.com/mymmrac/telego"
  15. th "github.com/mymmrac/telego/telegohandler"
  16. tu "github.com/mymmrac/telego/telegoutil"
  17. )
  18. var bot *telego.Bot
  19. var botHandler *th.BotHandler
  20. var adminIds []int64
  21. var isRunning bool
  22. type LoginStatus byte
  23. const (
  24. LoginSuccess LoginStatus = 1
  25. LoginFail LoginStatus = 0
  26. )
  27. type Tgbot struct {
  28. inboundService InboundService
  29. settingService SettingService
  30. serverService ServerService
  31. xrayService XrayService
  32. lastStatus *Status
  33. }
  34. func (t *Tgbot) NewTgbot() *Tgbot {
  35. return new(Tgbot)
  36. }
  37. func (t *Tgbot) Start() error {
  38. tgBottoken, err := t.settingService.GetTgBotToken()
  39. if err != nil || tgBottoken == "" {
  40. logger.Warning("Get TgBotToken failed:", err)
  41. return err
  42. }
  43. tgBotid, err := t.settingService.GetTgBotChatId()
  44. if err != nil {
  45. logger.Warning("Get GetTgBotChatId failed:", err)
  46. return err
  47. }
  48. for _, adminId := range strings.Split(tgBotid, ",") {
  49. id, err := strconv.Atoi(adminId)
  50. if err != nil {
  51. logger.Warning("Failed to get IDs from GetTgBotChatId:", err)
  52. return err
  53. }
  54. adminIds = append(adminIds, int64(id))
  55. }
  56. bot, err = telego.NewBot(tgBottoken)
  57. if err != nil {
  58. fmt.Println("Get tgbot's api error:", err)
  59. return err
  60. }
  61. // listen for TG bot income messages
  62. if !isRunning {
  63. logger.Info("Starting Telegram receiver ...")
  64. go t.OnReceive()
  65. isRunning = true
  66. }
  67. return nil
  68. }
  69. func (t *Tgbot) IsRunnging() bool {
  70. return isRunning
  71. }
  72. func (t *Tgbot) Stop() {
  73. botHandler.Stop()
  74. bot.StopLongPolling()
  75. logger.Info("Stop Telegram receiver ...")
  76. isRunning = false
  77. adminIds = nil
  78. }
  79. func (t *Tgbot) OnReceive() {
  80. params := telego.GetUpdatesParams{
  81. Timeout: 10,
  82. }
  83. updates, _ := bot.UpdatesViaLongPolling(&params)
  84. botHandler, _ = th.NewBotHandler(bot, updates)
  85. botHandler.HandleMessage(func(bot *telego.Bot, message telego.Message) {
  86. t.answerCommand(&message, message.Chat.ID, checkAdmin(message.From.ID))
  87. }, th.AnyCommand())
  88. botHandler.HandleCallbackQuery(func(bot *telego.Bot, query telego.CallbackQuery) {
  89. t.asnwerCallback(&query, checkAdmin(query.From.ID))
  90. }, th.AnyCallbackQueryWithMessage())
  91. botHandler.Start()
  92. }
  93. func (t *Tgbot) answerCommand(message *telego.Message, chatId int64, isAdmin bool) {
  94. msg := ""
  95. command, commandArgs := tu.ParseCommand(message.Text)
  96. // Extract the command from the Message.
  97. switch command {
  98. case "help":
  99. msg = "This bot is providing you some specefic data from the server.\n\n Please choose:"
  100. case "start":
  101. msg = "Hello <i>" + message.From.FirstName + "</i> 👋"
  102. if isAdmin {
  103. hostname, _ := os.Hostname()
  104. msg += "\nWelcome to <b>" + hostname + "</b> management bot"
  105. }
  106. msg += "\n\nI can do some magics for you, please choose:"
  107. case "status":
  108. msg = "bot is ok ✅"
  109. case "usage":
  110. if len(commandArgs) > 0 {
  111. if isAdmin {
  112. t.searchClient(chatId, commandArgs[0])
  113. } else {
  114. t.searchForClient(chatId, commandArgs[0])
  115. }
  116. } else {
  117. msg = "❗Please provide a text for search!"
  118. }
  119. case "inbound":
  120. if isAdmin && len(commandArgs) > 0 {
  121. t.searchInbound(chatId, commandArgs[0])
  122. } else {
  123. msg = "❗ Unknown command"
  124. }
  125. default:
  126. msg = "❗ Unknown command"
  127. }
  128. t.SendAnswer(chatId, msg, isAdmin)
  129. }
  130. func (t *Tgbot) asnwerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool) {
  131. chatId := callbackQuery.Message.Chat.ID
  132. if isAdmin {
  133. dataArray := strings.Split(callbackQuery.Data, " ")
  134. if len(dataArray) >= 2 && len(dataArray[1]) > 0 {
  135. email := dataArray[1]
  136. switch dataArray[0] {
  137. case "client_refresh":
  138. t.sendCallbackAnswerTgBot(callbackQuery.ID, fmt.Sprintf("✅ %s : Client Refreshed successfully.", email))
  139. t.searchClient(chatId, email, callbackQuery.Message.MessageID)
  140. case "client_cancel":
  141. t.sendCallbackAnswerTgBot(callbackQuery.ID, fmt.Sprintf("❌ %s : Operation canceled.", email))
  142. t.searchClient(chatId, email, callbackQuery.Message.MessageID)
  143. case "ips_refresh":
  144. t.sendCallbackAnswerTgBot(callbackQuery.ID, fmt.Sprintf("✅ %s : IPs Refreshed successfully.", email))
  145. t.searchClientIps(chatId, email, callbackQuery.Message.MessageID)
  146. case "ips_cancel":
  147. t.sendCallbackAnswerTgBot(callbackQuery.ID, fmt.Sprintf("❌ %s : Operation canceled.", email))
  148. t.searchClientIps(chatId, email, callbackQuery.Message.MessageID)
  149. case "reset_traffic":
  150. inlineKeyboard := tu.InlineKeyboard(
  151. tu.InlineKeyboardRow(
  152. tu.InlineKeyboardButton("❌ Cancel Reset").WithCallbackData("client_cancel "+email),
  153. ),
  154. tu.InlineKeyboardRow(
  155. tu.InlineKeyboardButton("✅ Confirm Reset Traffic?").WithCallbackData("reset_traffic_c "+email),
  156. ),
  157. )
  158. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.MessageID, inlineKeyboard)
  159. case "reset_traffic_c":
  160. err := t.inboundService.ResetClientTrafficByEmail(email)
  161. if err == nil {
  162. t.xrayService.SetToNeedRestart()
  163. t.sendCallbackAnswerTgBot(callbackQuery.ID, fmt.Sprintf("✅ %s : Traffic reset successfully.", email))
  164. t.searchClient(chatId, email, callbackQuery.Message.MessageID)
  165. } else {
  166. t.sendCallbackAnswerTgBot(callbackQuery.ID, "❗ Error in Operation.")
  167. }
  168. case "reset_exp":
  169. var inlineKeyboard = tu.InlineKeyboard(
  170. tu.InlineKeyboardRow(
  171. tu.InlineKeyboardButton("❌ Cancel Reset").WithCallbackData("client_cancel "+email),
  172. ),
  173. tu.InlineKeyboardRow(
  174. tu.InlineKeyboardButton("♾ Unlimited").WithCallbackData("reset_exp_c "+email+" 0"),
  175. ),
  176. tu.InlineKeyboardRow(
  177. tu.InlineKeyboardButton("1 Month").WithCallbackData("reset_exp_c "+email+" 30"),
  178. tu.InlineKeyboardButton("2 Months").WithCallbackData("reset_exp_c "+email+" 60"),
  179. ),
  180. tu.InlineKeyboardRow(
  181. tu.InlineKeyboardButton("3 Months").WithCallbackData("reset_exp_c "+email+" 90"),
  182. tu.InlineKeyboardButton("6 Months").WithCallbackData("reset_exp_c "+email+" 180"),
  183. ),
  184. tu.InlineKeyboardRow(
  185. tu.InlineKeyboardButton("9 Months").WithCallbackData("reset_exp_c "+email+" 270"),
  186. tu.InlineKeyboardButton("12 Months").WithCallbackData("reset_exp_c "+email+" 360"),
  187. ),
  188. tu.InlineKeyboardRow(
  189. tu.InlineKeyboardButton("10 Days").WithCallbackData("reset_exp_c "+email+" 10"),
  190. tu.InlineKeyboardButton("20 Days").WithCallbackData("reset_exp_c "+email+" 20"),
  191. ),
  192. )
  193. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.MessageID, inlineKeyboard)
  194. case "reset_exp_c":
  195. if len(dataArray) == 3 {
  196. days, err := strconv.Atoi(dataArray[2])
  197. if err == nil {
  198. var date int64 = 0
  199. if days > 0 {
  200. date = int64(-(days * 24 * 60 * 60000))
  201. }
  202. err := t.inboundService.ResetClientExpiryTimeByEmail(email, date)
  203. if err == nil {
  204. t.xrayService.SetToNeedRestart()
  205. t.sendCallbackAnswerTgBot(callbackQuery.ID, fmt.Sprintf("✅ %s : Expire days reset successfully.", email))
  206. t.searchClient(chatId, email, callbackQuery.Message.MessageID)
  207. return
  208. }
  209. }
  210. }
  211. t.sendCallbackAnswerTgBot(callbackQuery.ID, "❗ Error in Operation.")
  212. t.searchClient(chatId, email, callbackQuery.Message.MessageID)
  213. case "ip_limit":
  214. inlineKeyboard := tu.InlineKeyboard(
  215. tu.InlineKeyboardRow(
  216. tu.InlineKeyboardButton("❌ Cancel IP Limit").WithCallbackData("client_cancel "+email),
  217. ),
  218. tu.InlineKeyboardRow(
  219. tu.InlineKeyboardButton("♾ Unlimited").WithCallbackData("ip_limit_c "+email+" 0"),
  220. ),
  221. tu.InlineKeyboardRow(
  222. tu.InlineKeyboardButton("1").WithCallbackData("ip_limit_c "+email+" 1"),
  223. tu.InlineKeyboardButton("2").WithCallbackData("ip_limit_c "+email+" 2"),
  224. ),
  225. tu.InlineKeyboardRow(
  226. tu.InlineKeyboardButton("3").WithCallbackData("ip_limit_c "+email+" 3"),
  227. tu.InlineKeyboardButton("4").WithCallbackData("ip_limit_c "+email+" 4"),
  228. ),
  229. tu.InlineKeyboardRow(
  230. tu.InlineKeyboardButton("5").WithCallbackData("ip_limit_c "+email+" 5"),
  231. tu.InlineKeyboardButton("6").WithCallbackData("ip_limit_c "+email+" 6"),
  232. tu.InlineKeyboardButton("7").WithCallbackData("ip_limit_c "+email+" 7"),
  233. ),
  234. tu.InlineKeyboardRow(
  235. tu.InlineKeyboardButton("8").WithCallbackData("ip_limit_c "+email+" 8"),
  236. tu.InlineKeyboardButton("9").WithCallbackData("ip_limit_c "+email+" 9"),
  237. tu.InlineKeyboardButton("10").WithCallbackData("ip_limit_c "+email+" 10"),
  238. ),
  239. )
  240. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.MessageID, inlineKeyboard)
  241. case "ip_limit_c":
  242. if len(dataArray) == 3 {
  243. count, err := strconv.Atoi(dataArray[2])
  244. if err == nil {
  245. err := t.inboundService.ResetClientIpLimitByEmail(email, count)
  246. if err == nil {
  247. t.xrayService.SetToNeedRestart()
  248. t.sendCallbackAnswerTgBot(callbackQuery.ID, fmt.Sprintf("✅ %s : IP limit %d saved successfully.", email, count))
  249. t.searchClient(chatId, email, callbackQuery.Message.MessageID)
  250. return
  251. }
  252. }
  253. }
  254. t.sendCallbackAnswerTgBot(callbackQuery.ID, "❗ Error in Operation.")
  255. t.searchClient(chatId, email, callbackQuery.Message.MessageID)
  256. case "clear_ips":
  257. inlineKeyboard := tu.InlineKeyboard(
  258. tu.InlineKeyboardRow(
  259. tu.InlineKeyboardButton("❌ Cancel").WithCallbackData("ips_cancel "+email),
  260. ),
  261. tu.InlineKeyboardRow(
  262. tu.InlineKeyboardButton("✅ Confirm Clear IPs?").WithCallbackData("clear_ips_c "+email),
  263. ),
  264. )
  265. t.editMessageCallbackTgBot(chatId, callbackQuery.Message.MessageID, inlineKeyboard)
  266. case "clear_ips_c":
  267. err := t.inboundService.ClearClientIps(email)
  268. if err == nil {
  269. t.sendCallbackAnswerTgBot(callbackQuery.ID, fmt.Sprintf("✅ %s : IPs cleared successfully.", email))
  270. t.searchClientIps(chatId, email, callbackQuery.Message.MessageID)
  271. } else {
  272. t.sendCallbackAnswerTgBot(callbackQuery.ID, "❗ Error in Operation.")
  273. }
  274. case "ip_log":
  275. t.sendCallbackAnswerTgBot(callbackQuery.ID, fmt.Sprintf("✅ %s : Get IP Log.", email))
  276. t.searchClientIps(chatId, email)
  277. case "toggle_enable":
  278. enabled, err := t.inboundService.ToggleClientEnableByEmail(email)
  279. if err == nil {
  280. t.xrayService.SetToNeedRestart()
  281. if enabled {
  282. t.sendCallbackAnswerTgBot(callbackQuery.ID, fmt.Sprintf("✅ %s : Enabled successfully.", email))
  283. } else {
  284. t.sendCallbackAnswerTgBot(callbackQuery.ID, fmt.Sprintf("✅ %s : Disabled successfully.", email))
  285. }
  286. t.searchClient(chatId, email, callbackQuery.Message.MessageID)
  287. } else {
  288. t.sendCallbackAnswerTgBot(callbackQuery.ID, "❗ Error in Operation.")
  289. }
  290. }
  291. return
  292. }
  293. }
  294. // Respond to the callback query, telling Telegram to show the user
  295. // a message with the data received.
  296. t.sendCallbackAnswerTgBot(callbackQuery.ID, callbackQuery.Data)
  297. switch callbackQuery.Data {
  298. case "get_usage":
  299. t.SendMsgToTgbot(chatId, t.getServerUsage())
  300. case "inbounds":
  301. t.SendMsgToTgbot(chatId, t.getInboundUsages())
  302. case "deplete_soon":
  303. t.SendMsgToTgbot(chatId, t.getExhausted())
  304. case "get_backup":
  305. t.sendBackup(chatId)
  306. case "client_traffic":
  307. t.getClientUsage(chatId, callbackQuery.From.Username, strconv.FormatInt(callbackQuery.From.ID, 10))
  308. case "client_commands":
  309. t.SendMsgToTgbot(chatId, "To search for statistics, just use folowing command:\r\n \r\n<code>/usage [UID|Password]</code>\r\n \r\nUse UID for vmess/vless and Password for Trojan.")
  310. case "commands":
  311. t.SendMsgToTgbot(chatId, "Search for a client email:\r\n<code>/usage email</code>\r\n \r\nSearch for inbounds (with client stats):\r\n<code>/inbound [remark]</code>")
  312. }
  313. }
  314. func checkAdmin(tgId int64) bool {
  315. for _, adminId := range adminIds {
  316. if adminId == tgId {
  317. return true
  318. }
  319. }
  320. return false
  321. }
  322. func (t *Tgbot) SendAnswer(chatId int64, msg string, isAdmin bool) {
  323. numericKeyboard := tu.InlineKeyboard(
  324. tu.InlineKeyboardRow(
  325. tu.InlineKeyboardButton("Server Usage").WithCallbackData("get_usage"),
  326. tu.InlineKeyboardButton("Get DB Backup").WithCallbackData("get_backup"),
  327. ),
  328. tu.InlineKeyboardRow(
  329. tu.InlineKeyboardButton("Get Inbounds").WithCallbackData("inbounds"),
  330. tu.InlineKeyboardButton("Deplete soon").WithCallbackData("deplete_soon"),
  331. ),
  332. tu.InlineKeyboardRow(
  333. tu.InlineKeyboardButton("Commands").WithCallbackData("commands"),
  334. ),
  335. )
  336. numericKeyboardClient := tu.InlineKeyboard(
  337. tu.InlineKeyboardRow(
  338. tu.InlineKeyboardButton("Get Usage").WithCallbackData("client_traffic"),
  339. tu.InlineKeyboardButton("Commands").WithCallbackData("client_commands"),
  340. ),
  341. )
  342. params := telego.SendMessageParams{
  343. ChatID: tu.ID(chatId),
  344. Text: msg,
  345. ParseMode: "HTML",
  346. }
  347. if isAdmin {
  348. params.ReplyMarkup = numericKeyboard
  349. } else {
  350. params.ReplyMarkup = numericKeyboardClient
  351. }
  352. _, err := bot.SendMessage(&params)
  353. if err != nil {
  354. logger.Warning("Error sending telegram message :", err)
  355. }
  356. }
  357. func (t *Tgbot) SendMsgToTgbot(chatId int64, msg string, inlineKeyboard ...*telego.InlineKeyboardMarkup) {
  358. if !isRunning {
  359. return
  360. }
  361. var allMessages []string
  362. limit := 2000
  363. // paging message if it is big
  364. if len(msg) > limit {
  365. messages := strings.Split(msg, "\r\n \r\n")
  366. lastIndex := -1
  367. for _, message := range messages {
  368. if (len(allMessages) == 0) || (len(allMessages[lastIndex])+len(message) > limit) {
  369. allMessages = append(allMessages, message)
  370. lastIndex++
  371. } else {
  372. allMessages[lastIndex] += "\r\n \r\n" + message
  373. }
  374. }
  375. } else {
  376. allMessages = append(allMessages, msg)
  377. }
  378. for _, message := range allMessages {
  379. params := telego.SendMessageParams{
  380. ChatID: tu.ID(chatId),
  381. Text: message,
  382. ParseMode: "HTML",
  383. }
  384. if len(inlineKeyboard) > 0 {
  385. params.ReplyMarkup = inlineKeyboard[0]
  386. }
  387. _, err := bot.SendMessage(&params)
  388. if err != nil {
  389. logger.Warning("Error sending telegram message :", err)
  390. }
  391. time.Sleep(500 * time.Millisecond)
  392. }
  393. }
  394. func (t *Tgbot) SendMsgToTgbotAdmins(msg string) {
  395. for _, adminId := range adminIds {
  396. t.SendMsgToTgbot(adminId, msg)
  397. }
  398. }
  399. func (t *Tgbot) SendReport() {
  400. runTime, err := t.settingService.GetTgbotRuntime()
  401. if err == nil && len(runTime) > 0 {
  402. t.SendMsgToTgbotAdmins("🕰 Scheduled reports: " + runTime + "\r\nDate-Time: " + time.Now().Format("2006-01-02 15:04:05"))
  403. }
  404. info := t.getServerUsage()
  405. t.SendMsgToTgbotAdmins(info)
  406. exhausted := t.getExhausted()
  407. t.SendMsgToTgbotAdmins(exhausted)
  408. backupEnable, err := t.settingService.GetTgBotBackup()
  409. if err == nil && backupEnable {
  410. for _, adminId := range adminIds {
  411. t.sendBackup(int64(adminId))
  412. }
  413. }
  414. }
  415. func (t *Tgbot) getServerUsage() string {
  416. var info string
  417. //get hostname
  418. name, err := os.Hostname()
  419. if err != nil {
  420. logger.Error("get hostname error:", err)
  421. name = ""
  422. }
  423. info = fmt.Sprintf("💻 Hostname: %s\r\n", name)
  424. info += fmt.Sprintf("🚀X-UI Version: %s\r\n", config.GetVersion())
  425. //get ip address
  426. var ip string
  427. var ipv6 string
  428. netInterfaces, err := net.Interfaces()
  429. if err != nil {
  430. logger.Error("net.Interfaces failed, err:", err.Error())
  431. info += "🌐 IP: Unknown\r\n \r\n"
  432. } else {
  433. for i := 0; i < len(netInterfaces); i++ {
  434. if (netInterfaces[i].Flags & net.FlagUp) != 0 {
  435. addrs, _ := netInterfaces[i].Addrs()
  436. for _, address := range addrs {
  437. if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
  438. if ipnet.IP.To4() != nil {
  439. ip += ipnet.IP.String() + " "
  440. } else if ipnet.IP.To16() != nil && !ipnet.IP.IsLinkLocalUnicast() {
  441. ipv6 += ipnet.IP.String() + " "
  442. }
  443. }
  444. }
  445. }
  446. }
  447. info += fmt.Sprintf("🌐IP: %s\r\n🌐IPv6: %s\r\n", ip, ipv6)
  448. }
  449. // get latest status of server
  450. t.lastStatus = t.serverService.GetStatus(t.lastStatus)
  451. info += fmt.Sprintf("🔌Server Uptime: %d days\r\n", int(t.lastStatus.Uptime/86400))
  452. info += fmt.Sprintf("📈Server Load: %.1f, %.1f, %.1f\r\n", t.lastStatus.Loads[0], t.lastStatus.Loads[1], t.lastStatus.Loads[2])
  453. info += fmt.Sprintf("📋Server Memory: %s/%s\r\n", common.FormatTraffic(int64(t.lastStatus.Mem.Current)), common.FormatTraffic(int64(t.lastStatus.Mem.Total)))
  454. info += fmt.Sprintf("🔹TcpCount: %d\r\n", t.lastStatus.TcpCount)
  455. info += fmt.Sprintf("🔸UdpCount: %d\r\n", t.lastStatus.UdpCount)
  456. info += fmt.Sprintf("🚦Traffic: %s (↑%s,↓%s)\r\n", common.FormatTraffic(int64(t.lastStatus.NetTraffic.Sent+t.lastStatus.NetTraffic.Recv)), common.FormatTraffic(int64(t.lastStatus.NetTraffic.Sent)), common.FormatTraffic(int64(t.lastStatus.NetTraffic.Recv)))
  457. info += fmt.Sprintf("ℹXray status: %s", t.lastStatus.Xray.State)
  458. return info
  459. }
  460. func (t *Tgbot) UserLoginNotify(username string, ip string, time string, status LoginStatus) {
  461. if username == "" || ip == "" || time == "" {
  462. logger.Warning("UserLoginNotify failed,invalid info")
  463. return
  464. }
  465. var msg string
  466. // Get hostname
  467. name, err := os.Hostname()
  468. if err != nil {
  469. logger.Warning("get hostname error:", err)
  470. return
  471. }
  472. if status == LoginSuccess {
  473. msg = fmt.Sprintf("✅ Successfully logged-in to the panel\r\nHostname:%s\r\n", name)
  474. } else if status == LoginFail {
  475. msg = fmt.Sprintf("❗ Login to the panel was unsuccessful\r\nHostname:%s\r\n", name)
  476. }
  477. msg += fmt.Sprintf("⏰ Time:%s\r\n", time)
  478. msg += fmt.Sprintf("🆔 Username:%s\r\n", username)
  479. msg += fmt.Sprintf("🌐 IP:%s\r\n", ip)
  480. t.SendMsgToTgbotAdmins(msg)
  481. }
  482. func (t *Tgbot) getInboundUsages() string {
  483. info := ""
  484. // get traffic
  485. inbouds, err := t.inboundService.GetAllInbounds()
  486. if err != nil {
  487. logger.Warning("GetAllInbounds run failed:", err)
  488. info += "❌ Failed to get inbounds"
  489. } else {
  490. // NOTE:If there no any sessions here,need to notify here
  491. // TODO:Sub-node push, automatic conversion format
  492. for _, inbound := range inbouds {
  493. info += fmt.Sprintf("📍Inbound:%s\r\nPort:%d\r\n", inbound.Remark, inbound.Port)
  494. info += fmt.Sprintf("Traffic: %s (↑%s,↓%s)\r\n", common.FormatTraffic((inbound.Up + inbound.Down)), common.FormatTraffic(inbound.Up), common.FormatTraffic(inbound.Down))
  495. if inbound.ExpiryTime == 0 {
  496. info += "Expire date: ♾ Unlimited\r\n \r\n"
  497. } else {
  498. info += fmt.Sprintf("Expire date:%s\r\n \r\n", time.Unix((inbound.ExpiryTime/1000), 0).Format("2006-01-02 15:04:05"))
  499. }
  500. }
  501. }
  502. return info
  503. }
  504. func (t *Tgbot) getClientUsage(chatId int64, tgUserName string, tgUserID string) {
  505. traffics, err := t.inboundService.GetClientTrafficTgBot(tgUserID)
  506. if err != nil {
  507. logger.Warning(err)
  508. msg := "❌ Something went wrong!"
  509. t.SendMsgToTgbot(chatId, msg)
  510. return
  511. }
  512. if len(traffics) == 0 {
  513. if len(tgUserName) == 0 {
  514. msg := "Your configuration is not found!\nPlease ask your Admin to use your telegram user id in your configuration(s).\n\nYour user id: <b>" + tgUserID + "</b>"
  515. t.SendMsgToTgbot(chatId, msg)
  516. return
  517. }
  518. traffics, err = t.inboundService.GetClientTrafficTgBot(tgUserName)
  519. }
  520. if err != nil {
  521. logger.Warning(err)
  522. msg := "❌ Something went wrong!"
  523. t.SendMsgToTgbot(chatId, msg)
  524. return
  525. }
  526. if len(traffics) == 0 {
  527. msg := "Your configuration is not found!\nPlease ask your Admin to use your telegram username or user id in your configuration(s).\n\nYour username: <b>@" + tgUserName + "</b>\n\nYour user id: <b>" + tgUserID + "</b>"
  528. t.SendMsgToTgbot(chatId, msg)
  529. return
  530. }
  531. for _, traffic := range traffics {
  532. expiryTime := ""
  533. if traffic.ExpiryTime == 0 {
  534. expiryTime = "♾Unlimited"
  535. } else if traffic.ExpiryTime < 0 {
  536. expiryTime = fmt.Sprintf("%d days", traffic.ExpiryTime/-86400000)
  537. } else {
  538. expiryTime = time.Unix((traffic.ExpiryTime / 1000), 0).Format("2006-01-02 15:04:05")
  539. }
  540. total := ""
  541. if traffic.Total == 0 {
  542. total = "♾Unlimited"
  543. } else {
  544. total = common.FormatTraffic((traffic.Total))
  545. }
  546. 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",
  547. traffic.Enable, traffic.Email, common.FormatTraffic(traffic.Up), common.FormatTraffic(traffic.Down), common.FormatTraffic((traffic.Up + traffic.Down)),
  548. total, expiryTime)
  549. t.SendMsgToTgbot(chatId, output)
  550. }
  551. t.SendAnswer(chatId, "Please choose:", false)
  552. }
  553. func (t *Tgbot) searchClientIps(chatId int64, email string, messageID ...int) {
  554. ips, err := t.inboundService.GetInboundClientIps(email)
  555. if err != nil || len(ips) == 0 {
  556. ips = "No IP Record"
  557. }
  558. output := fmt.Sprintf("📧 Email: %s\r\n🔢 IPs: \r\n%s\r\n", email, ips)
  559. inlineKeyboard := tu.InlineKeyboard(
  560. tu.InlineKeyboardRow(
  561. tu.InlineKeyboardButton("🔄 Refresh").WithCallbackData("ips_refresh "+email),
  562. ),
  563. tu.InlineKeyboardRow(
  564. tu.InlineKeyboardButton("❌ Clear IPs").WithCallbackData("clear_ips "+email),
  565. ),
  566. )
  567. if len(messageID) > 0 {
  568. t.editMessageTgBot(chatId, messageID[0], output, inlineKeyboard)
  569. } else {
  570. t.SendMsgToTgbot(chatId, output, inlineKeyboard)
  571. }
  572. }
  573. func (t *Tgbot) searchClient(chatId int64, email string, messageID ...int) {
  574. traffic, err := t.inboundService.GetClientTrafficByEmail(email)
  575. if err != nil {
  576. logger.Warning(err)
  577. msg := "❌ Something went wrong!"
  578. t.SendMsgToTgbot(chatId, msg)
  579. return
  580. }
  581. if traffic == nil {
  582. msg := "No result!"
  583. t.SendMsgToTgbot(chatId, msg)
  584. return
  585. }
  586. expiryTime := ""
  587. if traffic.ExpiryTime == 0 {
  588. expiryTime = "♾Unlimited"
  589. } else if traffic.ExpiryTime < 0 {
  590. expiryTime = fmt.Sprintf("%d days", traffic.ExpiryTime/-86400000)
  591. } else {
  592. expiryTime = time.Unix((traffic.ExpiryTime / 1000), 0).Format("2006-01-02 15:04:05")
  593. }
  594. total := ""
  595. if traffic.Total == 0 {
  596. total = "♾Unlimited"
  597. } else {
  598. total = common.FormatTraffic((traffic.Total))
  599. }
  600. 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",
  601. traffic.Enable, traffic.Email, common.FormatTraffic(traffic.Up), common.FormatTraffic(traffic.Down), common.FormatTraffic((traffic.Up + traffic.Down)),
  602. total, expiryTime)
  603. inlineKeyboard := tu.InlineKeyboard(
  604. tu.InlineKeyboardRow(
  605. tu.InlineKeyboardButton("🔄 Refresh").WithCallbackData("client_refresh "+email),
  606. ),
  607. tu.InlineKeyboardRow(
  608. tu.InlineKeyboardButton("📈 Reset Traffic").WithCallbackData("reset_traffic "+email),
  609. ),
  610. tu.InlineKeyboardRow(
  611. tu.InlineKeyboardButton("📅 Reset Expire Days").WithCallbackData("reset_exp "+email),
  612. ),
  613. tu.InlineKeyboardRow(
  614. tu.InlineKeyboardButton("🔢 IP Log").WithCallbackData("ip_log "+email),
  615. tu.InlineKeyboardButton("🔢 IP Limit").WithCallbackData("ip_limit "+email),
  616. ),
  617. tu.InlineKeyboardRow(
  618. tu.InlineKeyboardButton("🔘 Enable / Disable").WithCallbackData("toggle_enable "+email),
  619. ),
  620. )
  621. if len(messageID) > 0 {
  622. t.editMessageTgBot(chatId, messageID[0], output, inlineKeyboard)
  623. } else {
  624. t.SendMsgToTgbot(chatId, output, inlineKeyboard)
  625. }
  626. }
  627. func (t *Tgbot) searchInbound(chatId int64, remark string) {
  628. inbouds, err := t.inboundService.SearchInbounds(remark)
  629. if err != nil {
  630. logger.Warning(err)
  631. msg := "❌ Something went wrong!"
  632. t.SendMsgToTgbot(chatId, msg)
  633. return
  634. }
  635. for _, inbound := range inbouds {
  636. info := ""
  637. info += fmt.Sprintf("📍Inbound:%s\r\nPort:%d\r\n", inbound.Remark, inbound.Port)
  638. info += fmt.Sprintf("Traffic: %s (↑%s,↓%s)\r\n", common.FormatTraffic((inbound.Up + inbound.Down)), common.FormatTraffic(inbound.Up), common.FormatTraffic(inbound.Down))
  639. if inbound.ExpiryTime == 0 {
  640. info += "Expire date: ♾ Unlimited\r\n \r\n"
  641. } else {
  642. info += fmt.Sprintf("Expire date:%s\r\n \r\n", time.Unix((inbound.ExpiryTime/1000), 0).Format("2006-01-02 15:04:05"))
  643. }
  644. t.SendMsgToTgbot(chatId, info)
  645. for _, traffic := range inbound.ClientStats {
  646. expiryTime := ""
  647. if traffic.ExpiryTime == 0 {
  648. expiryTime = "♾Unlimited"
  649. } else if traffic.ExpiryTime < 0 {
  650. expiryTime = fmt.Sprintf("%d days", traffic.ExpiryTime/-86400000)
  651. } else {
  652. expiryTime = time.Unix((traffic.ExpiryTime / 1000), 0).Format("2006-01-02 15:04:05")
  653. }
  654. total := ""
  655. if traffic.Total == 0 {
  656. total = "♾Unlimited"
  657. } else {
  658. total = common.FormatTraffic((traffic.Total))
  659. }
  660. 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",
  661. traffic.Enable, traffic.Email, common.FormatTraffic(traffic.Up), common.FormatTraffic(traffic.Down), common.FormatTraffic((traffic.Up + traffic.Down)),
  662. total, expiryTime)
  663. t.SendMsgToTgbot(chatId, output)
  664. }
  665. }
  666. }
  667. func (t *Tgbot) searchForClient(chatId int64, query string) {
  668. traffic, err := t.inboundService.SearchClientTraffic(query)
  669. if err != nil {
  670. logger.Warning(err)
  671. msg := "❌ Something went wrong!"
  672. t.SendMsgToTgbot(chatId, msg)
  673. return
  674. }
  675. if traffic == nil {
  676. msg := "No result!"
  677. t.SendMsgToTgbot(chatId, msg)
  678. return
  679. }
  680. expiryTime := ""
  681. if traffic.ExpiryTime == 0 {
  682. expiryTime = "♾Unlimited"
  683. } else if traffic.ExpiryTime < 0 {
  684. expiryTime = fmt.Sprintf("%d days", traffic.ExpiryTime/-86400000)
  685. } else {
  686. expiryTime = time.Unix((traffic.ExpiryTime / 1000), 0).Format("2006-01-02 15:04:05")
  687. }
  688. total := ""
  689. if traffic.Total == 0 {
  690. total = "♾Unlimited"
  691. } else {
  692. total = common.FormatTraffic((traffic.Total))
  693. }
  694. 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",
  695. traffic.Enable, traffic.Email, common.FormatTraffic(traffic.Up), common.FormatTraffic(traffic.Down), common.FormatTraffic((traffic.Up + traffic.Down)),
  696. total, expiryTime)
  697. t.SendMsgToTgbot(chatId, output)
  698. }
  699. func (t *Tgbot) getExhausted() string {
  700. trDiff := int64(0)
  701. exDiff := int64(0)
  702. now := time.Now().Unix() * 1000
  703. var exhaustedInbounds []model.Inbound
  704. var exhaustedClients []xray.ClientTraffic
  705. var disabledInbounds []model.Inbound
  706. var disabledClients []xray.ClientTraffic
  707. output := ""
  708. TrafficThreshold, err := t.settingService.GetTrafficDiff()
  709. if err == nil && TrafficThreshold > 0 {
  710. trDiff = int64(TrafficThreshold) * 1073741824
  711. }
  712. ExpireThreshold, err := t.settingService.GetExpireDiff()
  713. if err == nil && ExpireThreshold > 0 {
  714. exDiff = int64(ExpireThreshold) * 86400000
  715. }
  716. inbounds, err := t.inboundService.GetAllInbounds()
  717. if err != nil {
  718. logger.Warning("Unable to load Inbounds", err)
  719. }
  720. for _, inbound := range inbounds {
  721. if inbound.Enable {
  722. if (inbound.ExpiryTime > 0 && (inbound.ExpiryTime-now < exDiff)) ||
  723. (inbound.Total > 0 && (inbound.Total-(inbound.Up+inbound.Down) < trDiff)) {
  724. exhaustedInbounds = append(exhaustedInbounds, *inbound)
  725. }
  726. if len(inbound.ClientStats) > 0 {
  727. for _, client := range inbound.ClientStats {
  728. if client.Enable {
  729. if (client.ExpiryTime > 0 && (client.ExpiryTime-now < exDiff)) ||
  730. (client.Total > 0 && (client.Total-(client.Up+client.Down) < trDiff)) {
  731. exhaustedClients = append(exhaustedClients, client)
  732. }
  733. } else {
  734. disabledClients = append(disabledClients, client)
  735. }
  736. }
  737. }
  738. } else {
  739. disabledInbounds = append(disabledInbounds, *inbound)
  740. }
  741. }
  742. output += fmt.Sprintf("Exhausted Inbounds count:\r\n🛑 Disabled: %d\r\n🔜 Deplete soon: %d\r\n \r\n", len(disabledInbounds), len(exhaustedInbounds))
  743. if len(exhaustedInbounds) > 0 {
  744. output += "Exhausted Inbounds:\r\n"
  745. for _, inbound := range exhaustedInbounds {
  746. output += fmt.Sprintf("📍Inbound:%s\r\nPort:%d\r\nTraffic: %s (↑%s,↓%s)\r\n", inbound.Remark, inbound.Port, common.FormatTraffic((inbound.Up + inbound.Down)), common.FormatTraffic(inbound.Up), common.FormatTraffic(inbound.Down))
  747. if inbound.ExpiryTime == 0 {
  748. output += "Expire date: ♾Unlimited\r\n \r\n"
  749. } else {
  750. output += fmt.Sprintf("Expire date:%s\r\n \r\n", time.Unix((inbound.ExpiryTime/1000), 0).Format("2006-01-02 15:04:05"))
  751. }
  752. }
  753. }
  754. output += fmt.Sprintf("Exhausted Clients count:\r\n🛑 Exhausted: %d\r\n🔜 Deplete soon: %d\r\n \r\n", len(disabledClients), len(exhaustedClients))
  755. if len(exhaustedClients) > 0 {
  756. output += "Exhausted Clients:\r\n"
  757. for _, traffic := range exhaustedClients {
  758. expiryTime := ""
  759. if traffic.ExpiryTime == 0 {
  760. expiryTime = "♾Unlimited"
  761. } else if traffic.ExpiryTime < 0 {
  762. expiryTime += fmt.Sprintf("%d days", traffic.ExpiryTime/-86400000)
  763. } else {
  764. expiryTime = time.Unix((traffic.ExpiryTime / 1000), 0).Format("2006-01-02 15:04:05")
  765. }
  766. total := ""
  767. if traffic.Total == 0 {
  768. total = "♾Unlimited"
  769. } else {
  770. total = common.FormatTraffic((traffic.Total))
  771. }
  772. output += fmt.Sprintf("💡 Active: %t\r\n📧 Email: %s\r\n🔼 Upload↑: %s\r\n🔽 Download↓: %s\r\n🔄 Total: %s / %s\r\n📅 Expire date: %s\r\n \r\n",
  773. traffic.Enable, traffic.Email, common.FormatTraffic(traffic.Up), common.FormatTraffic(traffic.Down), common.FormatTraffic((traffic.Up + traffic.Down)),
  774. total, expiryTime)
  775. }
  776. }
  777. return output
  778. }
  779. func (t *Tgbot) sendBackup(chatId int64) {
  780. sendingTime := time.Now().Format("2006-01-02 15:04:05")
  781. t.SendMsgToTgbot(chatId, "Backup time: "+sendingTime)
  782. file, err := os.Open(config.GetDBPath())
  783. if err != nil {
  784. logger.Warning("Error in opening db file for backup: ", err)
  785. }
  786. document := tu.Document(
  787. tu.ID(chatId),
  788. tu.File(file),
  789. )
  790. _, err = bot.SendDocument(document)
  791. if err != nil {
  792. logger.Warning("Error in uploading backup: ", err)
  793. }
  794. file, err = os.Open(xray.GetConfigPath())
  795. if err != nil {
  796. logger.Warning("Error in opening config.json file for backup: ", err)
  797. }
  798. document = tu.Document(
  799. tu.ID(chatId),
  800. tu.File(file),
  801. )
  802. _, err = bot.SendDocument(document)
  803. if err != nil {
  804. logger.Warning("Error in uploading config.json: ", err)
  805. }
  806. }
  807. func (t *Tgbot) sendCallbackAnswerTgBot(id string, message string) {
  808. params := telego.AnswerCallbackQueryParams{
  809. CallbackQueryID: id,
  810. Text: message,
  811. }
  812. if err := bot.AnswerCallbackQuery(&params); err != nil {
  813. logger.Warning(err)
  814. }
  815. }
  816. func (t *Tgbot) editMessageCallbackTgBot(chatId int64, messageID int, inlineKeyboard *telego.InlineKeyboardMarkup) {
  817. params := telego.EditMessageReplyMarkupParams{
  818. ChatID: tu.ID(chatId),
  819. MessageID: messageID,
  820. ReplyMarkup: inlineKeyboard,
  821. }
  822. if _, err := bot.EditMessageReplyMarkup(&params); err != nil {
  823. logger.Warning(err)
  824. }
  825. }
  826. func (t *Tgbot) editMessageTgBot(chatId int64, messageID int, text string, inlineKeyboard ...*telego.InlineKeyboardMarkup) {
  827. params := telego.EditMessageTextParams{
  828. ChatID: tu.ID(chatId),
  829. MessageID: messageID,
  830. Text: text,
  831. ParseMode: "HTML",
  832. }
  833. if len(inlineKeyboard) > 0 {
  834. params.ReplyMarkup = inlineKeyboard[0]
  835. }
  836. if _, err := bot.EditMessageText(&params); err != nil {
  837. logger.Warning(err)
  838. }
  839. }
  840. func fromChat(u *telego.Update) *telego.Chat {
  841. switch {
  842. case u.Message != nil:
  843. return &u.Message.Chat
  844. case u.EditedMessage != nil:
  845. return &u.EditedMessage.Chat
  846. case u.ChannelPost != nil:
  847. return &u.ChannelPost.Chat
  848. case u.EditedChannelPost != nil:
  849. return &u.EditedChannelPost.Chat
  850. case u.CallbackQuery != nil:
  851. return &u.CallbackQuery.Message.Chat
  852. default:
  853. return nil
  854. }
  855. }