@@ -15,6 +15,7 @@ import (
15
15
"os"
16
16
"strings"
17
17
"sync"
18
+ "time"
18
19
)
19
20
20
21
type ProxyConfig struct {
@@ -26,20 +27,21 @@ type ProxyManager struct {
26
27
currentIdx int
27
28
mu sync.Mutex
28
29
enableEdge bool
30
+ lastUsed time.Time
29
31
}
30
32
31
33
func NewProxyManager (enableEdge bool ) * ProxyManager {
32
34
return & ProxyManager {
33
35
proxies : make ([]* ProxyConfig , 0 ),
34
36
enableEdge : enableEdge ,
37
+ lastUsed : time .Now (),
35
38
}
36
39
}
37
40
38
41
func (pm * ProxyManager ) LoadProxies (filename string ) error {
39
42
file , err := os .Open (filename )
40
43
if err != nil {
41
44
if pm .enableEdge {
42
- // If edge mode is enabled and no proxy file, that's okay
43
45
return nil
44
46
}
45
47
return err
@@ -55,24 +57,18 @@ func (pm *ProxyManager) LoadProxies(filename string) error {
55
57
continue
56
58
}
57
59
58
- proxyStr := line
59
- proxyURL , err := url .Parse (proxyStr )
60
+ proxyURL , err := url .Parse (line )
60
61
if err != nil {
61
62
return fmt .Errorf ("invalid proxy URL: %s" , err )
62
63
}
63
64
64
- proxy := & ProxyConfig {
65
- proxyURL : proxyURL ,
66
- }
67
-
68
- pm .proxies = append (pm .proxies , proxy )
65
+ pm .proxies = append (pm .proxies , & ProxyConfig {proxyURL : proxyURL })
69
66
}
70
67
71
68
if err := scanner .Err (); err != nil {
72
69
return err
73
70
}
74
71
75
- // Only return error if no proxies AND edge mode is disabled
76
72
if len (pm .proxies ) == 0 && ! pm .enableEdge {
77
73
return fmt .Errorf ("no proxies loaded from configuration and edge mode is disabled" )
78
74
}
@@ -88,51 +84,73 @@ func (pm *ProxyManager) GetNextProxy() (*ProxyConfig, error) {
88
84
return nil , fmt .Errorf ("no proxies available" )
89
85
}
90
86
87
+ // Always increment the index
91
88
proxy := pm .proxies [pm .currentIdx ]
92
89
pm .currentIdx = (pm .currentIdx + 1 ) % len (pm .proxies )
93
90
91
+ // Update last used time
92
+ pm .lastUsed = time .Now ()
93
+
94
94
return proxy , nil
95
95
}
96
96
97
+ func (pm * ProxyManager ) ShouldUseDirect () bool {
98
+ pm .mu .Lock ()
99
+ defer pm .mu .Unlock ()
100
+
101
+ if ! pm .enableEdge {
102
+ return false
103
+ }
104
+
105
+ // If we have no proxies, always use direct
106
+ if len (pm .proxies ) == 0 {
107
+ return true
108
+ }
109
+
110
+ // In edge mode with proxies, use direct connection periodically
111
+ // This ensures we rotate through direct connection as well
112
+ return time .Since (pm .lastUsed ) > 5 * time .Second
113
+ }
114
+
97
115
type ProxyDialer struct {
98
116
manager * ProxyManager
99
117
}
100
118
101
119
func (d * ProxyDialer ) Dial (ctx context.Context , network , addr string ) (net.Conn , error ) {
102
- if d .manager .enableEdge {
103
- // If edge mode is enabled, try direct connection first
120
+ var lastError error
121
+
122
+ // Check if we should try direct connection first
123
+ if d .manager .ShouldUseDirect () {
104
124
conn , err := net .Dial (network , addr )
105
125
if err == nil {
106
126
return conn , nil
107
127
}
108
- // Only continue to proxies if we have any
109
- if len (d .manager .proxies ) == 0 {
110
- return nil , fmt .Errorf ("direct connection failed: %v" , err )
111
- }
128
+ lastError = err
112
129
}
113
130
114
- // If we get here and have no proxies, return error
115
- if len (d .manager .proxies ) == 0 {
116
- return nil , fmt .Errorf ("no proxies available and edge mode is disabled" )
117
- }
118
-
119
- // Try each proxy until one succeeds
120
- var lastError error
121
- for i := 0 ; i < len (d .manager .proxies ); i ++ {
131
+ // If we have proxies, try them
132
+ if len (d .manager .proxies ) > 0 {
122
133
proxy , err := d .manager .GetNextProxy ()
123
134
if err != nil {
135
+ if lastError != nil {
136
+ return nil , fmt .Errorf ("direct connection failed: %v, proxy error: %v" , lastError , err )
137
+ }
124
138
return nil , err
125
139
}
126
140
127
141
conn , err := d .dialWithProxy (proxy , network , addr )
128
- if err != nil {
129
- lastError = err
130
- continue
142
+ if err == nil {
143
+ return conn , nil
131
144
}
132
- return conn , nil
145
+ lastError = err
146
+ } else if ! d .manager .enableEdge {
147
+ return nil , fmt .Errorf ("no proxies available and edge mode is disabled" )
133
148
}
134
149
135
- return nil , fmt .Errorf ("all proxies failed, last error: %v" , lastError )
150
+ if lastError != nil {
151
+ return nil , fmt .Errorf ("all connection attempts failed, last error: %v" , lastError )
152
+ }
153
+ return nil , fmt .Errorf ("no connection methods available" )
136
154
}
137
155
138
156
func (d * ProxyDialer ) dialWithProxy (proxy * ProxyConfig , network , addr string ) (net.Conn , error ) {
@@ -283,19 +301,15 @@ func main() {
283
301
log .Fatal (err )
284
302
}
285
303
286
- port := os .Getenv ("DC_SOCKS_PROXY_PORT" )
287
- if port == "" {
288
- port = "1080"
289
- }
304
+ log .Printf ("SOCKS5 server running on :1080 (Edge Mode: %v, Users: %d, Proxies: %d)\n " ,
305
+ enableEdge , len (credentials ), len (proxyManager .proxies ))
290
306
291
- log .Printf ("SOCKS5 server running on :%s (Edge Mode: %v, Users: %d, Proxies: %d)\n " ,
292
- port , enableEdge , len (credentials ), len (proxyManager .proxies ))
293
- if err := server .ListenAndServe ("tcp" , ":" + port ); err != nil {
307
+ // Always listen on port 1080 inside container
308
+ if err := server .ListenAndServe ("tcp" , ":1080" ); err != nil {
294
309
log .Fatal (err )
295
310
}
296
311
}
297
312
298
- // Helper functions for SOCKS5
299
313
func performSocks5Handshake (conn net.Conn , proxyURL * url.URL ) error {
300
314
_ , err := conn .Write ([]byte {0x05 , 0x01 , 0x02 })
301
315
if err != nil {
0 commit comments