1
0

manager.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. package runtime
  2. import (
  3. "errors"
  4. "sync"
  5. "github.com/mhsanaei/3x-ui/v3/internal/database"
  6. "github.com/mhsanaei/3x-ui/v3/internal/database/model"
  7. )
  8. type NodeEgressResolver interface {
  9. NodeEgressProxyURL(nodeID int) string
  10. }
  11. type Manager struct {
  12. local Runtime
  13. mu sync.RWMutex
  14. remotes map[int]*Remote
  15. overrides map[int]Runtime // test-only: forces RuntimeFor to return a stub
  16. egressResolver NodeEgressResolver
  17. }
  18. func NewManager(localDeps LocalDeps) *Manager {
  19. return &Manager{
  20. local: NewLocal(localDeps),
  21. remotes: make(map[int]*Remote),
  22. }
  23. }
  24. // SetRuntimeOverride makes RuntimeFor(nodeID) return rt instead of building a
  25. // real Remote. Test seam for exercising node-dispatch paths without a network
  26. // node; pass nil rt to clear.
  27. func (m *Manager) SetRuntimeOverride(nodeID int, rt Runtime) {
  28. m.mu.Lock()
  29. defer m.mu.Unlock()
  30. if rt == nil {
  31. delete(m.overrides, nodeID)
  32. return
  33. }
  34. if m.overrides == nil {
  35. m.overrides = make(map[int]Runtime)
  36. }
  37. m.overrides[nodeID] = rt
  38. }
  39. func (m *Manager) SetNodeEgressResolver(r NodeEgressResolver) {
  40. m.mu.Lock()
  41. defer m.mu.Unlock()
  42. m.egressResolver = r
  43. }
  44. func (m *Manager) NodeEgressProxyURL(nodeID int) string {
  45. m.mu.RLock()
  46. defer m.mu.RUnlock()
  47. if m.egressResolver == nil {
  48. return ""
  49. }
  50. return m.egressResolver.NodeEgressProxyURL(nodeID)
  51. }
  52. func (m *Manager) RuntimeFor(nodeID *int) (Runtime, error) {
  53. if nodeID == nil {
  54. return m.local, nil
  55. }
  56. m.mu.RLock()
  57. if rt, ok := m.overrides[*nodeID]; ok {
  58. m.mu.RUnlock()
  59. return rt, nil
  60. }
  61. if rt, ok := m.remotes[*nodeID]; ok {
  62. m.mu.RUnlock()
  63. return rt, nil
  64. }
  65. m.mu.RUnlock()
  66. m.mu.Lock()
  67. defer m.mu.Unlock()
  68. if rt, ok := m.remotes[*nodeID]; ok {
  69. return rt, nil
  70. }
  71. n, err := loadNode(*nodeID)
  72. if err != nil {
  73. return nil, err
  74. }
  75. if !n.Enable {
  76. return nil, errors.New("node " + n.Name + " is disabled")
  77. }
  78. rt := NewRemote(n, m.egressResolver)
  79. m.remotes[*nodeID] = rt
  80. return rt, nil
  81. }
  82. func (m *Manager) Local() Runtime { return m.local }
  83. func (m *Manager) RemoteFor(node *model.Node) (*Remote, error) {
  84. if node == nil {
  85. return nil, errors.New("node is nil")
  86. }
  87. m.mu.RLock()
  88. if rt, ok := m.remotes[node.Id]; ok {
  89. m.mu.RUnlock()
  90. return rt, nil
  91. }
  92. m.mu.RUnlock()
  93. m.mu.Lock()
  94. defer m.mu.Unlock()
  95. if rt, ok := m.remotes[node.Id]; ok {
  96. return rt, nil
  97. }
  98. rt := NewRemote(node, m.egressResolver)
  99. m.remotes[node.Id] = rt
  100. return rt, nil
  101. }
  102. func (m *Manager) InvalidateNode(nodeID int) {
  103. m.mu.Lock()
  104. defer m.mu.Unlock()
  105. delete(m.remotes, nodeID)
  106. }
  107. func loadNode(id int) (*model.Node, error) {
  108. db := database.GetDB()
  109. n := &model.Node{}
  110. if err := db.Model(model.Node{}).Where("id = ?", id).First(n).Error; err != nil {
  111. return nil, err
  112. }
  113. return n, nil
  114. }
  115. var (
  116. managerMu sync.RWMutex
  117. manager *Manager
  118. )
  119. func SetManager(m *Manager) {
  120. managerMu.Lock()
  121. defer managerMu.Unlock()
  122. manager = m
  123. }
  124. func GetManager() *Manager {
  125. managerMu.RLock()
  126. defer managerMu.RUnlock()
  127. return manager
  128. }