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  }