feat: display tip in terminal when system proxy is modified

This commit is contained in:
ltaoo committed 2026-02-10 22:55:45 +08:00
1 parent fc3dfd3ada
commit 8e1ceb7b55
5 files changed
+298

No files matched your search

+26
View File
@@ -23,6 +23,7 @@ import (
"wx_channel/internal/manager"
"wx_channel/internal/officialaccount"
"wx_channel/pkg/certificate"
"wx_channel/pkg/system"
)
var (
@@ -191,6 +192,31 @@ func root_command(cfg *config.Config) {
} else {
color.Green(fmt.Sprintf("已修改系统代理为 %v", interceptor_srv.Addr()))
color.Green("请打开需要下载的视频号页面进行下载")
has_changed := false
expected_addr := interceptor_srv.Addr()
go func() {
ticker := time.NewTicker(10 * time.Second)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
cur, err := system.FetchCurProxy(system.ProxySettings{})
if err != nil {
continue
}
cur_addr := cur.Hostname + ":" + cur.Port
changed := cur == nil || cur_addr != expected_addr
if changed {
if !has_changed {
color.Red("\n系统代理已被修改,请重新启动下载器")
}
has_changed = true
}
}
}
}()
}
fmt.Println("\n按 Ctrl+C 退出...")
<-ctx.Done()
+4
View File
@@ -37,3 +37,7 @@ func EnableProxy(arg ProxySettings) error {
func DisableProxy(arg ProxySettings) error {
return disable_proxy(arg)
}
func FetchCurProxy(arg ProxySettings) (*ProxySettings, error) {
return fetch_cur_proxy(arg)
}
+71
View File
@@ -39,6 +39,77 @@ func disable_proxy(args ProxySettings) error {
return nil
}
func fetch_cur_proxy(args ProxySettings) (*ProxySettings, error) {
device := args.Device
if device == "" {
if port, err := get_network_interfaces(); err == nil && port != nil {
device = port.Port
}
}
if device == "" {
device = "Wi-Fi"
}
webProxy, err := read_network_proxy(device, false)
if err != nil {
return nil, err
}
if webProxy.Enabled && webProxy.Server != "" && webProxy.Port != "" {
return &ProxySettings{
Device: device,
Hostname: webProxy.Server,
Port: webProxy.Port,
}, nil
}
secureProxy, err := read_network_proxy(device, true)
if err != nil {
return nil, err
}
if secureProxy.Enabled && secureProxy.Server != "" && secureProxy.Port != "" {
return &ProxySettings{
Device: device,
Hostname: secureProxy.Server,
Port: secureProxy.Port,
}, nil
}
return nil, nil
}
type network_proxy_info struct {
Enabled bool
Server string
Port string
}
func read_network_proxy(device string, secure bool) (*network_proxy_info, error) {
command := "-getwebproxy"
if secure {
command = "-getsecurewebproxy"
}
output, err := exec.Command("networksetup", command, device).Output()
if err != nil {
return nil, fmt.Errorf("读取系统代理失败,%v", err)
}
info := &network_proxy_info{}
lines := strings.Split(string(output), "\n")
for _, line := range lines {
parts := strings.SplitN(strings.TrimSpace(line), ":", 2)
if len(parts) != 2 {
continue
}
key := strings.ToLower(strings.TrimSpace(parts[0]))
value := strings.TrimSpace(parts[1])
switch key {
case "enabled":
info.Enabled = strings.EqualFold(value, "yes")
case "server":
info.Server = value
case "port":
info.Port = value
}
}
return info, nil
}
func get_network_interfaces() (*HardwarePort, error) {
// 获取所有硬件端口信息
cmd := exec.Command("networksetup", "-listallhardwareports")
+72
View File
@@ -120,6 +120,78 @@ func disable_proxy(arg ProxySettings) error {
return nil
}
func fetch_cur_proxy(arg ProxySettings) (*ProxySettings, error) {
loginUserBytes, err := exec.Command("logname").Output()
if err != nil {
return nil, fmt.Errorf("获取登录用户失败(logname): %v", err)
}
loginUser := strings.TrimSpace(string(loginUserBytes))
uidBytes, err := exec.Command("id", "-u", loginUser).Output()
if err != nil {
return nil, fmt.Errorf("获取 UID 失败: %v", err)
}
uid := strings.TrimSpace(string(uidBytes))
dbusEnv := "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/" + uid + "/bus"
mode, err := read_gsettings(loginUser, dbusEnv, "org.gnome.system.proxy", "mode")
if err != nil {
return nil, err
}
mode = strings.Trim(mode, "\"'")
if mode != "manual" {
return nil, nil
}
host, port, err := read_proxy_host_port(loginUser, dbusEnv, "org.gnome.system.proxy.http")
if err != nil {
return nil, err
}
if host == "" || port == "" || port == "0" {
host, port, err = read_proxy_host_port(loginUser, dbusEnv, "org.gnome.system.proxy.https")
if err != nil {
return nil, err
}
}
if host == "" || port == "" || port == "0" {
return nil, nil
}
return &ProxySettings{
Hostname: host,
Port: port,
}, nil
}
func get_network_interfaces() (*HardwarePort, error) {
return nil, errors.New("not support")
}
func read_proxy_host_port(loginUser string, dbusEnv string, schema string) (string, string, error) {
host, err := read_gsettings(loginUser, dbusEnv, schema, "host")
if err != nil {
return "", "", err
}
host = strings.Trim(host, "\"'")
portValue, err := read_gsettings(loginUser, dbusEnv, schema, "port")
if err != nil {
return "", "", err
}
portValue = strings.Trim(portValue, "\"'")
if host == "" {
return "", "", nil
}
if portValue == "" {
return "", "", nil
}
if _, err := strconv.Atoi(portValue); err != nil {
return "", "", nil
}
return host, portValue, nil
}
func read_gsettings(loginUser string, dbusEnv string, schema string, key string) (string, error) {
fullCmd := []string{"-u", loginUser, "env", dbusEnv, "gsettings", "get", schema, key}
cmd := exec.Command("sudo", fullCmd...)
output, err := cmd.CombinedOutput()
if err != nil {
return "", fmt.Errorf("读取系统代理失败: sudo %s\n错误: %v\n输出: %s", strings.Join(fullCmd, " "), err, string(output))
}
return strings.TrimSpace(string(output)), nil
}
+125
View File
@@ -5,7 +5,10 @@ package system
import (
"errors"
"fmt"
"net"
"os/exec"
"strconv"
"strings"
)
func enable_proxy(args ProxySettings) error {
@@ -45,6 +48,128 @@ func disable_proxy(args ProxySettings) error {
return nil
}
func fetch_cur_proxy(args ProxySettings) (*ProxySettings, error) {
path := `HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings`
enableValue, err := read_reg_value(path, "ProxyEnable")
if err != nil {
return nil, err
}
if enableValue == "" {
return nil, nil
}
enabled, err := parse_reg_dword(enableValue)
if err != nil {
return nil, err
}
if enabled == 0 {
return nil, nil
}
serverValue, err := read_reg_value(path, "ProxyServer")
if err != nil {
return nil, err
}
if serverValue == "" {
return nil, nil
}
host, port, err := parse_proxy_server_value(serverValue)
if err != nil {
return nil, err
}
if host == "" || port == "" {
return nil, nil
}
return &ProxySettings{
Hostname: host,
Port: port,
}, nil
}
func get_network_interfaces() (*HardwarePort, error) {
return nil, errors.New("not support")
}
func read_reg_value(path string, name string) (string, error) {
cmd := exec.Command("reg", "query", path, "/v", name)
output, err := cmd.CombinedOutput()
if err != nil {
outputText := string(output)
lower := strings.ToLower(outputText)
if strings.Contains(lower, "unable to find") || strings.Contains(outputText, "找不到") || strings.Contains(outputText, "无法找到") {
return "", nil
}
return "", fmt.Errorf("读取系统代理失败,%v", outputText)
}
for _, line := range strings.Split(string(output), "\n") {
if !strings.Contains(line, name) {
continue
}
fields := strings.Fields(line)
if len(fields) < 3 {
continue
}
return fields[len(fields)-1], nil
}
return "", nil
}
func parse_reg_dword(value string) (int64, error) {
num, err := strconv.ParseInt(strings.TrimSpace(value), 0, 64)
if err != nil {
return 0, fmt.Errorf("解析系统代理开关失败: %v", err)
}
return num, nil
}
func parse_proxy_server_value(value string) (string, string, error) {
raw := strings.TrimSpace(value)
if raw == "" {
return "", "", nil
}
parts := strings.Split(raw, ";")
candidate := pick_proxy_candidate(parts, "http=")
if candidate == "" {
candidate = pick_proxy_candidate(parts, "https=")
}
if candidate == "" {
for _, part := range parts {
part = strings.TrimSpace(part)
if idx := strings.Index(part, "="); idx >= 0 {
candidate = strings.TrimSpace(part[idx+1:])
break
}
}
}
if candidate == "" {
candidate = raw
}
return split_host_port(candidate)
}
func pick_proxy_candidate(parts []string, prefix string) string {
for _, part := range parts {
part = strings.TrimSpace(part)
if strings.HasPrefix(strings.ToLower(part), prefix) {
return strings.TrimSpace(part[len(prefix):])
}
}
return ""
}
func split_host_port(value string) (string, string, error) {
candidate := strings.TrimSpace(value)
if candidate == "" {
return "", "", nil
}
if strings.HasPrefix(candidate, "[") {
host, port, err := net.SplitHostPort(candidate)
if err != nil {
return "", "", fmt.Errorf("解析系统代理地址失败: %v", err)
}
return host, port, nil
}
idx := strings.LastIndex(candidate, ":")
if idx <= 0 || idx == len(candidate)-1 {
return "", "", fmt.Errorf("解析系统代理地址失败: %s", candidate)
}
return candidate[:idx], candidate[idx+1:], nil
}