stats_notify_job.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. package job
  2. import (
  3. "fmt"
  4. "net"
  5. "os"
  6. "time"
  7. "x-ui/logger"
  8. "x-ui/util/common"
  9. "x-ui/web/service"
  10. tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
  11. )
  12. type LoginStatus byte
  13. const (
  14. LoginSuccess LoginStatus = 1
  15. LoginFail LoginStatus = 0
  16. )
  17. type StatsNotifyJob struct {
  18. enable bool
  19. xrayService service.XrayService
  20. inboundService service.InboundService
  21. settingService service.SettingService
  22. }
  23. func NewStatsNotifyJob() *StatsNotifyJob {
  24. return new(StatsNotifyJob)
  25. }
  26. func (j *StatsNotifyJob) SendMsgToTgbot(msg string) {
  27. //Telegram bot basic info
  28. tgBottoken, err := j.settingService.GetTgBotToken()
  29. if err != nil || tgBottoken == "" {
  30. logger.Warning("sendMsgToTgbot failed,GetTgBotToken fail:", err)
  31. return
  32. }
  33. tgBotid, err := j.settingService.GetTgBotChatId()
  34. if err != nil {
  35. logger.Warning("sendMsgToTgbot failed,GetTgBotChatId fail:", err)
  36. return
  37. }
  38. bot, err := tgbotapi.NewBotAPI(tgBottoken)
  39. if err != nil {
  40. fmt.Println("get tgbot error:", err)
  41. return
  42. }
  43. bot.Debug = true
  44. fmt.Printf("Authorized on account %s", bot.Self.UserName)
  45. info := tgbotapi.NewMessage(int64(tgBotid), msg)
  46. //msg.ReplyToMessageID = int(tgBotid)
  47. bot.Send(info)
  48. }
  49. // Here run is a interface method of Job interface
  50. func (j *StatsNotifyJob) Run() {
  51. if !j.xrayService.IsXrayRunning() {
  52. return
  53. }
  54. var info string
  55. //get hostname
  56. name, err := os.Hostname()
  57. if err != nil {
  58. fmt.Println("get hostname error:", err)
  59. return
  60. }
  61. info = fmt.Sprintf("Hostname:%s\r\n", name)
  62. //get ip address
  63. var ip string
  64. netInterfaces, err := net.Interfaces()
  65. if err != nil {
  66. fmt.Println("net.Interfaces failed, err:", err.Error())
  67. return
  68. }
  69. for i := 0; i < len(netInterfaces); i++ {
  70. if (netInterfaces[i].Flags & net.FlagUp) != 0 {
  71. addrs, _ := netInterfaces[i].Addrs()
  72. for _, address := range addrs {
  73. if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
  74. if ipnet.IP.To4() != nil {
  75. ip = ipnet.IP.String()
  76. break
  77. } else {
  78. ip = ipnet.IP.String()
  79. break
  80. }
  81. }
  82. }
  83. }
  84. }
  85. info += fmt.Sprintf("IP:%s\r\n \r\n", ip)
  86. // get traffic
  87. inbouds, err := j.inboundService.GetAllInbounds()
  88. if err != nil {
  89. logger.Warning("StatsNotifyJob run failed:", err)
  90. return
  91. }
  92. // NOTE:If there no any sessions here,need to notify here
  93. // TODO:Sub-node push, automatic conversion format
  94. for _, inbound := range inbouds {
  95. info += fmt.Sprintf("Node name:%s\r\nPort:%d\r\nUpload↑:%s\r\nDownload↓:%s\r\nTotal:%s\r\n", inbound.Remark, inbound.Port, common.FormatTraffic(inbound.Up), common.FormatTraffic(inbound.Down), common.FormatTraffic((inbound.Up + inbound.Down)))
  96. if inbound.ExpiryTime == 0 {
  97. info += fmt.Sprintf("Expire date:unlimited\r\n \r\n")
  98. } else {
  99. info += fmt.Sprintf("Expire date:%s\r\n \r\n", time.Unix((inbound.ExpiryTime/1000), 0).Format("2006-01-02 15:04:05"))
  100. }
  101. }
  102. j.SendMsgToTgbot(info)
  103. }
  104. func (j *StatsNotifyJob) UserLoginNotify(username string, ip string, time string, status LoginStatus) {
  105. if username == "" || ip == "" || time == "" {
  106. logger.Warning("UserLoginNotify failed,invalid info")
  107. return
  108. }
  109. var msg string
  110. // Get hostname
  111. name, err := os.Hostname()
  112. if err != nil {
  113. fmt.Println("get hostname error:", err)
  114. return
  115. }
  116. if status == LoginSuccess {
  117. msg = fmt.Sprintf("Successfully logged-in to the panel\r\nHostname:%s\r\n", name)
  118. } else if status == LoginFail {
  119. msg = fmt.Sprintf("Login to the panel was unsuccessful\r\nHostname:%s\r\n", name)
  120. }
  121. msg += fmt.Sprintf("Time:%s\r\n", time)
  122. msg += fmt.Sprintf("Username:%s\r\n", username)
  123. msg += fmt.Sprintf("IP:%s\r\n", ip)
  124. j.SendMsgToTgbot(msg)
  125. }
  126. var numericKeyboard = tgbotapi.NewInlineKeyboardMarkup(
  127. tgbotapi.NewInlineKeyboardRow(
  128. tgbotapi.NewInlineKeyboardButtonData("Get Usage", "get_usage"),
  129. ),
  130. )
  131. func (j *StatsNotifyJob) OnReceive() *StatsNotifyJob {
  132. tgBottoken, err := j.settingService.GetTgBotToken()
  133. if err != nil || tgBottoken == "" {
  134. logger.Warning("sendMsgToTgbot failed,GetTgBotToken fail:", err)
  135. return j
  136. }
  137. bot, err := tgbotapi.NewBotAPI(tgBottoken)
  138. if err != nil {
  139. fmt.Println("get tgbot error:", err)
  140. return j
  141. }
  142. bot.Debug = false
  143. u := tgbotapi.NewUpdate(0)
  144. u.Timeout = 10
  145. updates := bot.GetUpdatesChan(u)
  146. for update := range updates {
  147. if update.Message == nil {
  148. if update.CallbackQuery != nil {
  149. // Respond to the callback query, telling Telegram to show the user
  150. // a message with the data received.
  151. callback := tgbotapi.NewCallback(update.CallbackQuery.ID, update.CallbackQuery.Data)
  152. if _, err := bot.Request(callback); err != nil {
  153. logger.Warning(err)
  154. }
  155. // And finally, send a message containing the data received.
  156. msg := tgbotapi.NewMessage(update.CallbackQuery.Message.Chat.ID, "")
  157. switch update.CallbackQuery.Data {
  158. case "get_usage":
  159. msg.Text = "for get your usage send command like this : \n <code>/usage uuid | id</code> \n example : <code>/usage fc3239ed-8f3b-4151-ff51-b183d5182142</code>"
  160. msg.ParseMode = "HTML"
  161. }
  162. if _, err := bot.Send(msg); err != nil {
  163. logger.Warning(err)
  164. }
  165. }
  166. continue
  167. }
  168. if !update.Message.IsCommand() { // ignore any non-command Messages
  169. continue
  170. }
  171. // Create a new MessageConfig. We don't have text yet,
  172. // so we leave it empty.
  173. msg := tgbotapi.NewMessage(update.Message.Chat.ID, "")
  174. // Extract the command from the Message.
  175. switch update.Message.Command() {
  176. case "help":
  177. msg.Text = "What you need?"
  178. msg.ReplyMarkup = numericKeyboard
  179. case "start":
  180. msg.Text = "Hi :) \n What you need?"
  181. msg.ReplyMarkup = numericKeyboard
  182. case "status":
  183. msg.Text = "bot is ok."
  184. case "usage":
  185. msg.Text = j.getClientUsage(update.Message.CommandArguments())
  186. default:
  187. msg.Text = "I don't know that command, /help"
  188. msg.ReplyMarkup = numericKeyboard
  189. }
  190. if _, err := bot.Send(msg); err != nil {
  191. logger.Warning(err)
  192. }
  193. }
  194. return j
  195. }
  196. func (j *StatsNotifyJob) getClientUsage(id string) string {
  197. traffic, err := j.inboundService.GetClientTrafficById(id)
  198. if err != nil {
  199. logger.Warning(err)
  200. return "something wrong!"
  201. }
  202. expiryTime := ""
  203. if traffic.ExpiryTime == 0 {
  204. expiryTime = fmt.Sprintf("unlimited")
  205. } else {
  206. expiryTime = fmt.Sprintf("%s", time.Unix((traffic.ExpiryTime/1000), 0).Format("2006-01-02 15:04:05"))
  207. }
  208. total := ""
  209. if traffic.Total == 0 {
  210. total = fmt.Sprintf("unlimited")
  211. } else {
  212. total = fmt.Sprintf("%s", common.FormatTraffic((traffic.Total)))
  213. }
  214. output := fmt.Sprintf("💡 Active: %t\r\n📧 Email: %s\r\n🔼 Download↑: %s\r\n🔽 Upload↓: %s\r\n🔄 Total: %s / %s\r\n📅 Expire in: %s\r\n",
  215. traffic.Enable, traffic.Email, common.FormatTraffic(traffic.Up), common.FormatTraffic(traffic.Down), common.FormatTraffic((traffic.Up + traffic.Down)),
  216. total, expiryTime)
  217. return output
  218. }