@@ -14,17 +14,17 @@ import (
1414 "strings"
1515 "sync"
1616 "time"
17-
1817 "golang.org/x/net/proxy"
1918)
2019
21- type TestConfig struct {
20+ type TestJob struct {
2221 Tag string `json:"tag"`
2322 Protocol string `json:"protocol"`
24- Config json.RawMessage `json:"config"`
23+ Config json.RawMessage `json:"config,omitempty"`
24+ ConfigURI string `json:"config_uri,omitempty"`
2525 ListenIP string `json:"listen_ip"`
2626 TestPort int `json:"test_port"`
27- ClientPath string `json:"client_path"`
27+ ClientPath string `json:"client_path,omitempty "`
2828 FragmentConfig json.RawMessage `json:"fragment_config,omitempty"`
2929}
3030
@@ -37,91 +37,79 @@ type TestResult struct {
3737func main () {
3838 inputData , err := io .ReadAll (os .Stdin )
3939 if err != nil { os .Exit (1 ) }
40- var configs []TestConfig
41- if err := json .Unmarshal (inputData , & configs ); err != nil { os .Exit (1 ) }
40+ var jobs []TestJob
41+ if err := json .Unmarshal (inputData , & jobs ); err != nil { os .Exit (1 ) }
4242
43- results := make (chan TestResult , len (configs ))
43+ results := make (chan TestResult , len (jobs ))
4444 var wg sync.WaitGroup
4545
46- for _ , conf := range configs {
46+ for _ , job := range jobs {
4747 wg .Add (1 )
48- go func (c TestConfig ) {
48+ go func (j TestJob ) {
4949 defer wg .Done ()
5050
51- var cmd * exec.Cmd
52- var configFile * os.File
53-
54- ctx , cancel := context .WithTimeout (context .Background (), 15 * time .Second )
55- defer cancel ()
56-
57- if c .Protocol == "hysteria" || c .Protocol == "hysteria2" {
58- configFile , err = os .CreateTemp ("" , "hysteria-*.json" )
59- if err != nil { results <- TestResult {Tag : c .Tag , Ping : - 1 , Status : "tempfile_error" }; return }
60- defer os .Remove (configFile .Name ())
61- configFile .Write (c .Config )
62- configFile .Close ()
63- cmd = exec .CommandContext (ctx , c .ClientPath , "client" , "-c" , configFile .Name ())
64-
51+ if j .ClientPath != "" {
52+ runIndividualTest (j , results )
6553 } else {
66- configFile , err = os .CreateTemp ("" , "xray-*.json" )
67- if err != nil { results <- TestResult {Tag : c .Tag , Ping : - 1 , Status : "tempfile_error" }; return }
68- defer os .Remove (configFile .Name ())
69-
70- outbounds := []json.RawMessage {c .Config }
71- if len (c .FragmentConfig ) > 0 && string (c .FragmentConfig ) != "null" {
72- fragmentOutbound := map [string ]interface {}{ "protocol" : "freedom" , "tag" : "fragment" , "settings" : map [string ]json.RawMessage {"fragment" : c .FragmentConfig }}
73- fragmentBytes , _ := json .Marshal (fragmentOutbound )
74- outbounds = append (outbounds , json .RawMessage (fragmentBytes ))
75- }
76-
77- fullConfig := map [string ]interface {}{
78- "log" : map [string ]string {"loglevel" : "warning" },
79- "inbounds" : []map [string ]interface {}{{"protocol" : "socks" , "port" : c .TestPort , "listen" : c .ListenIP , "settings" : map [string ]interface {}{"auth" : "noauth" , "udp" : true }}},
80- "outbounds" : outbounds ,
81- }
82- configBytes , _ := json .Marshal (fullConfig )
83- configFile .Write (configBytes )
84- configFile .Close ()
85-
86- cmd = exec .CommandContext (ctx , c .ClientPath , "-c" , configFile .Name ())
54+ ping , status := testProxy (j .ListenIP , j .TestPort )
55+ results <- TestResult {Tag : j .Tag , Ping : ping , Status : status }
8756 }
57+ }(job )
58+ }
8859
60+ wg .Wait ()
61+ close (results )
8962
90- if runtime .GOOS == "windows" {
91- setHideWindow (cmd )
92- }
93-
94- var clientOutput bytes.Buffer
95- cmd .Stdout = & clientOutput
96- cmd .Stderr = & clientOutput
63+ finalResults := make ([]TestResult , 0 , len (jobs ))
64+ for res := range results { finalResults = append (finalResults , res ) }
65+ outputData , _ := json .Marshal (finalResults )
66+ fmt .Println (string (outputData ))
67+ }
9768
98- if err := cmd .Start (); err != nil {
99- results <- TestResult {Tag : c .Tag , Ping : - 1 , Status : "client_start_failed" }; return
100- }
69+ func runIndividualTest (j TestJob , results chan <- TestResult ) {
70+ var cmd * exec.Cmd
71+ configFile , err := os .CreateTemp ("" , "client-test-*.json" )
72+ if err != nil { results <- TestResult {Tag : j .Tag , Ping : - 1 , Status : "tempfile_error" }; return }
73+ defer os .Remove (configFile .Name ())
74+
75+ if j .Protocol == "hysteria2" {
76+ // Simplified Hysteria config creation
77+ uriParts := strings .Split (strings .Split (j .ConfigURI , "://" )[1 ], "@" )
78+ serverParts := strings .Split (uriParts [1 ], "?" )[0 ]
79+ sni := strings .Split (strings .Split (j .ConfigURI , "sni=" )[1 ], "#" )[0 ]
80+ config := map [string ]interface {}{
81+ "server" : serverParts , "auth" : uriParts [0 ],
82+ "socks5" : map [string ]string {"listen" : fmt .Sprintf ("%s:%d" , j .ListenIP , j .TestPort )},
83+ "tls" : map [string ]interface {}{"sni" : sni , "insecure" : true },
84+ }
85+ configBytes , _ := json .Marshal (config )
86+ configFile .Write (configBytes )
87+ configFile .Close ()
88+ cmd = exec .Command (j .ClientPath , "client" , "-c" , configFile .Name ())
89+ } else {
90+ // Logic for other individual clients can be added here
91+ results <- TestResult {Tag : j .Tag , Ping : - 1 , Status : "unsupported_individual_client" }; return
92+ }
10193
102- time .Sleep (900 * time .Millisecond )
103- ping , status := testProxy (c .ListenIP ,c .TestPort )
94+ ctx , cancel := context .WithTimeout (context .Background (), 15 * time .Second )
95+ defer cancel ()
96+ if runtime .GOOS == "windows" { setHideWindow (cmd ) }
10497
105- if status != "success" {
106- logStr := strings .ReplaceAll (string (clientOutput .Bytes ()), "\n " , " " )
107- if len (logStr ) > 200 { logStr = logStr [:200 ] }
108- status = fmt .Sprintf ("%s | log: %s" , status , logStr )
109- }
98+ var clientOutput bytes.Buffer
99+ cmd .Stdout , cmd .Stderr = & clientOutput , & clientOutput
110100
111- cmd .Process . Kill ()
112- cmd . Wait ()
101+ if err := cmd .Start (); err != nil { results <- TestResult { Tag : j . Tag , Ping : - 1 , Status : "client_start_failed" }; return }
102+ time . Sleep ( 1200 * time . Millisecond ) // Hysteria might take longer to start
113103
114- results <- TestResult {Tag : c .Tag , Ping : ping , Status : status }
115- }(conf )
104+ ping , status := testProxy (j .ListenIP , j .TestPort )
105+ if status != "success" {
106+ logStr := strings .ReplaceAll (string (clientOutput .Bytes ()), "\n " , " " )
107+ status = fmt .Sprintf ("%s | log: %s" , status , logStr [:200 ])
116108 }
117109
118- wg .Wait ()
119- close (results )
120-
121- finalResults := make ([]TestResult , 0 , len (configs ))
122- for res := range results { finalResults = append (finalResults , res ) }
123- outputData , _ := json .Marshal (finalResults )
124- fmt .Println (string (outputData ))
110+ cmd .Process .Kill ()
111+ cmd .Wait ()
112+ results <- TestResult {Tag : j .Tag , Ping : ping , Status : status }
125113}
126114
127115func testProxy (listenIP string , port int ) (int64 , string ) {
0 commit comments