mirror of
https://github.com/hackdiaz-dev/free-turn-proxy.git
synced 2026-10-12 09:41:53 +02:00
refactor(logx): общий Holder вместо пакетных переменных Log
This commit is contained in:
@@ -29,6 +29,7 @@ func main() {
|
||||
|
||||
// Резолв подписки до парсинга даёт обязательный peer для валидации.
|
||||
if subURL := config.PeekSubURL(args); subURL != "" {
|
||||
sub.SetLogger(logx.New(false))
|
||||
s, ferr := sub.Fetch(context.Background(), subURL)
|
||||
if ferr != nil {
|
||||
log.Fatalf("failed to fetch subscription: %v", ferr)
|
||||
|
||||
@@ -25,9 +25,11 @@ import (
|
||||
_ "golang.org/x/crypto/x509roots/fallback"
|
||||
)
|
||||
|
||||
var Log logx.Logger = logx.Nop()
|
||||
var logHolder logx.Holder
|
||||
|
||||
func SetLogger(l logx.Logger) { Log = logx.OrNop(l) }
|
||||
func SetLogger(l logx.Logger) { logHolder.Set(l) }
|
||||
|
||||
func Log() logx.Logger { return logHolder.Get() }
|
||||
|
||||
const (
|
||||
dohQueryTimeout = 6 * time.Second
|
||||
@@ -161,7 +163,7 @@ func (r *DohResolver) forwardRaw(ctx context.Context, query []byte) ([]byte, err
|
||||
body, err := r.postWire(epCtx, ep, query)
|
||||
cancel()
|
||||
if err != nil {
|
||||
Log.Warnf("[DoH] %s: %v", ep.Hostname, err)
|
||||
Log().Warnf("[DoH] %s: %v", ep.Hostname, err)
|
||||
lastErr = err
|
||||
continue
|
||||
}
|
||||
@@ -238,7 +240,7 @@ func startDohForwarder(r *DohResolver) (_ *dohForwarder, err error) {
|
||||
udpAddr: udpConn.LocalAddr().String(),
|
||||
tcpAddr: tcpLn.Addr().String(),
|
||||
}
|
||||
Log.Infof("[DoH] forwarder listening udp=%s tcp=%s", fwd.udpAddr, fwd.tcpAddr)
|
||||
Log().Infof("[DoH] forwarder listening udp=%s tcp=%s", fwd.udpAddr, fwd.tcpAddr)
|
||||
|
||||
go fwd.serveUDP(udpConn, r)
|
||||
go fwd.serveTCP(tcpLn, r)
|
||||
@@ -251,7 +253,7 @@ func (*dohForwarder) serveUDP(conn *net.UDPConn, r *DohResolver) {
|
||||
for {
|
||||
n, client, err := conn.ReadFromUDP(buf)
|
||||
if err != nil {
|
||||
Log.Errorf("[DoH] udp read: %v", err)
|
||||
Log().Errorf("[DoH] udp read: %v", err)
|
||||
return
|
||||
}
|
||||
query := append([]byte(nil), buf[:n]...)
|
||||
@@ -260,11 +262,11 @@ func (*dohForwarder) serveUDP(conn *net.UDPConn, r *DohResolver) {
|
||||
defer cancel()
|
||||
resp, err := r.forwardRaw(ctx, q)
|
||||
if err != nil {
|
||||
Log.Warnf("[DoH] udp forward failed: %v", err)
|
||||
Log().Warnf("[DoH] udp forward failed: %v", err)
|
||||
return
|
||||
}
|
||||
if _, err := conn.WriteToUDP(resp, c); err != nil {
|
||||
Log.Warnf("[DoH] udp write: %v", err)
|
||||
Log().Warnf("[DoH] udp write: %v", err)
|
||||
}
|
||||
}(query, client)
|
||||
}
|
||||
@@ -275,7 +277,7 @@ func (*dohForwarder) serveTCP(ln *net.TCPListener, r *DohResolver) {
|
||||
for {
|
||||
conn, err := ln.Accept()
|
||||
if err != nil {
|
||||
Log.Errorf("[DoH] tcp accept: %v", err)
|
||||
Log().Errorf("[DoH] tcp accept: %v", err)
|
||||
return
|
||||
}
|
||||
go handleDohForwarderTCP(conn, r)
|
||||
@@ -303,11 +305,11 @@ func handleDohForwarderTCP(conn net.Conn, r *DohResolver) {
|
||||
resp, err := r.forwardRaw(ctx, query)
|
||||
cancel()
|
||||
if err != nil {
|
||||
Log.Warnf("[DoH] tcp forward failed: %v", err)
|
||||
Log().Warnf("[DoH] tcp forward failed: %v", err)
|
||||
return
|
||||
}
|
||||
if len(resp) > 0xFFFF {
|
||||
Log.Warnf("[DoH] response too large for TCP framing: %d", len(resp))
|
||||
Log().Warnf("[DoH] response too large for TCP framing: %d", len(resp))
|
||||
return
|
||||
}
|
||||
out := make([]byte, 2+len(resp))
|
||||
@@ -432,9 +434,9 @@ func autoDial(r *DohResolver) dialFunc {
|
||||
return func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
probed.Do(func() {
|
||||
if udpProbe(autoUDPBudget) {
|
||||
Log.Infof("[DNS] UDP/53 probe OK, using UDP")
|
||||
Log().Infof("[DNS] UDP/53 probe OK, using UDP")
|
||||
} else {
|
||||
Log.Warnf("[DNS] UDP/53 unreachable; sticky-switching to DoH")
|
||||
Log().Warnf("[DNS] UDP/53 unreachable; sticky-switching to DoH")
|
||||
useDoH.Store(true)
|
||||
}
|
||||
})
|
||||
|
||||
+22
-1
@@ -1,7 +1,10 @@
|
||||
// Package logx предоставляет уровневый логгер поверх stdlib log.
|
||||
package logx
|
||||
|
||||
import "log"
|
||||
import (
|
||||
"log"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Logger - интерфейс уровневого логирования.
|
||||
type Logger interface {
|
||||
@@ -48,3 +51,21 @@ func (nopLogger) Infof(string, ...any) {}
|
||||
func (nopLogger) Warnf(string, ...any) {}
|
||||
func (nopLogger) Errorf(string, ...any) {}
|
||||
func (nopLogger) DebugEnabled() bool { return false }
|
||||
|
||||
// Holder хранит пакетный логгер, подменяемый на лету: ядро перезапускается в том же
|
||||
// процессе (mobile), поэтому Set гонится с пишущими горутинами.
|
||||
type Holder struct {
|
||||
ptr atomic.Pointer[Logger]
|
||||
}
|
||||
|
||||
func (h *Holder) Set(l Logger) {
|
||||
v := OrNop(l)
|
||||
h.ptr.Store(&v)
|
||||
}
|
||||
|
||||
func (h *Holder) Get() Logger {
|
||||
if p := h.ptr.Load(); p != nil {
|
||||
return *p
|
||||
}
|
||||
return Nop()
|
||||
}
|
||||
|
||||
@@ -23,9 +23,11 @@ import (
|
||||
"github.com/samosvalishe/free-turn-proxy/internal/randx"
|
||||
)
|
||||
|
||||
var Log logx.Logger = logx.Nop()
|
||||
var logHolder logx.Holder
|
||||
|
||||
func SetLogger(l logx.Logger) { Log = logx.OrNop(l) }
|
||||
func SetLogger(l logx.Logger) { logHolder.Set(l) }
|
||||
|
||||
func Log() logx.Logger { return logHolder.Get() }
|
||||
|
||||
const (
|
||||
captchaAPIVersion = "5.131"
|
||||
@@ -119,7 +121,7 @@ func (s *captchaSession) logger() logx.Logger {
|
||||
if s.log != nil {
|
||||
return s.log
|
||||
}
|
||||
return Log
|
||||
return Log()
|
||||
}
|
||||
|
||||
// Solve запускает авторешение captcha против VK captchaNotRobot API.
|
||||
@@ -441,7 +443,7 @@ func parseCaptchaDebugInfo(html string) string {
|
||||
return ""
|
||||
}
|
||||
if len(found) > 1 {
|
||||
Log.Warnf("[Captcha] window.vk holds %d uuid values, debug_info may be the wrong one", len(found))
|
||||
Log().Warnf("[Captcha] window.vk holds %d uuid values, debug_info may be the wrong one", len(found))
|
||||
}
|
||||
return found[0][1]
|
||||
}
|
||||
|
||||
@@ -23,14 +23,14 @@ type Error struct {
|
||||
func ParseError(errData map[string]any) *Error {
|
||||
codeFloat, ok := errData["error_code"].(float64)
|
||||
if !ok {
|
||||
Log.Warnf("[Captcha] missing error_code in error data")
|
||||
Log().Warnf("[Captcha] missing error_code in error data")
|
||||
return nil
|
||||
}
|
||||
code := int(codeFloat)
|
||||
|
||||
redirectURI, ok := errData["redirect_uri"].(string)
|
||||
if !ok {
|
||||
Log.Warnf("[Captcha] missing redirect_uri in error data")
|
||||
Log().Warnf("[Captcha] missing redirect_uri in error data")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ func ParseError(errData map[string]any) *Error {
|
||||
|
||||
errorMsg, ok := errData["error_msg"].(string)
|
||||
if !ok {
|
||||
Log.Warnf("[Captcha] missing error_msg in error data")
|
||||
Log().Warnf("[Captcha] missing error_msg in error data")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ func ParseError(errData map[string]any) *Error {
|
||||
if parsed, err := neturl.Parse(redirectURI); err == nil {
|
||||
sessionToken = parsed.Query().Get("session_token")
|
||||
} else {
|
||||
Log.Warnf("[Captcha] failed to parse redirect_uri: %v", err)
|
||||
Log().Warnf("[Captcha] failed to parse redirect_uri: %v", err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/samosvalishe/free-turn-proxy/internal/client/ish"
|
||||
@@ -26,12 +27,16 @@ import (
|
||||
"github.com/samosvalishe/free-turn-proxy/internal/provider/vk/internal/personanet"
|
||||
)
|
||||
|
||||
// Debug включает логирование проксируемого браузерного трафика.
|
||||
var Debug bool
|
||||
// debugFlag включает логирование проксируемого браузерного трафика.
|
||||
var debugFlag atomic.Bool
|
||||
|
||||
var Log logx.Logger = logx.Nop()
|
||||
func SetDebug(v bool) { debugFlag.Store(v) }
|
||||
|
||||
func SetLogger(l logx.Logger) { Log = logx.OrNop(l) }
|
||||
var logHolder logx.Holder
|
||||
|
||||
func SetLogger(l logx.Logger) { logHolder.Set(l) }
|
||||
|
||||
func Log() logx.Logger { return logHolder.Get() }
|
||||
|
||||
const captchaListenPort = "8765"
|
||||
|
||||
@@ -343,12 +348,12 @@ func startCaptchaServer(srv *http.Server, logPrefix string) error {
|
||||
listening = true
|
||||
wrappedListener, err := ish.WrapListener(listener)
|
||||
if err != nil {
|
||||
Log.Warnf("%s: failed to wrap listener for iSH: %v", logPrefix, err)
|
||||
Log().Warnf("%s: failed to wrap listener for iSH: %v", logPrefix, err)
|
||||
wrappedListener = listener
|
||||
}
|
||||
go func(listener net.Listener) {
|
||||
if err := srv.Serve(listener); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
Log.Errorf("%s: %s", logPrefix, err)
|
||||
Log().Errorf("%s: %s", logPrefix, err)
|
||||
}
|
||||
}(wrappedListener)
|
||||
}
|
||||
@@ -375,7 +380,7 @@ func runCaptchaServerAndWait(ctx context.Context, handler http.Handler, captchaU
|
||||
shutCtx, shutCancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
defer shutCancel()
|
||||
if err := srv.Shutdown(shutCtx); err != nil {
|
||||
Log.Warnf("%s: shutdown warning: %v", logPrefix, err)
|
||||
Log().Warnf("%s: shutdown warning: %v", logPrefix, err)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -435,18 +440,18 @@ func (t *loggingTransport) RoundTrip(req *http.Request) (*http.Response, error)
|
||||
if isCaptchaRequest {
|
||||
b, err := io.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
Log.Warnf("[Captcha Proxy] failed to read request body: %v", err)
|
||||
Log().Warnf("[Captcha Proxy] failed to read request body: %v", err)
|
||||
b = nil
|
||||
}
|
||||
req.Body = io.NopCloser(bytes.NewReader(b))
|
||||
|
||||
if Debug {
|
||||
Log.Debugf("[Captcha Proxy] real browser sent %s data: %s", req.URL.Path, string(b))
|
||||
if debugFlag.Load() {
|
||||
Log().Debugf("[Captcha Proxy] real browser sent %s data: %s", req.URL.Path, string(b))
|
||||
if env := browserPowEnvelope(b); env != "" {
|
||||
Log.Debugf("[Captcha Proxy] real browser pow: %s", env)
|
||||
Log().Debugf("[Captcha Proxy] real browser pow: %s", env)
|
||||
}
|
||||
for k, v := range req.Header {
|
||||
Log.Debugf("[Captcha Proxy] header (%s): %s = %s", req.URL.Path, k, strings.Join(v, ", "))
|
||||
Log().Debugf("[Captcha Proxy] header (%s): %s = %s", req.URL.Path, k, strings.Join(v, ", "))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -456,11 +461,11 @@ func (t *loggingTransport) RoundTrip(req *http.Request) (*http.Response, error)
|
||||
// Весь трафик виджета, а не только check/componentDone: иначе не видно, зовёт
|
||||
// ли живой браузер то, чего не зовём мы, и с какими паузами.
|
||||
if err != nil {
|
||||
Log.Debugf("[Captcha Proxy] http %s %s failed t=%s after=%s %s err=%v",
|
||||
Log().Debugf("[Captcha Proxy] http %s %s failed t=%s after=%s %s err=%v",
|
||||
req.Method, captcha.SafeURL(req.URL.String()), t.elapsed(), time.Since(start).Truncate(time.Millisecond), navSummary(req), err)
|
||||
return nil, err
|
||||
}
|
||||
Log.Debugf("[Captcha Proxy] http %s %s status=%d t=%s after=%s %s",
|
||||
Log().Debugf("[Captcha Proxy] http %s %s status=%d t=%s after=%s %s",
|
||||
req.Method, captcha.SafeURL(req.URL.String()), resp.StatusCode, t.elapsed(), time.Since(start).Truncate(time.Millisecond), navSummary(req))
|
||||
return resp, nil
|
||||
}
|
||||
@@ -509,7 +514,7 @@ func solveViaProxy(ctx context.Context, redirectURI string, dialer net.Dialer, p
|
||||
rewriteProxyRequest(req.Out, targetURL)
|
||||
},
|
||||
ErrorHandler: func(w http.ResponseWriter, r *http.Request, err error) {
|
||||
Log.Errorf("[Captcha Proxy] %s %s: %v", r.Method, r.URL.String(), err)
|
||||
Log().Errorf("[Captcha Proxy] %s %s: %v", r.Method, r.URL.String(), err)
|
||||
http.Error(w, "ошибка прокси капчи, детали в консоли клиента", http.StatusBadGateway)
|
||||
},
|
||||
ModifyResponse: func(res *http.Response) error {
|
||||
@@ -528,8 +533,8 @@ func solveViaProxy(ctx context.Context, redirectURI string, dialer net.Dialer, p
|
||||
|
||||
contentType := res.Header.Get("Content-Type")
|
||||
contentEncoding := res.Header.Get("Content-Encoding")
|
||||
if Debug {
|
||||
Log.Debugf("[Captcha Proxy] %s %d | Content-Type: %q, Encoding: %q", res.Request.Method, res.StatusCode, contentType, contentEncoding)
|
||||
if debugFlag.Load() {
|
||||
Log().Debugf("[Captcha Proxy] %s %d | Content-Type: %q, Encoding: %q", res.Request.Method, res.StatusCode, contentType, contentEncoding)
|
||||
}
|
||||
|
||||
shouldInspectBody := strings.Contains(contentType, "text/html") ||
|
||||
@@ -547,7 +552,7 @@ func solveViaProxy(ctx context.Context, redirectURI string, dialer net.Dialer, p
|
||||
reader = gzReader
|
||||
defer func() {
|
||||
if err := gzReader.Close(); err != nil {
|
||||
Log.Warnf("[Captcha Proxy] close gzip reader: %v", err)
|
||||
Log().Warnf("[Captcha Proxy] close gzip reader: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -599,10 +604,10 @@ func solveViaProxy(ctx context.Context, redirectURI string, dialer net.Dialer, p
|
||||
mux.HandleFunc("/local-captcha-result", func(w http.ResponseWriter, r *http.Request) {
|
||||
token := r.FormValue("token")
|
||||
if token != "" {
|
||||
Log.Infof("[Captcha] received success token from browser (%d bytes)", len(token))
|
||||
Log().Infof("[Captcha] received success token from browser (%d bytes)", len(token))
|
||||
notifyKey(keyCh, token)
|
||||
} else {
|
||||
Log.Warnf("[Captcha] received empty token from browser")
|
||||
Log().Warnf("[Captcha] received empty token from browser")
|
||||
}
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
@@ -665,7 +670,7 @@ func solveViaProxy(ctx context.Context, redirectURI string, dialer net.Dialer, p
|
||||
})
|
||||
|
||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
Log.Debugf("[Captcha Proxy] HTTP %s %s", r.Method, r.URL.Path)
|
||||
Log().Debugf("[Captcha Proxy] HTTP %s %s", r.Method, r.URL.Path)
|
||||
if r.URL.Path == "/" && targetURL.Path != "" && targetURL.Path != "/" && r.URL.RawQuery == "" {
|
||||
// не логируем полный redirect URL - шум в консоли
|
||||
http.Redirect(w, r, localCaptchaURLForTarget(targetURL), http.StatusTemporaryRedirect)
|
||||
|
||||
@@ -176,9 +176,9 @@ func splitSliderSteps(steps []int) (int, []int, int, error) {
|
||||
// Штатный формат: [size, ...пары свапов, attempts].
|
||||
attempts = tail[len(tail)-1]
|
||||
tail = tail[:len(tail)-1]
|
||||
Log.Debugf("[Captcha] slider attempts from payload=%d", attempts)
|
||||
Log().Debugf("[Captcha] slider attempts from payload=%d", attempts)
|
||||
} else {
|
||||
Log.Debugf("[Captcha] slider payload without attempts counter; default=%d", attempts)
|
||||
Log().Debugf("[Captcha] slider payload without attempts counter; default=%d", attempts)
|
||||
}
|
||||
if attempts <= 0 {
|
||||
attempts = 4
|
||||
|
||||
@@ -17,7 +17,7 @@ func (*Client) defaultAutoSolve(
|
||||
client tlsclient.HttpClient,
|
||||
profile browserprofile.Profile,
|
||||
) (string, error) {
|
||||
log := captcha.Log
|
||||
log := captcha.Log()
|
||||
log.Infof("[STREAM %d] [Captcha] Solving captcha (platform=%s)...", streamID, profile.Platform)
|
||||
|
||||
if captchaErr.SessionToken == "" {
|
||||
|
||||
@@ -43,7 +43,7 @@ func New(cfg Config, solver ManualSolverFunc) (*Provider, error) {
|
||||
}
|
||||
captcha.SetLogger(cfg.Log)
|
||||
manualcaptcha.SetLogger(cfg.Log)
|
||||
manualcaptcha.Debug = cfg.Debug
|
||||
manualcaptcha.SetDebug(cfg.Debug)
|
||||
auth := vkauth.New(vkauth.Config{
|
||||
Credentials: cfg.Credentials,
|
||||
Dialer: cfg.Dialer,
|
||||
|
||||
+8
-2
@@ -5,14 +5,20 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/samosvalishe/free-turn-proxy/internal/logx"
|
||||
"github.com/samosvalishe/free-turn-proxy/internal/uri"
|
||||
)
|
||||
|
||||
var logHolder logx.Holder
|
||||
|
||||
func SetLogger(l logx.Logger) { logHolder.Set(l) }
|
||||
|
||||
func log() logx.Logger { return logHolder.Get() }
|
||||
|
||||
// Sub представляет структуру подписки на серверы.
|
||||
type Sub struct {
|
||||
Name string
|
||||
@@ -132,7 +138,7 @@ func Parse(r io.Reader) (*Sub, error) {
|
||||
s.Nodes = append(s.Nodes, node)
|
||||
lastNode = &s.Nodes[len(s.Nodes)-1]
|
||||
} else {
|
||||
log.Printf("warning: skipped invalid freeturn URI in subscription: %v", err)
|
||||
log().Warnf("[Sub] skipped invalid freeturn URI: %v", err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -250,6 +250,7 @@ func startLocked(configJSON string, tunFD int, withTunnel bool) error {
|
||||
// Резолв подписки до парсинга даёт обязательный peer.
|
||||
overlayURI := ""
|
||||
if subURL := config.PeekSubURLJSON(raw); subURL != "" {
|
||||
sub.SetLogger(coreLog())
|
||||
s, err := sub.Fetch(context.Background(), subURL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to fetch subscription: %w", err)
|
||||
|
||||
Reference in New Issue
Block a user