Skip to content

Commit be64b4c

Browse files
Add files via upload
0 parents  commit be64b4c

2 files changed

Lines changed: 131 additions & 0 deletions

File tree

core_engine/go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module connection_tester
2+
3+
go 1.25.0

core_engine/main.go

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// core_engine/main.go
2+
3+
package main
4+
5+
import (
6+
"context"
7+
"encoding/json"
8+
"fmt"
9+
"io"
10+
"net"
11+
"net/http"
12+
"os"
13+
"sync"
14+
"time"
15+
16+
"golang.org/x/net/proxy"
17+
)
18+
19+
// note: This struct defines the input format we expect from Python.
20+
type TestConfig struct {
21+
Tag string `json:"tag"`
22+
Config json.RawMessage `json:"config"` // * We use RawMessage to keep the outbound config as-is.
23+
TestPort int `json:"test_port"`
24+
}
25+
26+
// note: This struct defines the output format we send back to Python.
27+
type TestResult struct {
28+
Tag string `json:"tag"`
29+
Ping int64 `json:"ping_ms"` // * Ping in milliseconds
30+
Status string `json:"status"`
31+
}
32+
33+
func main() {
34+
// ! Read the list of configs from Standard Input (stdin).
35+
inputData, err := io.ReadAll(os.Stdin)
36+
if err != nil {
37+
fmt.Fprintf(os.Stderr, "Error reading stdin: %v\n", err)
38+
os.Exit(1)
39+
}
40+
41+
var configs []TestConfig
42+
if err := json.Unmarshal(inputData, &configs); err != nil {
43+
fmt.Fprintf(os.Stderr, "Error unmarshaling json: %v\n", err)
44+
os.Exit(1)
45+
}
46+
47+
results := make([]TestResult, 0)
48+
var wg sync.WaitGroup // ? A WaitGroup waits for a collection of goroutines to finish.
49+
var mu sync.Mutex // ? A Mutex prevents race conditions when writing to the results slice.
50+
51+
// * All tests will run concurrently!
52+
for _, conf := range configs {
53+
wg.Add(1)
54+
go func(c TestConfig) {
55+
defer wg.Done()
56+
57+
// * Create a temporary config file for the Xray core to use.
58+
tmpFile, err := os.CreateTemp("", "xray-test-*.json")
59+
if err != nil {
60+
return
61+
}
62+
defer os.Remove(tmpFile.Name())
63+
64+
fullConfig := map[string]interface{}{
65+
"inbounds": []map[string]interface{}{
66+
{
67+
"protocol": "socks",
68+
"port": c.TestPort,
69+
"listen": "127.0.0.1",
70+
"settings": map[string]interface{}{"udp": true},
71+
},
72+
},
73+
"outbounds": []json.RawMessage{c.Config},
74+
}
75+
76+
configBytes, _ := json.Marshal(fullConfig)
77+
tmpFile.Write(configBytes)
78+
tmpFile.Close()
79+
80+
// todo: We need a way to run the xray executable here.
81+
// For now, let's assume it's running and we can test the SOCKS port.
82+
// This part will be completed in the next steps.
83+
84+
ping, status := testProxy(c.TestPort)
85+
86+
mu.Lock()
87+
results = append(results, TestResult{Tag: c.Tag, Ping: ping, Status: status})
88+
mu.Unlock()
89+
}(conf)
90+
}
91+
92+
wg.Wait() // * Wait for all tests to complete.
93+
94+
// ! Print the final results as a JSON array to Standard Output (stdout).
95+
outputData, _ := json.Marshal(results)
96+
fmt.Println(string(outputData))
97+
}
98+
99+
func testProxy(port int) (int64, string) {
100+
// * This function tests the SOCKS5 proxy that the Xray core creates.
101+
targetURL := "https://www.gstatic.com/generate_204"
102+
timeout := 8 * time.Second
103+
104+
dialer, err := proxy.SOCKS5("tcp", fmt.Sprintf("127.0.0.1:%d", port), nil, proxy.Direct)
105+
if err != nil {
106+
return -1, "failed_dialer"
107+
}
108+
109+
httpTransport := &http.Transport{}
110+
httpClient := &http.Client{Transport: httpTransport, Timeout: timeout}
111+
httpTransport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
112+
return dialer.Dial(network, addr)
113+
}
114+
115+
start := time.Now()
116+
resp, err := httpClient.Get(targetURL)
117+
if err != nil {
118+
return -1, "failed_http"
119+
}
120+
defer resp.Body.Close()
121+
122+
if resp.StatusCode != http.StatusOK {
123+
return -1, fmt.Sprintf("bad_status_%d", resp.StatusCode)
124+
}
125+
126+
latency := time.Since(start).Milliseconds()
127+
return latency, "success"
128+
}

0 commit comments

Comments
 (0)