@@ -4,51 +4,76 @@ import (
44 "context"
55 "crypto/tls"
66 "fmt"
7- // "net"
7+ "net"
88 "net/http"
99 "os"
1010 "os/exec"
1111 "runtime"
1212 "time"
1313
1414 "github.com/cretz/bine/tor"
15- // "golang.org/x/net/proxy"
15+ "github.com/wabarc/logger"
16+ "golang.org/x/net/proxy"
1617)
1718
18- func newTorClient () (* http.Client , * tor.Tor , error ) {
19- // Lookup tor executable file
20- if _ , err := exec .LookPath ("tor" ); err != nil {
21- return nil , nil , fmt .Errorf ("%w" , err )
22- }
19+ func newTorClient (done <- chan bool ) (* http.Client , error ) {
20+ var dialer proxy.ContextDialer
21+ if useProxy () {
22+ // Create a socks5 dialer
23+ pxy , err := proxy .SOCKS5 ("tcp" , "127.0.0.1:9050" , nil , proxy .Direct )
24+ if err != nil {
25+ return nil , fmt .Errorf ("Can't connect to the proxy: %w" , err )
26+ }
2327
24- // Start tor with default config
25- startConf := & tor.StartConf {TempDataDirBase : os .TempDir ()}
26- t , err := tor .Start (nil , startConf )
27- if err != nil {
28- return nil , nil , fmt .Errorf ("Make connection failed: %w" , err )
29- }
30- // defer t.Close()
28+ dialer = pxy .(interface {
29+ DialContext (ctx context.Context , network , addr string ) (net.Conn , error )
30+ })
31+ } else {
32+ // Lookup tor executable file
33+ if _ , err := exec .LookPath ("tor" ); err != nil {
34+ return nil , fmt .Errorf ("%w" , err )
35+ }
3136
32- // Wait at most a minute to start network and get
33- dialCtx , dialCancel := context .WithTimeout (context .Background (), time .Minute )
34- defer dialCancel ()
37+ // Start tor with default config
38+ startConf := & tor.StartConf {TempDataDirBase : os .TempDir ()}
39+ t , err := tor .Start (nil , startConf )
40+ if err != nil {
41+ return nil , fmt .Errorf ("Make connection failed: %w" , err )
42+ }
43+ // defer t.Close()
3544
36- // Make connection
37- dialer , err := t .Dialer (dialCtx , nil )
38- if err != nil {
39- t .Close ()
40- return nil , nil , fmt .Errorf ("Make connection failed: %w" , err )
41- }
45+ // Wait at most a minute to start network and get
46+ dialCtx , dialCancel := context .WithTimeout (context .Background (), time .Minute )
47+ defer dialCancel ()
4248
43- // Create a socks5 dialer
44- // pxy, err := proxy.SOCKS5("tcp", "127.0.0.1:9050", nil, proxy.Direct)
45- // if err != nil {
46- // return nil, fmt.Errorf("Can't connect to the proxy: %w", err)
47- // }
49+ // Make connection
50+ dialer , err = t .Dialer (dialCtx , nil )
51+ if err != nil {
52+ t .Close ()
53+ return nil , fmt .Errorf ("Make connection failed: %w" , err )
54+ }
4855
49- // dialer := pxy.(interface {
50- // DialContext(ctx context.Context, network, addr string) (net.Conn, error)
51- // })
56+ go func () {
57+ // Auto close tor client after 10 min
58+ tick := time .NewTicker (10 * time .Minute )
59+ for {
60+ select {
61+ case <- done :
62+ logger .Debug ("Closed tor client" )
63+ tick .Stop ()
64+ t .Close ()
65+ return
66+ case <- tick .C :
67+ logger .Debug ("Closed tor client, timeout" )
68+ tick .Stop ()
69+ t .Close ()
70+ return
71+ default :
72+ logger .Debug ("Waiting for close tor client" )
73+ }
74+ }
75+ }()
76+ }
5277
5378 return & http.Client {
5479 Timeout : timeout ,
@@ -65,5 +90,29 @@ func newTorClient() (*http.Client, *tor.Tor, error) {
6590 InsecureSkipVerify : true ,
6691 },
6792 },
68- }, t , nil
93+ }, nil
94+ }
95+
96+ func useProxy () bool {
97+ host := os .Getenv ("TOR_HOST" )
98+ port := os .Getenv ("TOR_SOCKS_PORT" )
99+ if host == "" {
100+ host = "127.0.0.1"
101+ }
102+ if port == "" {
103+ port = "9050"
104+ }
105+
106+ conn , err := net .DialTimeout ("tcp" , net .JoinHostPort (host , port ), time .Second )
107+ if err != nil {
108+ logger .Debug ("Try to connect tor proxy failed: %v" , err )
109+ return false
110+ }
111+ if conn != nil {
112+ conn .Close ()
113+ logger .Debug ("Connected: %v" , net .JoinHostPort (host , port ))
114+ return true
115+ }
116+
117+ return false
69118}
0 commit comments