github.com/Asutorufa/yuhaiin@v0.3.6-0.20240502055049-7984da7023a0/pkg/node/node.go (about) 1 package node 2 3 import ( 4 "context" 5 "fmt" 6 "net" 7 "sync" 8 9 "github.com/Asutorufa/yuhaiin/pkg/log" 10 "github.com/Asutorufa/yuhaiin/pkg/net/netapi" 11 "github.com/Asutorufa/yuhaiin/pkg/protos/node" 12 gn "github.com/Asutorufa/yuhaiin/pkg/protos/node/grpc" 13 "github.com/Asutorufa/yuhaiin/pkg/protos/node/latency" 14 "github.com/Asutorufa/yuhaiin/pkg/protos/node/point" 15 "github.com/Asutorufa/yuhaiin/pkg/protos/node/subscribe" 16 pt "github.com/Asutorufa/yuhaiin/pkg/protos/node/tag" 17 "github.com/Asutorufa/yuhaiin/pkg/utils/jsondb" 18 "google.golang.org/protobuf/types/known/durationpb" 19 "google.golang.org/protobuf/types/known/emptypb" 20 "google.golang.org/protobuf/types/known/wrapperspb" 21 ) 22 23 type Nodes struct { 24 gn.UnimplementedNodeServer 25 26 ruleTags func() []string 27 28 db *jsondb.DB[*node.Node] 29 manager *manager 30 outBound *outbound 31 links *link 32 } 33 34 func NewNodes(path string) *Nodes { 35 f := &Nodes{ 36 db: load(path), 37 } 38 39 f.manager = NewManager(f.db.Data.Manager) 40 f.outBound = NewOutbound(f.db, f.manager) 41 f.links = NewLink(f.db, f.outBound, f.manager) 42 43 return f 44 } 45 46 func (n *Nodes) SetRuleTags(f func() []string) { n.ruleTags = f } 47 48 func (n *Nodes) Now(context.Context, *emptypb.Empty) (*gn.NowResp, error) { 49 return &gn.NowResp{ 50 Tcp: n.db.Data.Tcp, 51 Udp: n.db.Data.Udp, 52 }, nil 53 } 54 55 func (n *Nodes) Get(_ context.Context, s *wrapperspb.StringValue) (*point.Point, error) { 56 p, ok := n.manager.GetNode(s.Value) 57 if !ok { 58 return &point.Point{}, fmt.Errorf("node not found") 59 } 60 61 return p, nil 62 } 63 64 func (n *Nodes) Save(c context.Context, p *point.Point) (*point.Point, error) { 65 if p.Name == "" || p.Group == "" { 66 return &point.Point{}, fmt.Errorf("add point name or group is empty") 67 } 68 n.manager.DeleteNode(p.Hash) 69 n.manager.AddNode(p) 70 return p, n.db.Save() 71 } 72 73 func (n *Nodes) Manager(context.Context, *emptypb.Empty) (*node.Manager, error) { 74 m := n.manager.GetManager() 75 76 if m.Tags == nil { 77 m.Tags = map[string]*pt.Tags{} 78 } 79 80 if n.ruleTags != nil { 81 for _, v := range n.ruleTags() { 82 if _, ok := m.Tags[v]; !ok { 83 m.Tags[v] = &pt.Tags{} 84 } 85 } 86 } 87 88 return m, nil 89 } 90 91 func (n *Nodes) Use(c context.Context, s *gn.UseReq) (*point.Point, error) { 92 p, err := n.Get(c, &wrapperspb.StringValue{Value: s.Hash}) 93 if err != nil { 94 return &point.Point{}, fmt.Errorf("get node failed: %w", err) 95 } 96 97 if s.Tcp { 98 n.db.Data.Tcp = p 99 } 100 if s.Udp { 101 n.db.Data.Udp = p 102 } 103 104 err = n.db.Save() 105 if err != nil { 106 return p, fmt.Errorf("save config failed: %w", err) 107 } 108 return p, nil 109 } 110 111 func (n *Nodes) Remove(_ context.Context, s *wrapperspb.StringValue) (*emptypb.Empty, error) { 112 n.manager.DeleteNode(s.Value) 113 return &emptypb.Empty{}, n.db.Save() 114 } 115 116 type latencyDialer struct { 117 netapi.Proxy 118 ipv6 bool 119 } 120 121 func (w *latencyDialer) Conn(ctx context.Context, a netapi.Address) (net.Conn, error) { 122 if w.ipv6 { 123 a.PreferIPv6(true) 124 } else { 125 a.PreferIPv4(true) 126 } 127 128 return w.Proxy.Conn(ctx, a) 129 } 130 131 func (w *latencyDialer) PacketConn(ctx context.Context, a netapi.Address) (net.PacketConn, error) { 132 if w.ipv6 { 133 a.PreferIPv6(true) 134 } else { 135 a.PreferIPv4(true) 136 } 137 138 return w.Proxy.PacketConn(ctx, a) 139 } 140 141 func (n *Nodes) Latency(c context.Context, req *latency.Requests) (*latency.Response, error) { 142 resp := &latency.Response{IdLatencyMap: make(map[string]*durationpb.Duration)} 143 var mu sync.Mutex 144 145 var wg sync.WaitGroup 146 for _, s := range req.Requests { 147 wg.Add(1) 148 go func(s *latency.Request) { 149 defer wg.Done() 150 p, err := n.Get(c, &wrapperspb.StringValue{Value: s.GetHash()}) 151 if err != nil { 152 return 153 } 154 155 px, err := n.outBound.GetDialer(p) 156 if err != nil { 157 return 158 } 159 160 px = &latencyDialer{Proxy: px, ipv6: s.GetIpv6()} 161 162 var t *durationpb.Duration 163 z, ok := s.Protocol.Protocol.(interface { 164 Latency(netapi.Proxy) (*durationpb.Duration, error) 165 }) 166 if ok { 167 t, err = z.Latency(px) 168 if err != nil { 169 log.Error("latency failed", "err", err) 170 } 171 } 172 173 mu.Lock() 174 resp.IdLatencyMap[s.Id] = t 175 mu.Unlock() 176 }(s) 177 } 178 179 wg.Wait() 180 return resp, nil 181 } 182 183 func (n *Nodes) Outbound() *outbound { return n.outBound } 184 185 func load(path string) *jsondb.DB[*node.Node] { 186 defaultNode := &node.Node{ 187 Tcp: &point.Point{}, 188 Udp: &point.Point{}, 189 Links: map[string]*subscribe.Link{}, 190 Manager: &node.Manager{ 191 GroupsV2: map[string]*node.Nodes{}, 192 Nodes: map[string]*point.Point{}, 193 Tags: map[string]*pt.Tags{}, 194 }, 195 } 196 197 return jsondb.Open[*node.Node](path, defaultNode) 198 }