@@ -18,10 +18,11 @@ import (
1818)
1919
2020type TestConfig struct {
21- Tag string `json:"tag"`
22- Config json.RawMessage `json:"config"`
23- TestPort int `json:"test_port"`
24- XrayPath string `json:"xray_path"`
21+ Tag string `json:"tag"`
22+ Protocol string `json:"protocol"`
23+ Config json.RawMessage `json:"config"`
24+ TestPort int `json:"test_port"`
25+ ClientPath string `json:"client_path"`
2526 FragmentConfig json.RawMessage `json:"fragment_config,omitempty"`
2627}
2728
@@ -33,14 +34,9 @@ type TestResult struct {
3334
3435func main () {
3536 inputData , err := io .ReadAll (os .Stdin )
36- if err != nil {
37- os .Exit (1 )
38- }
39-
37+ if err != nil { os .Exit (1 ) }
4038 var configs []TestConfig
41- if err := json .Unmarshal (inputData , & configs ); err != nil {
42- os .Exit (1 )
43- }
39+ if err := json .Unmarshal (inputData , & configs ); err != nil { os .Exit (1 ) }
4440
4541 results := make (chan TestResult , len (configs ))
4642 var wg sync.WaitGroup
@@ -50,64 +46,65 @@ func main() {
5046 go func (c TestConfig ) {
5147 defer wg .Done ()
5248
53- tmpFile , err := os .CreateTemp ("" , "xray-test-*.json" )
54- if err != nil {
55- results <- TestResult {Tag : c .Tag , Ping : - 1 , Status : "tempfile_error" }
56- return
57- }
58- defer os .Remove (tmpFile .Name ())
49+ var cmd * exec.Cmd
50+ var configFile * os.File
51+
52+ if c .Protocol == "hysteria" || c .Protocol == "hysteria2" || c .Protocol == "hy2" {
53+
54+ configFile , err = os .CreateTemp ("" , "hysteria-*.json" )
55+ if err != nil { results <- TestResult {Tag : c .Tag , Ping : - 1 , Status : "tempfile_error" }; return }
56+ defer os .Remove (configFile .Name ())
57+
58+ configFile .Write (c .Config )
59+ configFile .Close ()
5960
61+ cmd = exec .Command (c .ClientPath , "client" , "-c" , configFile .Name ())
6062
61- outbounds := []json. RawMessage { c . Config }
63+ } else {
6264
63- if len (c .FragmentConfig ) > 0 && string (c .FragmentConfig ) != "null" {
64- fragmentOutbound := map [string ]interface {}{
65- "protocol" : "freedom" ,
66- "tag" : "fragment" ,
67- "settings" : map [string ]json.RawMessage {
68- "fragment" : c .FragmentConfig ,
69- },
65+ configFile , err = os .CreateTemp ("" , "xray-*.json" )
66+ if err != nil { results <- TestResult {Tag : c .Tag , Ping : - 1 , Status : "tempfile_error" }; return }
67+ defer os .Remove (configFile .Name ())
68+
69+ outbounds := []json.RawMessage {c .Config }
70+ if len (c .FragmentConfig ) > 0 && string (c .FragmentConfig ) != "null" {
71+ fragmentOutbound := map [string ]interface {}{ "protocol" : "freedom" , "tag" : "fragment" , "settings" : map [string ]json.RawMessage {"fragment" : c .FragmentConfig }}
72+ fragmentBytes , _ := json .Marshal (fragmentOutbound )
73+ outbounds = append (outbounds , json .RawMessage (fragmentBytes ))
7074 }
71- fragmentBytes , _ := json .Marshal (fragmentOutbound )
72- outbounds = append (outbounds , json .RawMessage (fragmentBytes ))
73- }
7475
75- fullConfig := map [string ]interface {}{
76- "log" : map [string ]string {"loglevel" : "warning" }, // Use "warning" to reduce noise
77- "inbounds" : []map [string ]interface {}{{"protocol" : "socks" , "port" : c .TestPort , "listen" : "127.0.0.1" , "settings" : map [string ]interface {}{"auth" : "noauth" , "udp" : true }}},
78- "outbounds" : outbounds ,
79- }
76+ fullConfig := map [string ]interface {}{
77+ "log" : map [string ]string {"loglevel" : "warning" },
78+ "inbounds" : []map [string ]interface {}{{"protocol" : "socks" , "port" : c .TestPort , "listen" : "127.0.0.1" , "settings" : map [string ]interface {}{"auth" : "noauth" , "udp" : true }}},
79+ "outbounds" : outbounds ,
80+ }
81+ configBytes , _ := json .Marshal (fullConfig )
82+ configFile .Write (configBytes )
83+ configFile .Close ()
8084
81- configBytes , _ := json .Marshal (fullConfig )
82- tmpFile .Write (configBytes )
83- tmpFile .Close ()
85+ cmd = exec .Command (c .ClientPath , "-c" , configFile .Name ())
86+ }
8487
8588 ctx , cancel := context .WithTimeout (context .Background (), 15 * time .Second )
8689 defer cancel ()
90+ cmd .SysProcAttr = & exec.SysProcAttr {HideWindow : true }
91+ cmd .Cancel = func () error { return cmd .Process .Kill () }
8792
88- cmd := exec .CommandContext (ctx , c .XrayPath , "-c" , tmpFile .Name ())
89-
90- var xrayOutput bytes.Buffer
91- cmd .Stdout = & xrayOutput
92- cmd .Stderr = & xrayOutput
93+ var clientOutput bytes.Buffer
94+ cmd .Stdout = & clientOutput
95+ cmd .Stderr = & clientOutput
9396
9497 if err := cmd .Start (); err != nil {
95- results <- TestResult {Tag : c .Tag , Ping : - 1 , Status : "xray_start_failed" }
96- return
98+ results <- TestResult {Tag : c .Tag , Ping : - 1 , Status : "client_start_failed" }; return
9799 }
98100
99- time .Sleep (800 * time .Millisecond )
100-
101+ time .Sleep (900 * time .Millisecond )
101102 ping , status := testProxy (c .TestPort )
102103
103104 if status != "success" {
104- logStr := string (xrayOutput .Bytes ())
105- logStr = strings .ReplaceAll (logStr , "\n " , " " )
106- logStr = strings .ReplaceAll (logStr , "\r " , "" )
107- if len (logStr ) > 250 {
108- logStr = logStr [:250 ]
109- }
110- status = fmt .Sprintf ("%s | xray_log: %s" , status , logStr )
105+ logStr := strings .ReplaceAll (string (clientOutput .Bytes ()), "\n " , " " )
106+ if len (logStr ) > 200 { logStr = logStr [:200 ] }
107+ status = fmt .Sprintf ("%s | log: %s" , status , logStr )
111108 }
112109
113110 cmd .Process .Kill ()
@@ -121,40 +118,21 @@ func main() {
121118 close (results )
122119
123120 finalResults := make ([]TestResult , 0 , len (configs ))
124- for res := range results {
125- finalResults = append (finalResults , res )
126- }
127-
121+ for res := range results { finalResults = append (finalResults , res ) }
128122 outputData , _ := json .Marshal (finalResults )
129123 fmt .Println (string (outputData ))
130124}
131125
132126func testProxy (port int ) (int64 , string ) {
133127 targetURL := "http://www.google.com/generate_204"
134128 timeout := 8 * time .Second
135-
136129 dialer , err := proxy .SOCKS5 ("tcp" , fmt .Sprintf ("127.0.0.1:%d" , port ), nil , proxy .Direct )
137- if err != nil {
138- return - 1 , fmt .Sprintf ("failed_dialer: %v" , err )
139- }
140-
141- httpTransport := & http.Transport {}
142- httpClient := & http.Client {Transport : httpTransport , Timeout : timeout }
143- httpTransport .DialContext = func (ctx context.Context , network , addr string ) (net.Conn , error ) {
144- return dialer .Dial (network , addr )
145- }
146-
130+ if err != nil { return - 1 , fmt .Sprintf ("failed_dialer: %v" , err ) }
131+ httpClient := & http.Client { Transport : & http.Transport {DialContext : func (ctx context.Context , network , addr string ) (net.Conn , error ) { return dialer .Dial (network , addr ) }}, Timeout : timeout }
147132 start := time .Now ()
148133 resp , err := httpClient .Get (targetURL )
149- if err != nil {
150- return - 1 , fmt .Sprintf ("failed_http: %v" , err )
151- }
134+ if err != nil { return - 1 , fmt .Sprintf ("failed_http: %v" , err ) }
152135 defer resp .Body .Close ()
153-
154- if resp .StatusCode != http .StatusNoContent {
155- return - 1 , fmt .Sprintf ("bad_status_%d" , resp .StatusCode )
156- }
157-
158- latency := time .Since (start ).Milliseconds ()
159- return latency , "success"
136+ if resp .StatusCode != http .StatusNoContent { return - 1 , fmt .Sprintf ("bad_status_%d" , resp .StatusCode ) }
137+ return time .Since (start ).Milliseconds (), "success"
160138}
0 commit comments