tg-ws-proxy-go/mobile/mobile.go

136 lines
3.0 KiB
Go
Raw Normal View History

2026-03-22 19:39:24 +03:00
// Package mobile provides a Go mobile binding for the TG WS Proxy.
package mobile
import (
"context"
"fmt"
"log"
"net"
"os"
"path/filepath"
"github.com/Flowseal/tg-ws-proxy/internal/config"
"github.com/Flowseal/tg-ws-proxy/internal/proxy"
)
var server *proxy.Server
var cancel context.CancelFunc
// Start starts the proxy server with the given configuration.
// Returns "OK" on success or an error message.
func Start(host string, port int, dcIP string, verbose bool) string {
cfg := config.DefaultConfig()
cfg.Host = host
cfg.Port = port
if dcIP != "" {
cfg.DCIP = parseDCIP(dcIP)
}
cfg.Verbose = verbose
// Setup logging to file
logDir := getLogDir()
if err := os.MkdirAll(logDir, 0755); err != nil {
return fmt.Sprintf("Failed to create log dir: %v", err)
}
logFile := filepath.Join(logDir, "proxy.log")
f, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
return fmt.Sprintf("Failed to open log file: %v", err)
}
log.SetOutput(f)
log.SetFlags(log.Ldate | log.Ltime)
var ctx context.Context
ctx, cancel = context.WithCancel(context.Background())
server = proxy.NewServer(cfg)
if err := server.Start(ctx); err != nil {
cancel()
return fmt.Sprintf("Failed to start proxy: %v", err)
}
return "OK"
}
// Stop stops the proxy server.
func Stop() string {
if cancel != nil {
cancel()
}
if server != nil {
server.Stop()
}
return "OK"
}
// GetStatus returns the current proxy status.
func GetStatus() string {
if server == nil {
return "Not running"
}
stats := server.GetStats()
return fmt.Sprintf("Connections: %d | WS: %d | TCP: %d | Bytes Up: %d | Bytes Down: %d",
stats.ConnectionsTotal,
stats.ConnectionsWS,
stats.ConnectionsTCP,
stats.BytesUp,
stats.BytesDown)
}
// parseDCIP parses DC IP configuration string.
func parseDCIP(s string) []string {
if s == "" {
return nil
}
result := []string{}
for _, part := range split(s, ",") {
trimmed := trim(part)
if trimmed != "" {
result = append(result, trimmed)
}
}
return result
}
// getLogDir returns the log directory for Android.
func getLogDir() string {
// On Android, use app-specific directory
if dataDir := os.Getenv("ANDROID_DATA"); dataDir != "" {
return filepath.Join(dataDir, "tg-ws-proxy")
}
// Fallback to temp directory
return os.TempDir()
}
// Helper functions for string manipulation (avoiding strings package issues with gomobile)
func split(s, sep string) []string {
result := []string{}
start := 0
for i := 0; i <= len(s)-len(sep); i++ {
if s[i:i+len(sep)] == sep {
result = append(result, s[start:i])
start = i + len(sep)
}
}
result = append(result, s[start:])
return result
}
func trim(s string) string {
start := 0
end := len(s)
for start < end && (s[start] == ' ' || s[start] == '\t' || s[start] == '\n' || s[start] == '\r') {
start++
}
for end > start && (s[end-1] == ' ' || s[end-1] == '\t' || s[end-1] == '\n' || s[end-1] == '\r') {
end--
}
return s[start:end]
}
// Dummy function to use net package (required for SOCKS5)
func init() {
_ = net.Dial
}