mtproto_job.go 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. package job
  2. import (
  3. "github.com/mhsanaei/3x-ui/v3/internal/database/model"
  4. "github.com/mhsanaei/3x-ui/v3/internal/logger"
  5. "github.com/mhsanaei/3x-ui/v3/internal/mtproto"
  6. "github.com/mhsanaei/3x-ui/v3/internal/web/service"
  7. "github.com/mhsanaei/3x-ui/v3/internal/xray"
  8. )
  9. // MtprotoJob reconciles the running mtg sidecar processes against the enabled
  10. // mtproto inbounds in the database, restarts any that crashed, and folds the
  11. // per-client traffic scraped from each mtg /stats endpoint into the usual client
  12. // and inbound traffic accounting.
  13. type MtprotoJob struct {
  14. inboundService service.InboundService
  15. }
  16. // NewMtprotoJob creates a new mtproto reconcile/traffic job instance.
  17. func NewMtprotoJob() *MtprotoJob {
  18. return new(MtprotoJob)
  19. }
  20. // Run reconciles desired mtproto inbounds with running mtg processes and records
  21. // per-client traffic deltas and online status.
  22. func (j *MtprotoJob) Run() {
  23. inbounds, err := j.inboundService.GetAllInbounds()
  24. if err != nil {
  25. logger.Warning("mtproto job: get inbounds failed:", err)
  26. return
  27. }
  28. var desired []mtproto.Instance
  29. routedTags := make(map[string]bool)
  30. activeTags := make([]string, 0)
  31. for _, ib := range inbounds {
  32. if ib.Protocol != model.MTProto || !ib.Enable || ib.NodeID != nil {
  33. continue
  34. }
  35. if inst, ok := mtproto.InstanceFromInbound(ib); ok {
  36. desired = append(desired, inst)
  37. activeTags = append(activeTags, inst.Tag)
  38. if inst.RouteThroughXray {
  39. routedTags[inst.Tag] = true
  40. }
  41. }
  42. }
  43. mgr := mtproto.GetManager()
  44. mgr.Reconcile(desired)
  45. deltas, onlineEmails := mgr.CollectTraffic()
  46. // A routed inbound's total is already metered through the Xray bridge by
  47. // xray_traffic_job, so only non-routed inbounds are rolled up here; per-client
  48. // deltas are always kept, since the bridge cannot tell mtproto users apart.
  49. clientTraffics := make([]*xray.ClientTraffic, 0, len(deltas))
  50. inboundUp := make(map[string]int64)
  51. inboundDown := make(map[string]int64)
  52. for _, d := range deltas {
  53. clientTraffics = append(clientTraffics, &xray.ClientTraffic{
  54. Email: d.Email,
  55. Up: d.Up,
  56. Down: d.Down,
  57. })
  58. if !routedTags[d.Tag] {
  59. inboundUp[d.Tag] += d.Up
  60. inboundDown[d.Tag] += d.Down
  61. }
  62. }
  63. traffics := make([]*xray.Traffic, 0, len(inboundUp))
  64. for tag, up := range inboundUp {
  65. traffics = append(traffics, &xray.Traffic{
  66. IsInbound: true,
  67. Tag: tag,
  68. Up: up,
  69. Down: inboundDown[tag],
  70. })
  71. }
  72. if len(traffics) > 0 || len(clientTraffics) > 0 {
  73. if _, _, err := j.inboundService.AddTraffic(traffics, clientTraffics); err != nil {
  74. logger.Warning("mtproto job: add traffic failed:", err)
  75. }
  76. }
  77. j.inboundService.RefreshLocalOnlineClients(onlineEmails, activeTags)
  78. }