@@ -18,13 +18,12 @@ import (
1818)
1919
2020type TestJob struct {
21- Tag string `json:"tag"`
22- Protocol string `json:"protocol"`
23- Config json.RawMessage `json:"config,omitempty"`
24- ConfigURI string `json:"config_uri,omitempty"`
25- ListenIP string `json:"listen_ip"`
26- TestPort int `json:"test_port"`
27- ClientPath string `json:"client_path,omitempty"`
21+ Tag string `json:"tag"`
22+ Protocol string `json:"protocol"`
23+ ConfigURI string `json:"config_uri,omitempty"`
24+ ListenIP string `json:"listen_ip"`
25+ TestPort int `json:"test_port"`
26+ ClientPath string `json:"client_path,omitempty"`
2827}
2928
3029type TestResult struct {
@@ -35,9 +34,13 @@ type TestResult struct {
3534
3635func main () {
3736 inputData , err := io .ReadAll (os .Stdin )
38- if err != nil { os .Exit (1 ) }
37+ if err != nil {
38+ os .Exit (1 )
39+ }
3940 var jobs []TestJob
40- if err := json .Unmarshal (inputData , & jobs ); err != nil { os .Exit (1 ) }
41+ if err := json .Unmarshal (inputData , & jobs ); err != nil {
42+ os .Exit (1 )
43+ }
4144
4245 results := make (chan TestResult , len (jobs ))
4346 var wg sync.WaitGroup
@@ -54,23 +57,33 @@ func main() {
5457 close (results )
5558
5659 finalResults := make ([]TestResult , 0 , len (jobs ))
57- for res := range results { finalResults = append (finalResults , res ) }
60+ for res := range results {
61+ finalResults = append (finalResults , res )
62+ }
5863 outputData , _ := json .Marshal (finalResults )
5964 fmt .Println (string (outputData ))
6065}
6166
6267func runTest (j TestJob , results chan <- TestResult ) {
68+ if j .ClientPath == "" {
69+ ping , status := testProxy (j .ListenIP , j .TestPort )
70+ results <- TestResult {Tag : j .Tag , Ping : ping , Status : status }
71+ return
72+ }
73+
6374 var cmd * exec.Cmd
6475 var configFile * os.File
6576 var err error
6677
67- // Create a context with a timeout for the entire test
6878 ctx , cancel := context .WithTimeout (context .Background (), 15 * time .Second )
6979 defer cancel ()
7080
7181 if j .Protocol == "hysteria2" {
7282 configFile , err = os .CreateTemp ("" , "hysteria-*.json" )
73- if err != nil { results <- TestResult {Tag : j .Tag , Ping : - 1 , Status : "tempfile_error" }; return }
83+ if err != nil {
84+ results <- TestResult {Tag : j .Tag , Ping : - 1 , Status : "tempfile_error" }
85+ return
86+ }
7487 defer os .Remove (configFile .Name ())
7588
7689 uriParts := strings .Split (strings .Split (j .ConfigURI , "://" )[1 ], "@" )
@@ -84,25 +97,13 @@ func runTest(j TestJob, results chan<- TestResult) {
8497 configBytes , _ := json .Marshal (config )
8598 configFile .Write (configBytes )
8699 configFile .Close ()
87- cmd = exec .CommandContext (ctx , j .ClientPath , "client" , "-c" , configFile .Name ()) // ! Use CommandContext
100+ cmd = exec .CommandContext (ctx , j .ClientPath , "client" , "-c" , configFile .Name ())
88101 } else {
89- // Default is Xray
90- configFile , err = os .CreateTemp ("" , "xray-*.json" )
91- if err != nil { results <- TestResult {Tag : j .Tag , Ping : - 1 , Status : "tempfile_error" }; return }
92- defer os .Remove (configFile .Name ())
93-
94- fullConfig := map [string ]interface {}{
95- "log" : map [string ]string {"loglevel" : "warning" },
96- "inbounds" : []map [string ]interface {}{{"protocol" : "socks" , "port" : j .TestPort , "listen" : j .ListenIP , "settings" : map [string ]interface {}{"auth" : "noauth" , "udp" : true }}},
97- "outbounds" : []json.RawMessage {j .Config },
98- }
99- configBytes , _ := json .Marshal (fullConfig )
100- configFile .Write (configBytes )
101- configFile .Close ()
102- cmd = exec .CommandContext (ctx , j .ClientPath , "-c" , configFile .Name ()) // ! Use CommandContext
102+ results <- TestResult {Tag : j .Tag , Ping : - 1 , Status : "unsupported_client_protocol" }
103+ return
103104 }
104105
105- setHideWindow (cmd ) // This function is platform-specific
106+ setHideWindow (cmd )
106107
107108 var clientOutput bytes.Buffer
108109 cmd .Stdout , cmd .Stderr = & clientOutput , & clientOutput
@@ -112,12 +113,31 @@ func runTest(j TestJob, results chan<- TestResult) {
112113 return
113114 }
114115
115- time .Sleep (900 * time .Millisecond )
116+ proxyReady := false
117+ for i := 0 ; i < 20 ; i ++ {
118+ conn , err := net .DialTimeout ("tcp" , fmt .Sprintf ("%s:%d" , j .ListenIP , j .TestPort ), 200 * time .Millisecond )
119+ if err == nil {
120+ conn .Close ()
121+ proxyReady = true
122+ break
123+ }
124+ time .Sleep (200 * time .Millisecond )
125+ }
126+
127+ if ! proxyReady {
128+ cmd .Process .Kill ()
129+ cmd .Wait ()
130+ results <- TestResult {Tag : j .Tag , Ping : - 1 , Status : "proxy_startup_timeout" }
131+ return
132+ }
133+
116134 ping , status := testProxy (j .ListenIP , j .TestPort )
117135
118136 if status != "success" {
119137 logStr := strings .ReplaceAll (string (clientOutput .Bytes ()), "\n " , " " )
120- if len (logStr ) > 200 { logStr = logStr [:200 ] }
138+ if len (logStr ) > 200 {
139+ logStr = logStr [:200 ]
140+ }
121141 status = fmt .Sprintf ("%s | log: %s" , status , logStr )
122142 }
123143
@@ -131,12 +151,23 @@ func testProxy(listenIP string, port int) (int64, string) {
131151 targetURL := "http://www.google.com/generate_204"
132152 timeout := 8 * time .Second
133153 dialer , err := proxy .SOCKS5 ("tcp" , fmt .Sprintf ("%s:%d" , listenIP , port ), nil , proxy .Direct )
134- if err != nil { return - 1 , fmt .Sprintf ("failed_dialer: %v" , err ) }
135- httpClient := & http.Client { Transport : & http.Transport {DialContext : func (ctx context.Context , network , addr string ) (net.Conn , error ) { return dialer .Dial (network , addr ) }}, Timeout : timeout }
154+ if err != nil {
155+ return - 1 , fmt .Sprintf ("failed_dialer: %v" , err )
156+ }
157+ transport := & http.Transport {
158+ DialContext : func (ctx context.Context , network , addr string ) (net.Conn , error ) {
159+ return dialer .Dial (network , addr )
160+ },
161+ }
162+ httpClient := & http.Client {Transport : transport , Timeout : timeout }
136163 start := time .Now ()
137164 resp , err := httpClient .Get (targetURL )
138- if err != nil { return - 1 , fmt .Sprintf ("failed_http: %v" , err ) }
165+ if err != nil {
166+ return - 1 , fmt .Sprintf ("failed_http: %v" , err )
167+ }
139168 defer resp .Body .Close ()
140- if resp .StatusCode != http .StatusNoContent { return - 1 , fmt .Sprintf ("bad_status_%d" , resp .StatusCode ) }
169+ if resp .StatusCode != http .StatusNoContent {
170+ return - 1 , fmt .Sprintf ("bad_status_%d" , resp .StatusCode )
171+ }
141172 return time .Since (start ).Milliseconds (), "success"
142173}
0 commit comments