package app import ( "context" "net" "time" transportcfg "selective-vpn-api/app/transportcfg" ) type transportDialRunner func(ctx context.Context, network, address string) (net.Conn, error) var transportDialContext transportDialRunner = func(ctx context.Context, network, address string) (net.Conn, error) { var d net.Dialer return d.DialContext(ctx, network, address) } type transportDialEndpoint struct { Host string Port int } func (ep transportDialEndpoint) address() string { return transportcfg.Endpoint{Host: ep.Host, Port: ep.Port}.Address() } func transportProbeClientLatency(client TransportClient) (int, error) { return transportcfg.ProbeClientLatency(transportCfgClient(client), transportProbeDeps()) } func transportProbeDialEndpoint(client TransportClient, ep transportDialEndpoint, timeout time.Duration) (int, error) { return transportcfg.ProbeDialEndpoint( transportCfgClient(client), transportcfg.Endpoint{Host: ep.Host, Port: ep.Port}, timeout, transportProbeDeps(), ) } func transportProbeDialEndpointHost(ep transportDialEndpoint, timeout time.Duration) (int, error) { return transportcfg.ProbeDialEndpointHost( transportcfg.Endpoint{Host: ep.Host, Port: ep.Port}, timeout, transportcfg.DialRunner(transportDialContext), ) } func transportProbeDialEndpointInNetns(client TransportClient, ep transportDialEndpoint, timeout time.Duration) (int, error) { return transportcfg.ProbeDialEndpointInNetns( transportCfgClient(client), transportcfg.Endpoint{Host: ep.Host, Port: ep.Port}, timeout, transportProbeDeps(), ) } func transportCollectProbeEndpoints(client TransportClient) []transportDialEndpoint { return transportDialEndpointsFromCfg(transportcfg.CollectProbeEndpoints(transportCfgClient(client), nil, transportConfigInt)) } func transportCollectConfigProbeEndpoints(cfg map[string]any) []transportDialEndpoint { return transportDialEndpointsFromCfg(transportcfg.CollectConfigProbeEndpoints(cfg, transportConfigInt)) } func transportCollectSingBoxConfigProbeEndpoints(client TransportClient) []transportDialEndpoint { return transportDialEndpointsFromCfg(transportcfg.CollectSingBoxConfigProbeEndpoints(transportCfgClient(client), nil)) } func transportCollectProbeEndpointsRecursive(node any, out *[]transportDialEndpoint) { if out == nil { return } tmp := make([]transportcfg.Endpoint, 0, len(*out)) for _, ep := range *out { tmp = append(tmp, transportcfg.Endpoint{Host: ep.Host, Port: ep.Port}) } transportcfg.CollectProbeEndpointsRecursive(node, &tmp) *out = transportDialEndpointsFromCfg(tmp) } func transportParseDialEndpoint(raw string, fallbackPort int) (transportDialEndpoint, bool) { ep, ok := transportcfg.ParseDialEndpoint(raw, fallbackPort) if !ok { return transportDialEndpoint{}, false } return transportDialEndpoint{Host: ep.Host, Port: ep.Port}, true } func transportDedupeProbeEndpoints(in []transportDialEndpoint) []transportDialEndpoint { cfgIn := make([]transportcfg.Endpoint, 0, len(in)) for _, ep := range in { cfgIn = append(cfgIn, transportcfg.Endpoint{Host: ep.Host, Port: ep.Port}) } return transportDialEndpointsFromCfg(transportcfg.DedupeProbeEndpoints(cfgIn)) } func transportParseInt(raw any) (int, bool) { return transportcfg.ParseInt(raw) } func splitCSV(raw string) []string { return transportcfg.SplitCSV(raw) } func transportProbeDeps() transportcfg.ProbeDeps { return transportcfg.ProbeDeps{ Dial: transportcfg.DialRunner(transportDialContext), HealthTimeout: transportBackendHealthTimeout, ProbeTimeout: transportBackendProbeTimeout, NetnsEnabled: func(c transportcfg.Client) bool { return transportNetnsEnabled(transportClientFromCfg(c)) }, NetnsName: func(c transportcfg.Client) string { return transportNetnsName(transportClientFromCfg(c)) }, NetnsExecCommand: func(c transportcfg.Client, ns string, command ...string) (string, []string, error) { return transportNetnsExecCommand(transportClientFromCfg(c), ns, command...) }, RunCommand: func(timeout time.Duration, name string, args ...string) (string, string, int, error) { return transportRunCommand(timeout, name, args...) }, CommandError: transportCommandError, ShellJoinArgs: func(args []string) string { return shellJoinArgs(args) }, ConfigInt: transportConfigInt, } } func transportClientFromCfg(client transportcfg.Client) TransportClient { return TransportClient{ ID: client.ID, Kind: TransportClientKind(client.Kind), Config: cloneMap(client.Config), } } func transportDialEndpointsFromCfg(in []transportcfg.Endpoint) []transportDialEndpoint { out := make([]transportDialEndpoint, 0, len(in)) for _, ep := range in { out = append(out, transportDialEndpoint{Host: ep.Host, Port: ep.Port}) } return out }