manager.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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. if sameRemoteIdentity(rt.node, node) {
  90. m.mu.RUnlock()
  91. return rt, nil
  92. }
  93. m.mu.RUnlock()
  94. } else {
  95. m.mu.RUnlock()
  96. }
  97. m.mu.Lock()
  98. defer m.mu.Unlock()
  99. if rt, ok := m.remotes[node.Id]; ok {
  100. if sameRemoteIdentity(rt.node, node) {
  101. return rt, nil
  102. }
  103. } else {
  104. rt := NewRemote(cloneRemoteNode(node), m.egressResolver)
  105. m.remotes[node.Id] = rt
  106. return rt, nil
  107. }
  108. rt := NewRemote(cloneRemoteNode(node), m.egressResolver)
  109. m.remotes[node.Id] = rt
  110. return rt, nil
  111. }
  112. func cloneRemoteNode(n *model.Node) *model.Node {
  113. if n == nil {
  114. return nil
  115. }
  116. clone := *n
  117. if n.InboundTags != nil {
  118. clone.InboundTags = append([]string(nil), n.InboundTags...)
  119. }
  120. return &clone
  121. }
  122. func sameRemoteIdentity(a, b *model.Node) bool {
  123. if a == nil || b == nil {
  124. return a == b
  125. }
  126. return a.Id == b.Id &&
  127. a.Scheme == b.Scheme &&
  128. a.Address == b.Address &&
  129. a.Port == b.Port &&
  130. a.BasePath == b.BasePath &&
  131. a.ApiToken == b.ApiToken &&
  132. a.AllowPrivateAddress == b.AllowPrivateAddress &&
  133. a.TlsVerifyMode == b.TlsVerifyMode &&
  134. a.PinnedCertSha256 == b.PinnedCertSha256 &&
  135. a.OutboundTag == b.OutboundTag
  136. }
  137. func (m *Manager) InvalidateNode(nodeID int) {
  138. m.mu.Lock()
  139. defer m.mu.Unlock()
  140. delete(m.remotes, nodeID)
  141. }
  142. func loadNode(id int) (*model.Node, error) {
  143. db := database.GetDB()
  144. n := &model.Node{}
  145. if err := db.Model(model.Node{}).Where("id = ?", id).First(n).Error; err != nil {
  146. return nil, err
  147. }
  148. return n, nil
  149. }
  150. var (
  151. managerMu sync.RWMutex
  152. manager *Manager
  153. )
  154. func SetManager(m *Manager) {
  155. managerMu.Lock()
  156. defer managerMu.Unlock()
  157. manager = m
  158. }
  159. func GetManager() *Manager {
  160. managerMu.RLock()
  161. defer managerMu.RUnlock()
  162. return manager
  163. }