host.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. package service
  2. import (
  3. "sort"
  4. "github.com/mhsanaei/3x-ui/v3/internal/database"
  5. "github.com/mhsanaei/3x-ui/v3/internal/database/model"
  6. "github.com/mhsanaei/3x-ui/v3/internal/util/common"
  7. )
  8. // HostService manages Host rows (override endpoints attached to an inbound).
  9. // Mirrors the empty-struct + database.GetDB() shape of ClientService.
  10. type HostService struct{}
  11. // GetHosts returns every host, grouped by inbound then ordered by sort_order.
  12. func (s *HostService) GetHosts() ([]*model.Host, error) {
  13. var hosts []*model.Host
  14. err := database.GetDB().Order("inbound_id asc, sort_order asc, id asc").Find(&hosts).Error
  15. return hosts, err
  16. }
  17. // GetHostsByInbound returns one inbound's hosts ordered by sort_order then id.
  18. func (s *HostService) GetHostsByInbound(inboundId int) ([]*model.Host, error) {
  19. var hosts []*model.Host
  20. err := database.GetDB().Where("inbound_id = ?", inboundId).Order("sort_order asc, id asc").Find(&hosts).Error
  21. return hosts, err
  22. }
  23. func (s *HostService) GetHost(id int) (*model.Host, error) {
  24. host := &model.Host{}
  25. if err := database.GetDB().First(host, id).Error; err != nil {
  26. return nil, err
  27. }
  28. return host, nil
  29. }
  30. // AddHost creates a host after confirming its inbound exists (no hard FK).
  31. func (s *HostService) AddHost(host *model.Host) (*model.Host, error) {
  32. db := database.GetDB()
  33. var count int64
  34. if err := db.Model(&model.Inbound{}).Where("id = ?", host.InboundId).Count(&count).Error; err != nil {
  35. return nil, err
  36. }
  37. if count == 0 {
  38. return nil, common.NewError("inbound not found")
  39. }
  40. host.Id = 0
  41. if err := db.Create(host).Error; err != nil {
  42. return nil, err
  43. }
  44. return host, nil
  45. }
  46. // UpdateHost overwrites a host's content. InboundId and SortOrder are immutable
  47. // here — the inbound is fixed at creation and ordering is owned by ReorderHosts.
  48. func (s *HostService) UpdateHost(id int, host *model.Host) (*model.Host, error) {
  49. db := database.GetDB()
  50. existing := &model.Host{}
  51. if err := db.First(existing, id).Error; err != nil {
  52. return nil, err
  53. }
  54. host.Id = id
  55. host.InboundId = existing.InboundId
  56. host.SortOrder = existing.SortOrder
  57. host.CreatedAt = existing.CreatedAt
  58. if err := db.Save(host).Error; err != nil {
  59. return nil, err
  60. }
  61. return s.GetHost(id)
  62. }
  63. func (s *HostService) DeleteHost(id int) error {
  64. return database.GetDB().Delete(&model.Host{}, id).Error
  65. }
  66. func (s *HostService) SetHostEnable(id int, enable bool) error {
  67. return database.GetDB().Model(&model.Host{}).Where("id = ?", id).Update("is_disabled", !enable).Error
  68. }
  69. func (s *HostService) SetHostsEnable(ids []int, enable bool) error {
  70. if len(ids) == 0 {
  71. return nil
  72. }
  73. return database.GetDB().Model(&model.Host{}).Where("id IN ?", ids).Update("is_disabled", !enable).Error
  74. }
  75. func (s *HostService) DeleteHosts(ids []int) error {
  76. if len(ids) == 0 {
  77. return nil
  78. }
  79. return database.GetDB().Where("id IN ?", ids).Delete(&model.Host{}).Error
  80. }
  81. // ReorderHosts assigns sort_order by the position of each id in ids, in a single
  82. // transaction (driver-safe on SQLite and Postgres).
  83. func (s *HostService) ReorderHosts(ids []int) error {
  84. if len(ids) == 0 {
  85. return nil
  86. }
  87. tx := database.GetDB().Begin()
  88. for i, id := range ids {
  89. if err := tx.Model(&model.Host{}).Where("id = ?", id).Update("sort_order", i).Error; err != nil {
  90. tx.Rollback()
  91. return err
  92. }
  93. }
  94. return tx.Commit().Error
  95. }
  96. // GetAllTags returns the distinct, sorted set of tags across all hosts.
  97. func (s *HostService) GetAllTags() ([]string, error) {
  98. hosts, err := s.GetHosts()
  99. if err != nil {
  100. return nil, err
  101. }
  102. set := make(map[string]struct{})
  103. for _, h := range hosts {
  104. for _, tag := range h.Tags {
  105. if tag != "" {
  106. set[tag] = struct{}{}
  107. }
  108. }
  109. }
  110. out := make([]string, 0, len(set))
  111. for tag := range set {
  112. out = append(out, tag)
  113. }
  114. sort.Strings(out)
  115. return out, nil
  116. }