manager.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  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. localOverride Runtime // test-only: forces RuntimeFor(nil) to return a stub
  17. egressResolver NodeEgressResolver
  18. }
  19. func NewManager(localDeps LocalDeps) *Manager {
  20. return &Manager{
  21. local: NewLocal(localDeps),
  22. remotes: make(map[int]*Remote),
  23. }
  24. }
  25. // SetRuntimeOverride makes RuntimeFor(nodeID) return rt instead of building a
  26. // real Remote. Test seam for exercising node-dispatch paths without a network
  27. // node; pass nil rt to clear.
  28. func (m *Manager) SetRuntimeOverride(nodeID int, rt Runtime) {
  29. m.mu.Lock()
  30. defer m.mu.Unlock()
  31. if rt == nil {
  32. delete(m.overrides, nodeID)
  33. return
  34. }
  35. if m.overrides == nil {
  36. m.overrides = make(map[int]Runtime)
  37. }
  38. m.overrides[nodeID] = rt
  39. }
  40. // SetLocalRuntimeOverride makes RuntimeFor(nil) return rt instead of the real
  41. // local runtime. Test seam for exercising the local dispatch path (MTProto
  42. // sidecar, local Xray) without a running child process; pass nil rt to clear.
  43. func (m *Manager) SetLocalRuntimeOverride(rt Runtime) {
  44. m.mu.Lock()
  45. defer m.mu.Unlock()
  46. m.localOverride = rt
  47. }
  48. func (m *Manager) SetNodeEgressResolver(r NodeEgressResolver) {
  49. m.mu.Lock()
  50. defer m.mu.Unlock()
  51. m.egressResolver = r
  52. }
  53. func (m *Manager) NodeEgressProxyURL(nodeID int) string {
  54. m.mu.RLock()
  55. defer m.mu.RUnlock()
  56. if m.egressResolver == nil {
  57. return ""
  58. }
  59. return m.egressResolver.NodeEgressProxyURL(nodeID)
  60. }
  61. func (m *Manager) RuntimeFor(nodeID *int) (Runtime, error) {
  62. if nodeID == nil {
  63. m.mu.RLock()
  64. if m.localOverride != nil {
  65. rt := m.localOverride
  66. m.mu.RUnlock()
  67. return rt, nil
  68. }
  69. m.mu.RUnlock()
  70. return m.local, nil
  71. }
  72. m.mu.RLock()
  73. if rt, ok := m.overrides[*nodeID]; ok {
  74. m.mu.RUnlock()
  75. return rt, nil
  76. }
  77. if rt, ok := m.remotes[*nodeID]; ok {
  78. m.mu.RUnlock()
  79. return rt, nil
  80. }
  81. m.mu.RUnlock()
  82. m.mu.Lock()
  83. defer m.mu.Unlock()
  84. if rt, ok := m.remotes[*nodeID]; ok {
  85. return rt, nil
  86. }
  87. n, err := loadNode(*nodeID)
  88. if err != nil {
  89. return nil, err
  90. }
  91. if !n.Enable {
  92. return nil, errors.New("node " + n.Name + " is disabled")
  93. }
  94. rt := NewRemote(n, m.egressResolver)
  95. m.remotes[*nodeID] = rt
  96. return rt, nil
  97. }
  98. func (m *Manager) Local() Runtime { return m.local }
  99. func (m *Manager) RemoteFor(node *model.Node) (*Remote, error) {
  100. if node == nil {
  101. return nil, errors.New("node is nil")
  102. }
  103. m.mu.RLock()
  104. if rt, ok := m.remotes[node.Id]; ok {
  105. if sameRemoteIdentity(rt.node, node) {
  106. m.mu.RUnlock()
  107. return rt, nil
  108. }
  109. m.mu.RUnlock()
  110. } else {
  111. m.mu.RUnlock()
  112. }
  113. m.mu.Lock()
  114. defer m.mu.Unlock()
  115. if rt, ok := m.remotes[node.Id]; ok {
  116. if sameRemoteIdentity(rt.node, node) {
  117. return rt, nil
  118. }
  119. } else {
  120. rt := NewRemote(cloneRemoteNode(node), m.egressResolver)
  121. m.remotes[node.Id] = rt
  122. return rt, nil
  123. }
  124. rt := NewRemote(cloneRemoteNode(node), m.egressResolver)
  125. m.remotes[node.Id] = rt
  126. return rt, nil
  127. }
  128. func cloneRemoteNode(n *model.Node) *model.Node {
  129. if n == nil {
  130. return nil
  131. }
  132. clone := *n
  133. if n.InboundTags != nil {
  134. clone.InboundTags = append([]string(nil), n.InboundTags...)
  135. }
  136. return &clone
  137. }
  138. func sameRemoteIdentity(a, b *model.Node) bool {
  139. if a == nil || b == nil {
  140. return a == b
  141. }
  142. return a.Id == b.Id &&
  143. a.Scheme == b.Scheme &&
  144. a.Address == b.Address &&
  145. a.Port == b.Port &&
  146. a.BasePath == b.BasePath &&
  147. a.ApiToken == b.ApiToken &&
  148. a.AllowPrivateAddress == b.AllowPrivateAddress &&
  149. a.TlsVerifyMode == b.TlsVerifyMode &&
  150. a.PinnedCertSha256 == b.PinnedCertSha256 &&
  151. a.OutboundTag == b.OutboundTag
  152. }
  153. func (m *Manager) InvalidateNode(nodeID int) {
  154. m.mu.Lock()
  155. defer m.mu.Unlock()
  156. delete(m.remotes, nodeID)
  157. }
  158. func loadNode(id int) (*model.Node, error) {
  159. db := database.GetDB()
  160. n := &model.Node{}
  161. if err := db.Model(model.Node{}).Where("id = ?", id).First(n).Error; err != nil {
  162. return nil, err
  163. }
  164. return n, nil
  165. }
  166. var (
  167. managerMu sync.RWMutex
  168. manager *Manager
  169. )
  170. func SetManager(m *Manager) {
  171. managerMu.Lock()
  172. defer managerMu.Unlock()
  173. manager = m
  174. }
  175. func GetManager() *Manager {
  176. managerMu.RLock()
  177. defer managerMu.RUnlock()
  178. return manager
  179. }