feat: display tip in terminal when system proxy is modified
This commit is contained in:
1 parent
fc3dfd3ada
commit
8e1ceb7b55
5 files changed
+298
No files matched your search
+26
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
Reference in new issue
Block a user