diff --git a/README.md b/README.md index 9ca8e3f..926b810 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # ECS -[![release](https://github.com/oneclickvirt/ecs/actions/workflows/main.yaml/badge.svg)](https://github.com/oneclickvirt/ecs/actions/workflows/main.yaml) [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Foneclickvirt%2Fecs.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Foneclickvirt%2Fecs?ref=badge_shield) +[![release](https://github.com/oneclickvirt/ecs/actions/workflows/main.yaml/badge.svg)](https://github.com/oneclickvirt/ecs/actions/workflows/main.yaml) +[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Foneclickvirt%2Fecs.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Foneclickvirt%2Fecs?ref=badge_shield) [![Hits](https://hits.spiritlhl.net/goecs.svg?action=hit&title=Hits&title_bg=%23555555&count_bg=%230eecf8&edge_flat=false)](https://hits.spiritlhl.net) @@ -138,19 +139,19 @@ Shell 版本:[https://github.com/spiritLHLS/ecs](https://github.com/spiritLHLS export noninteractive=true && ./goecs.sh env ``` -3. **安装 `goecs`** +3. **安装 `goecs` 本体(仅下载二进制文件无依赖安装)** ```bash ./goecs.sh install ``` -4. **升级 `goecs`** +4. **升级 `goecs` 本体** ```bash ./goecs.sh upgrade ``` -5. **卸载 `goecs`** +5. **卸载 `goecs` 本体** ```bash ./goecs.sh uninstall @@ -342,6 +343,7 @@ GOOS=darwin GOARCH=amd64 go build -o goecs_darwin | 测试稳定性 | 核心测试组件10年以上未变 | 每个大版本更新测试项,分数不同版本间难以对比(每个版本对标当前最好的CPU) | | 测试内容 | 仅测试计算性能 | 覆盖多种性能测试,分数加权计算,但部分测试实际不常用 | | 适用场景 | 适合快速测试,仅测试计算性能 | 适合综合全面的测试 | +| 排行榜 | [sysbench.spiritlhl.net](https://sysbench.spiritlhl.net/) | [browser.geekbench.com](https://browser.geekbench.com/) | 且```goecs```测试使用何种CPU测试方式可使用参数指定,默认只是为了更多用户快速测试的需求 diff --git a/disktest/disktest.go b/disktest/disktest.go index eb3329c..b56bde4 100644 --- a/disktest/disktest.go +++ b/disktest/disktest.go @@ -36,6 +36,6 @@ func DiskTest(language, testMethod, testPath string, isMultiCheck bool, autoChan if !strings.Contains(res, "\n") && res != "" { res += "\n" } - fmt.Printf(res) + fmt.Printf("%s", res) //fmt.Println("--------------------------------------------------") } diff --git a/disktest/disktest_test.go b/disktest/disktest_test.go index 16946b3..6e32e67 100644 --- a/disktest/disktest_test.go +++ b/disktest/disktest_test.go @@ -3,5 +3,5 @@ package disktest import "testing" func TestDiskIoTest(t *testing.T) { - DiskTest("zh", "sysbench", "", false) + DiskTest("zh", "sysbench", "", false, false) } diff --git a/go.mod b/go.mod index a64400f..279aa89 100644 --- a/go.mod +++ b/go.mod @@ -8,8 +8,8 @@ require ( github.com/imroc/req/v3 v3.50.0 github.com/oneclickvirt/CommonMediaTests v0.0.4-20250329123841 github.com/oneclickvirt/UnlockTests v0.0.27-20250628125053 - github.com/oneclickvirt/backtrace v0.0.5-20250517095024 - github.com/oneclickvirt/basics v0.0.13-20250628134234 + github.com/oneclickvirt/backtrace v0.0.5-20250629024536 + github.com/oneclickvirt/basics v0.0.13-20250629023612 github.com/oneclickvirt/cputest v0.0.10-20250404151448 github.com/oneclickvirt/defaultset v0.0.2-20240624082446 github.com/oneclickvirt/disktest v0.0.8-20250425015826 @@ -18,7 +18,7 @@ require ( github.com/oneclickvirt/nt3 v0.0.5-20250416131047 github.com/oneclickvirt/pingtest v0.0.7-20250413051539 github.com/oneclickvirt/portchecker v0.0.3-20250329125750 - github.com/oneclickvirt/security v0.0.4-20250522031128 + github.com/oneclickvirt/security v0.0.4-20250629033626 github.com/oneclickvirt/speedtest v0.0.9-20250521034111 ) diff --git a/go.sum b/go.sum index 7531f61..d99e161 100644 --- a/go.sum +++ b/go.sum @@ -101,10 +101,10 @@ github.com/oneclickvirt/CommonMediaTests v0.0.4-20250329123841 h1:Zef93z9UiZQwRA github.com/oneclickvirt/CommonMediaTests v0.0.4-20250329123841/go.mod h1:DAmFPRjFV5p9fEzUUSml5jJGn2f1NZJQCzTxITHDjc4= github.com/oneclickvirt/UnlockTests v0.0.27-20250628125053 h1:Ug8kySZR1weRUcsnGOv+f3HAl791AfkA7EWV3JmiMQA= github.com/oneclickvirt/UnlockTests v0.0.27-20250628125053/go.mod h1:yXWIZB6iLS88pEd9m4QJi1GENn+7I91zA72y5ONz2Oc= -github.com/oneclickvirt/backtrace v0.0.5-20250517095024 h1:j912aga/17znOqMB2VAxWOQYa4GL6YMFBhv+6c7jkvA= -github.com/oneclickvirt/backtrace v0.0.5-20250517095024/go.mod h1:5AH00bo41hH3d2/JVuCTlBkZUs3AXX4nlKVXb6piZcI= -github.com/oneclickvirt/basics v0.0.13-20250628134234 h1:ykbtiheQsN/lPc6z4X6oMYco4ZpDwQZ7z98jWnKi8oU= -github.com/oneclickvirt/basics v0.0.13-20250628134234/go.mod h1:yN1IEOXN6v/GJqJSA70Pooo6nXBI/6rq72vTY72wJMQ= +github.com/oneclickvirt/backtrace v0.0.5-20250629024536 h1:caHCa0DHmbYWBFN1bqKxpvPnN0wOxDEqJv1VDvDdLWs= +github.com/oneclickvirt/backtrace v0.0.5-20250629024536/go.mod h1:5AH00bo41hH3d2/JVuCTlBkZUs3AXX4nlKVXb6piZcI= +github.com/oneclickvirt/basics v0.0.13-20250629023612 h1:cQg+cGBt2NMRrjhJPH+CbevZrwtMU8pIZIY2Lp6zmt4= +github.com/oneclickvirt/basics v0.0.13-20250629023612/go.mod h1:yN1IEOXN6v/GJqJSA70Pooo6nXBI/6rq72vTY72wJMQ= github.com/oneclickvirt/cputest v0.0.10-20250404151448 h1:ovGtCwFXG0qmpyNDRqcNDIiAmhrtemCjIUXTJ1fPH0o= github.com/oneclickvirt/cputest v0.0.10-20250404151448/go.mod h1:MmaHN9+XMntI3rLycwj8Ne31fG18IfNoa8N2utDK1CY= github.com/oneclickvirt/dd v0.0.1-20250406062523 h1:jegTww4fuoFEqwFozvGJEqUNI/5ew3QJ0XcKZZ/zuTs= @@ -125,8 +125,8 @@ github.com/oneclickvirt/pingtest v0.0.7-20250413051539 h1:mYOsEmMtwKr40hwM2NimVL github.com/oneclickvirt/pingtest v0.0.7-20250413051539/go.mod h1:d3Ntx5m9lMll3a/k3+2B+5emj//vgDh4/NHTxs2qQE8= github.com/oneclickvirt/portchecker v0.0.3-20250329125750 h1:TTNL0pnQlRsn046kW59I/9UWRpihttFHWnU7Ixycggk= github.com/oneclickvirt/portchecker v0.0.3-20250329125750/go.mod h1:HQxSTrqM8/QFqHMTBZ7S8H9eEO5FkUXU1eb7ZX5Mk+k= -github.com/oneclickvirt/security v0.0.4-20250522031128 h1:k/zpiES/W0lW6Rumlmo4i7zp2ncimfeOUKadrylde8M= -github.com/oneclickvirt/security v0.0.4-20250522031128/go.mod h1:hdCr9UFkJ0tQfFP4mIycZehF5v7VfzSQwNn2qkY0bGo= +github.com/oneclickvirt/security v0.0.4-20250629033626 h1:DEchQ7WKKz4CzQpMlweoqA993BGncvmp1rL1ICNDJ2g= +github.com/oneclickvirt/security v0.0.4-20250629033626/go.mod h1:/5eVnZLvP7RUjwhoI6d8iIMP7msbkHC5So3ZxM+A7Zg= github.com/oneclickvirt/speedtest v0.0.9-20250521034111 h1:yygDk+s5qFhPMDRzdMfyopm1xU512peNqY6WYyvYcfY= github.com/oneclickvirt/speedtest v0.0.9-20250521034111/go.mod h1:zd5ZgIGslmtQLQehEfRjyumlvgDHTpCSMchKfKXoASI= github.com/onsi/ginkgo/v2 v2.22.1 h1:QW7tbJAUDyVDVOM5dFa7qaybo+CRfR7bemlQUN6Z8aM= diff --git a/goecs.go b/goecs.go index 6f853af..878bc40 100644 --- a/goecs.go +++ b/goecs.go @@ -5,9 +5,19 @@ import ( "context" "flag" "fmt" + "net/http" + "os" + "os/signal" + "regexp" + "runtime" + "strings" + "sync" + "syscall" + "time" + "github.com/oneclickvirt/CommonMediaTests/commediatests" unlocktestmodel "github.com/oneclickvirt/UnlockTests/model" - "github.com/oneclickvirt/backtrace/bk" + backtrace "github.com/oneclickvirt/backtrace/bk" backtracemodel "github.com/oneclickvirt/backtrace/model" basicmodel "github.com/oneclickvirt/basics/model" cputestmodel "github.com/oneclickvirt/cputest/model" @@ -26,19 +36,10 @@ import ( "github.com/oneclickvirt/pingtest/pt" "github.com/oneclickvirt/portchecker/email" speedtestmodel "github.com/oneclickvirt/speedtest/model" - "net/http" - "os" - "os/signal" - "regexp" - "runtime" - "strings" - "sync" - "syscall" - "time" ) var ( - ecsVersion = "v0.1.37" + ecsVersion = "v0.1.38" menuMode bool onlyChinaTest bool input, choice string @@ -79,7 +80,6 @@ func getMenuChoice(language string) string { return } }() - for { go func() { var input string @@ -95,7 +95,7 @@ func getMenuChoice(language string) string { }() select { case input := <-inputChan: - re := regexp.MustCompile(`^\d+$`) // 正则表达式匹配纯数字 + re := regexp.MustCompile(`^\d+$`) if re.MatchString(input) { inChoice := input switch inChoice { @@ -121,7 +121,7 @@ func getMenuChoice(language string) string { } } -func main() { +func parseFlags() { goecsFlag.BoolVar(&help, "h", false, "Show help information") goecsFlag.BoolVar(&showVersion, "v", false, "Display version information") goecsFlag.BoolVar(&menuMode, "menu", true, "Enable/Disable menu mode, disable example: -menu=false") // true 默认启用菜单栏模式 @@ -149,15 +149,22 @@ func main() { goecsFlag.BoolVar(&enableLogger, "log", false, "Enable/Disable logging in the current path") goecsFlag.BoolVar(&enabelUpload, "upload", true, "Enable/Disable upload the result") goecsFlag.Parse(os.Args[1:]) +} + +func handleHelpAndVersion() bool { if help { fmt.Printf("Usage: %s [options]\n", os.Args[0]) goecsFlag.PrintDefaults() - return + return true } if showVersion { fmt.Println(ecsVersion) - return + return true } + return false +} + +func initLogger() { if enableLogger { gostunmodel.EnableLoger = true basicmodel.EnableLoger = true @@ -171,129 +178,206 @@ func main() { nt3model.EnableLoger = true speedtestmodel.EnableLoger = true } - go func() { - http.Get("https://hits.spiritlhl.net/goecs.svg?action=hit&title=Hits&title_bg=%23555555&count_bg=%230eecf8&edge_flat=false") - }() - if menuMode { - basicStatus, cpuTestStatus, memoryTestStatus, diskTestStatus = false, false, false, false - commTestStatus, utTestStatus, securityTestStatus, emailTestStatus = false, false, false, false - backtraceStatus, nt3Status, speedTestStatus = false, false, false - autoChangeDiskTestMethod = true - switch language { - case "zh": - fmt.Println("VPS融合怪版本: ", ecsVersion) - fmt.Println("1. 融合怪完全体") - fmt.Println("2. 极简版(系统信息+CPU+内存+磁盘+测速节点5个)") - fmt.Println("3. 精简版(系统信息+CPU+内存+磁盘+常用流媒体+路由+测速节点5个)") - fmt.Println("4. 精简网络版(系统信息+CPU+内存+磁盘+回程+路由+测速节点5个)") - fmt.Println("5. 精简解锁版(系统信息+CPU+内存+磁盘IO+御三家+常用流媒体+测速节点5个)") - fmt.Println("6. 网络单项(IP质量检测+三网回程+三网路由与延迟+测速节点11个)") - fmt.Println("7. 解锁单项(御三家解锁+常用流媒体解锁)") - fmt.Println("8. 硬件单项(系统信息+CPU+内存+dd磁盘测试+fio磁盘测试)") - fmt.Println("9. IP质量检测(15个数据库的IP检测+邮件端口检测)") - fmt.Println("10. 三网回程线路+广州三网路由+全国三网延迟") - case "en": - fmt.Println("VPS Fusion Monster Test Version: ", ecsVersion) - fmt.Println("1. VPS Fusion Monster Test Comprehensive Test Suite") - fmt.Println("2. Minimal Test Suite (System Info + CPU + Memory + Disk + 5 Speed Test Nodes)") - fmt.Println("3. Standard Test Suite (System Info + CPU + Memory + Disk + Basic Unlock Tests + 5 Speed Test Nodes)") - fmt.Println("4. Network-Focused Test Suite (System Info + CPU + Memory + Disk + 5 Speed Test Nodes)") - fmt.Println("5. Unlock-Focused Test Suite (System Info + CPU + Memory + Disk IO + Basic Unlock Tests + Common Streaming Services + 5 Speed Test Nodes)") - fmt.Println("6. Network-Only Test (IP Quality Test + 5 Speed Test Nodes)") - fmt.Println("7. Unlock-Only Test (Basic Unlock Tests + Common Streaming Services Unlock)") - fmt.Println("8. Hardware-Only Test (System Info + CPU + Memory + dd Disk Test + fio Disk Test)") - fmt.Println("9. IP Quality Test (IP Test with 15 Databases + Email Port Test)") - } - Loop: - for { - choice = getMenuChoice(language) - switch choice { - case "1": - basicStatus = true - cpuTestStatus = true - memoryTestStatus = true - diskTestStatus = true - commTestStatus = true - utTestStatus = true - securityTestStatus = true - emailTestStatus = true - backtraceStatus = true - nt3Status = true - speedTestStatus = true - onlyChinaTest = utils.CheckChina(enableLogger) - break Loop - case "2": - basicStatus = true - cpuTestStatus = true - memoryTestStatus = true - diskTestStatus = true - speedTestStatus = true - break Loop - case "3": - basicStatus = true - cpuTestStatus = true - memoryTestStatus = true - diskTestStatus = true - utTestStatus = true - nt3Status = true - speedTestStatus = true - break Loop - case "4": - basicStatus = true - cpuTestStatus = true - memoryTestStatus = true - diskTestStatus = true - backtraceStatus = true - nt3Status = true - speedTestStatus = true - break Loop - case "5": - basicStatus = true - cpuTestStatus = true - memoryTestStatus = true - diskTestStatus = true - commTestStatus = true - utTestStatus = true - speedTestStatus = true - break Loop - case "6": - securityTestStatus = true - speedTestStatus = true - backtraceStatus = true - nt3Status = true - break Loop - case "7": - commTestStatus = true - utTestStatus = true - enabelUpload = false - break Loop - case "8": - basicStatus = true - cpuTestStatus = true - memoryTestStatus = true - diskTestStatus = true - securityTestStatus = false - autoChangeDiskTestMethod = false - break Loop - case "9": - securityTestStatus = true - emailTestStatus = true - break Loop - case "10": - backtraceStatus = true - nt3Status = true - pingTestStatus = true - enabelUpload = false - break Loop - default: - if language == "zh" { - fmt.Println("无效的选项") - } else { - fmt.Println("Invalid choice") - } +} + +func handleMenuMode(preCheck utils.NetCheckResult) { + basicStatus, cpuTestStatus, memoryTestStatus, diskTestStatus = false, false, false, false + commTestStatus, utTestStatus, securityTestStatus, emailTestStatus = false, false, false, false + backtraceStatus, nt3Status, speedTestStatus = false, false, false + autoChangeDiskTestMethod = true + printMenuOptions() +Loop: + for { + choice = getMenuChoice(language) + switch choice { + case "1": + setFullTestStatus(preCheck) + onlyChinaTest = utils.CheckChina(enableLogger) + break Loop + case "2": + setMinimalTestStatus(preCheck) + break Loop + case "3": + setStandardTestStatus(preCheck) + break Loop + case "4": + setNetworkFocusedTestStatus(preCheck) + break Loop + case "5": + setUnlockFocusedTestStatus(preCheck) + break Loop + case "6": + if !preCheck.Connected { + fmt.Println("Can not test without network connection!") + return } + setNetworkOnlyTestStatus() + break Loop + case "7": + if !preCheck.Connected { + fmt.Println("Can not test without network connection!") + return + } + setUnlockOnlyTestStatus() + break Loop + case "8": + setHardwareOnlyTestStatus(preCheck) + break Loop + case "9": + if !preCheck.Connected { + fmt.Println("Can not test without network connection!") + return + } + setIPQualityTestStatus() + break Loop + case "10": + if !preCheck.Connected { + fmt.Println("Can not test without network connection!") + return + } + setRouteTestStatus() + break Loop + default: + printInvalidChoice() } } +} + +func printMenuOptions() { + switch language { + case "zh": + fmt.Println("VPS融合怪版本: ", ecsVersion) + fmt.Println("1. 融合怪完全体") + fmt.Println("2. 极简版(系统信息+CPU+内存+磁盘+测速节点5个)") + fmt.Println("3. 精简版(系统信息+CPU+内存+磁盘+常用流媒体+路由+测速节点5个)") + fmt.Println("4. 精简网络版(系统信息+CPU+内存+磁盘+回程+路由+测速节点5个)") + fmt.Println("5. 精简解锁版(系统信息+CPU+内存+磁盘IO+御三家+常用流媒体+测速节点5个)") + fmt.Println("6. 网络单项(IP质量检测+三网回程+三网路由与延迟+测速节点11个)") + fmt.Println("7. 解锁单项(御三家解锁+常用流媒体解锁)") + fmt.Println("8. 硬件单项(系统信息+CPU+内存+dd磁盘测试+fio磁盘测试)") + fmt.Println("9. IP质量检测(15个数据库的IP检测+邮件端口检测)") + fmt.Println("10. 三网回程线路+广州三网路由+全国三网延迟") + case "en": + fmt.Println("VPS Fusion Monster Test Version: ", ecsVersion) + fmt.Println("1. VPS Fusion Monster Test Comprehensive Test Suite") + fmt.Println("2. Minimal Test Suite (System Info + CPU + Memory + Disk + 5 Speed Test Nodes)") + fmt.Println("3. Standard Test Suite (System Info + CPU + Memory + Disk + Basic Unlock Tests + 5 Speed Test Nodes)") + fmt.Println("4. Network-Focused Test Suite (System Info + CPU + Memory + Disk + 5 Speed Test Nodes)") + fmt.Println("5. Unlock-Focused Test Suite (System Info + CPU + Memory + Disk IO + Basic Unlock Tests + Common Streaming Services + 5 Speed Test Nodes)") + fmt.Println("6. Network-Only Test (IP Quality Test + 5 Speed Test Nodes)") + fmt.Println("7. Unlock-Only Test (Basic Unlock Tests + Common Streaming Services Unlock)") + fmt.Println("8. Hardware-Only Test (System Info + CPU + Memory + dd Disk Test + fio Disk Test)") + fmt.Println("9. IP Quality Test (IP Test with 15 Databases + Email Port Test)") + } +} + +func setFullTestStatus(preCheck utils.NetCheckResult) { + basicStatus = true + cpuTestStatus = true + memoryTestStatus = true + diskTestStatus = true + if preCheck.Connected { + commTestStatus = true + utTestStatus = true + securityTestStatus = true + emailTestStatus = true + backtraceStatus = true + nt3Status = true + speedTestStatus = true + } +} + +func setMinimalTestStatus(preCheck utils.NetCheckResult) { + basicStatus = true + cpuTestStatus = true + memoryTestStatus = true + diskTestStatus = true + if preCheck.Connected { + speedTestStatus = true + } +} + +func setStandardTestStatus(preCheck utils.NetCheckResult) { + basicStatus = true + cpuTestStatus = true + memoryTestStatus = true + diskTestStatus = true + if preCheck.Connected { + utTestStatus = true + nt3Status = true + speedTestStatus = true + } +} + +func setNetworkFocusedTestStatus(preCheck utils.NetCheckResult) { + basicStatus = true + cpuTestStatus = true + memoryTestStatus = true + diskTestStatus = true + if preCheck.Connected { + backtraceStatus = true + nt3Status = true + speedTestStatus = true + } +} + +func setUnlockFocusedTestStatus(preCheck utils.NetCheckResult) { + basicStatus = true + cpuTestStatus = true + memoryTestStatus = true + diskTestStatus = true + if preCheck.Connected { + commTestStatus = true + utTestStatus = true + speedTestStatus = true + } +} + +func setNetworkOnlyTestStatus() { + securityTestStatus = true + speedTestStatus = true + backtraceStatus = true + nt3Status = true +} + +func setUnlockOnlyTestStatus() { + commTestStatus = true + utTestStatus = true + enabelUpload = false +} + +func setHardwareOnlyTestStatus(preCheck utils.NetCheckResult) { + basicStatus = true + cpuTestStatus = true + memoryTestStatus = true + diskTestStatus = true + if preCheck.Connected { + securityTestStatus = false + autoChangeDiskTestMethod = false + } +} + +func setIPQualityTestStatus() { + securityTestStatus = true + emailTestStatus = true +} + +func setRouteTestStatus() { + backtraceStatus = true + nt3Status = true + pingTestStatus = true + enabelUpload = false +} + +func printInvalidChoice() { + if language == "zh" { + fmt.Println("无效的选项") + } else { + fmt.Println("Invalid choice") + } +} + +func handleLanguageSpecificSettings() { if language == "en" { backtraceStatus = false nt3Status = false @@ -301,325 +385,346 @@ func main() { if !enabelUpload { securityTestStatus = false } - var ( - startTime time.Time - wg1, wg2, wg3 sync.WaitGroup - basicInfo, securityInfo, emailInfo, mediaInfo, ptInfo string - output, tempOutput string - ) - // 信号处理部分 - uploadDone := make(chan bool, 1) - sig := make(chan os.Signal, 1) - signal.Notify(sig, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) - // 启动一个goroutine来等待信号 - go func() { - startTime = time.Now() - select { - case <-sig: - if !finish { - endTime := time.Now() - duration := endTime.Sub(startTime) - minutes := int(duration.Minutes()) - seconds := int(duration.Seconds()) % 60 - currentTime := time.Now().Format("Mon Jan 2 15:04:05 MST 2006") - var mu sync.Mutex - mu.Lock() - output = utils.PrintAndCapture(func() { - utils.PrintCenteredTitle("", width) - fmt.Printf("Cost Time : %d min %d sec\n", minutes, seconds) - fmt.Printf("Current Time : %s\n", currentTime) - utils.PrintCenteredTitle("", width) - }, tempOutput, output) - mu.Unlock() - // 创建一个通道来传递上传结果 - resultChan := make(chan struct { +} + +func handleSignalInterrupt(sig chan os.Signal, startTime *time.Time, output *string, tempOutput string, uploadDone chan bool) { + *startTime = time.Now() + select { + case <-sig: + if !finish { + endTime := time.Now() + duration := endTime.Sub(*startTime) + minutes := int(duration.Minutes()) + seconds := int(duration.Seconds()) % 60 + currentTime := time.Now().Format("Mon Jan 2 15:04:05 MST 2006") + var mu sync.Mutex + mu.Lock() + *output = utils.PrintAndCapture(func() { + utils.PrintCenteredTitle("", width) + fmt.Printf("Cost Time : %d min %d sec\n", minutes, seconds) + fmt.Printf("Current Time : %s\n", currentTime) + utils.PrintCenteredTitle("", width) + }, tempOutput, *output) + mu.Unlock() + resultChan := make(chan struct { + httpURL string + httpsURL string + }, 1) + go func() { + httpURL, httpsURL := utils.ProcessAndUpload(*output, filePath, enabelUpload) + resultChan <- struct { httpURL string httpsURL string - }, 1) // 使用带缓冲的通道,避免可能的阻塞 - // 启动上传 - go func() { - httpURL, httpsURL := utils.ProcessAndUpload(output, filePath, enabelUpload) - resultChan <- struct { - httpURL string - httpsURL string - }{httpURL, httpsURL} - uploadDone <- true - }() - // 等待上传完成或超时 - select { - case result := <-resultChan: - if result.httpURL != "" || result.httpsURL != "" { - if language == "en" { - fmt.Printf("Upload successfully!\nHttp URL: %s\nHttps URL: %s\n", result.httpURL, result.httpsURL) - } else { - fmt.Printf("上传成功!\nHttp URL: %s\nHttps URL: %s\n", result.httpURL, result.httpsURL) - } + }{httpURL, httpsURL} + uploadDone <- true + }() + select { + case result := <-resultChan: + if result.httpURL != "" || result.httpsURL != "" { + if language == "en" { + fmt.Printf("Upload successfully!\nHttp URL: %s\nHttps URL: %s\n", result.httpURL, result.httpsURL) + } else { + fmt.Printf("上传成功!\nHttp URL: %s\nHttps URL: %s\n", result.httpURL, result.httpsURL) } - // 给打印操作一些时间完成 - time.Sleep(100 * time.Millisecond) - if runtime.GOOS == "windows" || runtime.GOOS == "darwin" { - fmt.Println("Press Enter to exit...") - fmt.Scanln() - } - os.Exit(0) - case <-time.After(30 * time.Second): - fmt.Println("上传超时,程序退出") - if runtime.GOOS == "windows" || runtime.GOOS == "darwin" { - fmt.Println("Press Enter to exit...") - fmt.Scanln() - } - os.Exit(1) } + time.Sleep(100 * time.Millisecond) + if runtime.GOOS == "windows" || runtime.GOOS == "darwin" { + fmt.Println("Press Enter to exit...") + fmt.Scanln() + } + os.Exit(0) + case <-time.After(30 * time.Second): + fmt.Println("上传超时,程序退出") + if runtime.GOOS == "windows" || runtime.GOOS == "darwin" { + fmt.Println("Press Enter to exit...") + fmt.Scanln() + } + os.Exit(1) } - os.Exit(0) } - }() - switch language { - case "zh": - output = utils.PrintAndCapture(func() { - utils.PrintHead(language, width, ecsVersion) - if basicStatus || securityTestStatus { - if basicStatus { - utils.PrintCenteredTitle("系统基础信息", width) - } - basicInfo, securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, nt3CheckType, securityTestStatus) - if basicStatus { - fmt.Printf(basicInfo) - } else if (input == "6" || input == "9") && securityTestStatus { - scanner := bufio.NewScanner(strings.NewReader(basicInfo)) - for scanner.Scan() { - line := scanner.Text() - if strings.Contains(line, "IPV") { - fmt.Println(line) - } - } - } - } - }, tempOutput, output) - output = utils.PrintAndCapture(func() { - if cpuTestStatus { - utils.PrintCenteredTitle(fmt.Sprintf("CPU测试-通过%s测试", cpuTestMethod), width) - cputest.CpuTest(language, cpuTestMethod, cpuTestThreadMode) - } - }, tempOutput, output) - output = utils.PrintAndCapture(func() { - if memoryTestStatus { - utils.PrintCenteredTitle(fmt.Sprintf("内存测试-通过%s测试", memoryTestMethod), width) - memorytest.MemoryTest(language, memoryTestMethod) - } - }, tempOutput, output) - output = utils.PrintAndCapture(func() { - if diskTestStatus && autoChangeDiskTestMethod { - utils.PrintCenteredTitle(fmt.Sprintf("硬盘测试-通过%s测试", diskTestMethod), width) - disktest.DiskTest(language, diskTestMethod, diskTestPath, diskMultiCheck, autoChangeDiskTestMethod) - } else if diskTestStatus && !autoChangeDiskTestMethod { - utils.PrintCenteredTitle(fmt.Sprintf("硬盘测试-通过%s测试", "dd"), width) - disktest.DiskTest(language, "dd", diskTestPath, diskMultiCheck, autoChangeDiskTestMethod) - utils.PrintCenteredTitle(fmt.Sprintf("硬盘测试-通过%s测试", "fio"), width) - disktest.DiskTest(language, "fio", diskTestPath, diskMultiCheck, autoChangeDiskTestMethod) - } - }, tempOutput, output) - if onlyChinaTest || pingTestStatus { - wg3.Add(1) + os.Exit(0) + } +} + +func runChineseTests(preCheck utils.NetCheckResult, wg1, wg2, wg3 *sync.WaitGroup, basicInfo, securityInfo, emailInfo, mediaInfo, ptInfo *string, output, tempOutput string, startTime time.Time) string { + output = runBasicTests(preCheck, basicInfo, securityInfo, output, tempOutput) + output = runCPUTest(output, tempOutput) + output = runMemoryTest(output, tempOutput) + output = runDiskTest(output, tempOutput) + if (onlyChinaTest || pingTestStatus) && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" { + wg3.Add(1) + go func() { + defer wg3.Done() + *ptInfo = pt.PingTest() + }() + } + if emailTestStatus { + wg2.Add(1) + go func() { + defer wg2.Done() + *emailInfo = email.EmailCheck() + }() + } + if utTestStatus && !onlyChinaTest { + wg1.Add(1) + go func() { + defer wg1.Done() + *mediaInfo = unlocktest.MediaTest(language) + }() + } + if preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" { + output = runStreamingTests(wg1, *mediaInfo, output, tempOutput) + output = runSecurityTests(*securityInfo, output, tempOutput) + output = runEmailTests(wg2, *emailInfo, output, tempOutput) + } + if runtime.GOOS != "windows" && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" { + output = runNetworkTests(wg3, *ptInfo, output, tempOutput) + } + if preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" { + output = runSpeedTests(output, tempOutput) + } + return appendTimeInfo(output, tempOutput, startTime) +} + +func runEnglishTests(preCheck utils.NetCheckResult, wg1, wg2 *sync.WaitGroup, basicInfo, securityInfo, emailInfo, mediaInfo *string, output, tempOutput string, startTime time.Time) string { + output = runBasicTests(preCheck, basicInfo, securityInfo, output, tempOutput) + output = runCPUTest(output, tempOutput) + output = runMemoryTest(output, tempOutput) + output = runDiskTest(output, tempOutput) + if preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" { + if utTestStatus { + wg1.Add(1) go func() { - defer wg3.Done() - ptInfo = pt.PingTest() + defer wg1.Done() + *mediaInfo = unlocktest.MediaTest(language) }() } if emailTestStatus { wg2.Add(1) go func() { defer wg2.Done() - emailInfo = email.EmailCheck() + *emailInfo = email.EmailCheck() }() } - if utTestStatus && !onlyChinaTest { - wg1.Add(1) - go func() { - defer wg1.Done() - mediaInfo = unlocktest.MediaTest(language) - }() - } - output = utils.PrintAndCapture(func() { - if commTestStatus && !onlyChinaTest { - utils.PrintCenteredTitle("御三家流媒体解锁", width) - fmt.Printf(commediatests.MediaTests(language)) - } - }, tempOutput, output) - output = utils.PrintAndCapture(func() { - if utTestStatus && !onlyChinaTest { - utils.PrintCenteredTitle("跨国流媒体解锁", width) - wg1.Wait() - fmt.Printf(mediaInfo) - } - }, tempOutput, output) - output = utils.PrintAndCapture(func() { - if securityTestStatus { - utils.PrintCenteredTitle("IP质量检测", width) - fmt.Printf(securityInfo) - } - }, tempOutput, output) - output = utils.PrintAndCapture(func() { - if emailTestStatus { - utils.PrintCenteredTitle("邮件端口检测", width) - wg2.Wait() - fmt.Println(emailInfo) - } - }, tempOutput, output) - if runtime.GOOS != "windows" { - output = utils.PrintAndCapture(func() { - if backtraceStatus && !onlyChinaTest { - utils.PrintCenteredTitle("三网回程线路检测", width) - if strings.Contains(output, "IPV6") { - backtrace.BackTrace(true) - } else { - backtrace.BackTrace(false) - } - } - }, tempOutput, output) - // nexttrace 在win上不支持检测,报错 bind: An invalid argument was supplied. - output = utils.PrintAndCapture(func() { - if nt3Status && !onlyChinaTest { - utils.PrintCenteredTitle("三网回程路由检测", width) - nt.TraceRoute(language, nt3Location, nt3CheckType) - } - }, tempOutput, output) - output = utils.PrintAndCapture(func() { - if onlyChinaTest || pingTestStatus { - utils.PrintCenteredTitle("三网ICMP的PING值检测", width) - wg3.Wait() - fmt.Println(ptInfo) - } - }, tempOutput, output) - } - output = utils.PrintAndCapture(func() { - if speedTestStatus { - utils.PrintCenteredTitle("就近节点测速", width) - speedtest.ShowHead(language) - if choice == "1" || !menuMode { - speedtest.NearbySP() - speedtest.CustomSP("net", "global", 2, language) - speedtest.CustomSP("net", "cu", spNum, language) - speedtest.CustomSP("net", "ct", spNum, language) - speedtest.CustomSP("net", "cmcc", spNum, language) - } else if choice == "2" || choice == "3" || choice == "4" || choice == "5" { - speedtest.CustomSP("net", "global", 4, language) - } else if choice == "6" { - speedtest.CustomSP("net", "global", 11, language) - } - } - }, tempOutput, output) - endTime := time.Now() - duration := endTime.Sub(startTime) - minutes := int(duration.Minutes()) - seconds := int(duration.Seconds()) % 60 - currentTime := time.Now().Format("Mon Jan 2 15:04:05 MST 2006") - output = utils.PrintAndCapture(func() { - utils.PrintCenteredTitle("", width) - fmt.Printf("花费 : %d 分 %d 秒\n", minutes, seconds) - fmt.Printf("时间 : %s\n", currentTime) - utils.PrintCenteredTitle("", width) - }, tempOutput, output) - case "en": - output = utils.PrintAndCapture(func() { - utils.PrintHead(language, width, ecsVersion) - if basicStatus || securityTestStatus { - if basicStatus { + output = runStreamingTests(wg1, *mediaInfo, output, tempOutput) + output = runSecurityTests(*securityInfo, output, tempOutput) + output = runEmailTests(wg2, *emailInfo, output, tempOutput) + output = runEnglishSpeedTests(output, tempOutput) + } + return appendTimeInfo(output, tempOutput, startTime) +} + +func runBasicTests(preCheck utils.NetCheckResult, basicInfo, securityInfo *string, output, tempOutput string) string { + return utils.PrintAndCapture(func() { + utils.PrintHead(language, width, ecsVersion) + if basicStatus || securityTestStatus { + if basicStatus { + if language == "zh" { + utils.PrintCenteredTitle("系统基础信息", width) + } else { utils.PrintCenteredTitle("System-Basic-Information", width) } - basicInfo, securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, nt3CheckType, securityTestStatus) - if basicStatus { - fmt.Printf(basicInfo) - } else if (input == "6" || input == "9") && securityTestStatus { - scanner := bufio.NewScanner(strings.NewReader(basicInfo)) - for scanner.Scan() { - line := scanner.Text() - if strings.Contains(line, "IPV") { - fmt.Println(line) - } + } + if preCheck.Connected && preCheck.StackType == "DualStack" { + *basicInfo, *securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, nt3CheckType, securityTestStatus) + } else if preCheck.Connected && preCheck.StackType == "IPv4" { + *basicInfo, *securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, "ipv4", securityTestStatus) + } else if preCheck.Connected && preCheck.StackType == "IPv6" { + *basicInfo, *securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, "ipv6", securityTestStatus) + } else { + *basicInfo, *securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, "", false) + securityTestStatus = false + } + if basicStatus { + fmt.Printf("%s", *basicInfo) + } else if (input == "6" || input == "9") && securityTestStatus { + scanner := bufio.NewScanner(strings.NewReader(*basicInfo)) + for scanner.Scan() { + line := scanner.Text() + if strings.Contains(line, "IPV") { + fmt.Println(line) } } } - }, tempOutput, output) - output = utils.PrintAndCapture(func() { - if cpuTestStatus { + } + }, tempOutput, output) +} + +func runCPUTest(output, tempOutput string) string { + return utils.PrintAndCapture(func() { + if cpuTestStatus { + if language == "zh" { + utils.PrintCenteredTitle(fmt.Sprintf("CPU测试-通过%s测试", cpuTestMethod), width) + } else { utils.PrintCenteredTitle(fmt.Sprintf("CPU-Test--%s-Method", cpuTestMethod), width) - cputest.CpuTest(language, cpuTestMethod, cpuTestThreadMode) } - }, tempOutput, output) - output = utils.PrintAndCapture(func() { - if memoryTestStatus { + cputest.CpuTest(language, cpuTestMethod, cpuTestThreadMode) + } + }, tempOutput, output) +} + +func runMemoryTest(output, tempOutput string) string { + return utils.PrintAndCapture(func() { + if memoryTestStatus { + if language == "zh" { + utils.PrintCenteredTitle(fmt.Sprintf("内存测试-通过%s测试", memoryTestMethod), width) + } else { utils.PrintCenteredTitle(fmt.Sprintf("Memory-Test--%s-Method", memoryTestMethod), width) - memorytest.MemoryTest(language, memoryTestMethod) } - }, tempOutput, output) - output = utils.PrintAndCapture(func() { - if diskTestStatus && autoChangeDiskTestMethod { + memorytest.MemoryTest(language, memoryTestMethod) + } + }, tempOutput, output) +} + +func runDiskTest(output, tempOutput string) string { + return utils.PrintAndCapture(func() { + if diskTestStatus && autoChangeDiskTestMethod { + if language == "zh" { + utils.PrintCenteredTitle(fmt.Sprintf("硬盘测试-通过%s测试", diskTestMethod), width) + } else { utils.PrintCenteredTitle(fmt.Sprintf("Disk-Test--%s-Method", diskTestMethod), width) - disktest.DiskTest(language, diskTestMethod, diskTestPath, diskMultiCheck, autoChangeDiskTestMethod) - } else if diskTestStatus && !autoChangeDiskTestMethod { + } + disktest.DiskTest(language, diskTestMethod, diskTestPath, diskMultiCheck, autoChangeDiskTestMethod) + } else if diskTestStatus && !autoChangeDiskTestMethod { + if language == "zh" { + utils.PrintCenteredTitle(fmt.Sprintf("硬盘测试-通过%s测试", "dd"), width) + disktest.DiskTest(language, "dd", diskTestPath, diskMultiCheck, autoChangeDiskTestMethod) + utils.PrintCenteredTitle(fmt.Sprintf("硬盘测试-通过%s测试", "fio"), width) + disktest.DiskTest(language, "fio", diskTestPath, diskMultiCheck, autoChangeDiskTestMethod) + } else { utils.PrintCenteredTitle(fmt.Sprintf("Disk-Test--%s-Method", "dd"), width) disktest.DiskTest(language, "dd", diskTestPath, diskMultiCheck, autoChangeDiskTestMethod) utils.PrintCenteredTitle(fmt.Sprintf("Disk-Test--%s-Method", "fio"), width) disktest.DiskTest(language, "fio", diskTestPath, diskMultiCheck, autoChangeDiskTestMethod) } - }, tempOutput, output) - if utTestStatus { - wg1.Add(1) - go func() { - defer wg1.Done() - mediaInfo = unlocktest.MediaTest(language) - }() } - if emailTestStatus { - wg2.Add(1) - go func() { - defer wg2.Done() - emailInfo = email.EmailCheck() - }() + }, tempOutput, output) +} + +func runStreamingTests(wg1 *sync.WaitGroup, mediaInfo string, output, tempOutput string) string { + return utils.PrintAndCapture(func() { + if language == "zh" { + if commTestStatus && !onlyChinaTest { + utils.PrintCenteredTitle("御三家流媒体解锁", width) + fmt.Printf("%s", commediatests.MediaTests(language)) + } } - output = utils.PrintAndCapture(func() { - if utTestStatus { + if utTestStatus && (language == "zh" && !onlyChinaTest || language == "en") { + if language == "zh" { + utils.PrintCenteredTitle("跨国流媒体解锁", width) + } else { utils.PrintCenteredTitle("Cross-Border-Streaming-Media-Unlock", width) - wg1.Wait() - fmt.Printf(mediaInfo) } - }, tempOutput, output) - output = utils.PrintAndCapture(func() { - if securityTestStatus { + wg1.Wait() + fmt.Printf("%s", mediaInfo) + } + }, tempOutput, output) +} + +func runSecurityTests(securityInfo string, output, tempOutput string) string { + return utils.PrintAndCapture(func() { + if securityTestStatus { + if language == "zh" { + utils.PrintCenteredTitle("IP质量检测", width) + } else { utils.PrintCenteredTitle("IP-Quality-Check", width) - fmt.Printf(securityInfo) } - }, tempOutput, output) - output = utils.PrintAndCapture(func() { - if emailTestStatus { + fmt.Printf("%s", securityInfo) + } + }, tempOutput, output) +} + +func runEmailTests(wg2 *sync.WaitGroup, emailInfo string, output, tempOutput string) string { + return utils.PrintAndCapture(func() { + if emailTestStatus { + if language == "zh" { + utils.PrintCenteredTitle("邮件端口检测", width) + } else { utils.PrintCenteredTitle("Email-Port-Check", width) - wg2.Wait() - fmt.Println(emailInfo) } - }, tempOutput, output) - output = utils.PrintAndCapture(func() { - if speedTestStatus { - utils.PrintCenteredTitle("Speed-Test", width) - speedtest.ShowHead(language) + wg2.Wait() + fmt.Println(emailInfo) + } + }, tempOutput, output) +} + +func runNetworkTests(wg3 *sync.WaitGroup, ptInfo string, output, tempOutput string) string { + output = utils.PrintAndCapture(func() { + if backtraceStatus && !onlyChinaTest { + utils.PrintCenteredTitle("三网回程线路检测", width) + if strings.Contains(output, "IPV6") { + backtrace.BackTrace(true) + } else { + backtrace.BackTrace(false) + } + } + }, tempOutput, output) + output = utils.PrintAndCapture(func() { + if nt3Status && !onlyChinaTest { + utils.PrintCenteredTitle("三网回程路由检测", width) + nt.TraceRoute(language, nt3Location, nt3CheckType) + } + }, tempOutput, output) + return utils.PrintAndCapture(func() { + if onlyChinaTest || pingTestStatus { + utils.PrintCenteredTitle("三网ICMP的PING值检测", width) + wg3.Wait() + fmt.Println(ptInfo) + } + }, tempOutput, output) +} + +func runSpeedTests(output, tempOutput string) string { + return utils.PrintAndCapture(func() { + if speedTestStatus { + utils.PrintCenteredTitle("就近节点测速", width) + speedtest.ShowHead(language) + if choice == "1" || !menuMode { speedtest.NearbySP() - speedtest.CustomSP("net", "global", -1, language) + speedtest.CustomSP("net", "global", 2, language) + speedtest.CustomSP("net", "cu", spNum, language) + speedtest.CustomSP("net", "ct", spNum, language) + speedtest.CustomSP("net", "cmcc", spNum, language) + } else if choice == "2" || choice == "3" || choice == "4" || choice == "5" { + speedtest.CustomSP("net", "global", 4, language) + } else if choice == "6" { + speedtest.CustomSP("net", "global", 11, language) } - }, tempOutput, output) - endTime := time.Now() - duration := endTime.Sub(startTime) - minutes := int(duration.Minutes()) - seconds := int(duration.Seconds()) % 60 - currentTime := time.Now().Format("Mon Jan 2 15:04:05 MST 2006") - output = utils.PrintAndCapture(func() { - utils.PrintCenteredTitle("", width) + } + }, tempOutput, output) +} + +func runEnglishSpeedTests(output, tempOutput string) string { + return utils.PrintAndCapture(func() { + if speedTestStatus { + utils.PrintCenteredTitle("Speed-Test", width) + speedtest.ShowHead(language) + speedtest.NearbySP() + speedtest.CustomSP("net", "global", -1, language) + } + }, tempOutput, output) +} + +func appendTimeInfo(output, tempOutput string, startTime time.Time) string { + endTime := time.Now() + duration := endTime.Sub(startTime) + minutes := int(duration.Minutes()) + seconds := int(duration.Seconds()) % 60 + currentTime := time.Now().Format("Mon Jan 2 15:04:05 MST 2006") + return utils.PrintAndCapture(func() { + utils.PrintCenteredTitle("", width) + if language == "zh" { + fmt.Printf("花费 : %d 分 %d 秒\n", minutes, seconds) + fmt.Printf("时间 : %s\n", currentTime) + } else { fmt.Printf("Cost Time : %d min %d sec\n", minutes, seconds) fmt.Printf("Current Time : %s\n", currentTime) - utils.PrintCenteredTitle("", width) - }, tempOutput, output) - default: - fmt.Println("Unsupported language") - } + } + utils.PrintCenteredTitle("", width) + }, tempOutput, output) +} + +func handleUploadResults(output string) { httpURL, httpsURL := utils.ProcessAndUpload(output, filePath, enabelUpload) if httpURL != "" || httpsURL != "" { if language == "en" { @@ -628,6 +733,42 @@ func main() { fmt.Printf("上传成功!\nHttp URL: %s\nHttps URL: %s\n", httpURL, httpsURL) } } +} + +func main() { + parseFlags() + if handleHelpAndVersion() { + return + } + initLogger() + go func() { + http.Get("https://hits.spiritlhl.net/goecs.svg?action=hit&title=Hits&title_bg=%23555555&count_bg=%230eecf8&edge_flat=false") + }() + preCheck := utils.CheckPublicAccess(3 * time.Second) + if menuMode { + handleMenuMode(preCheck) + } + handleLanguageSpecificSettings() + var ( + startTime time.Time + wg1, wg2, wg3 sync.WaitGroup + basicInfo, securityInfo, emailInfo, mediaInfo, ptInfo string + output, tempOutput string + ) + uploadDone := make(chan bool, 1) + sig := make(chan os.Signal, 1) + signal.Notify(sig, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) + go handleSignalInterrupt(sig, &startTime, &output, tempOutput, uploadDone) + startTime = time.Now() + switch language { + case "zh": + output = runChineseTests(preCheck, &wg1, &wg2, &wg3, &basicInfo, &securityInfo, &emailInfo, &mediaInfo, &ptInfo, output, tempOutput, startTime) + case "en": + output = runEnglishTests(preCheck, &wg1, &wg2, &basicInfo, &securityInfo, &emailInfo, &mediaInfo, output, tempOutput, startTime) + default: + fmt.Println("Unsupported language") + } + handleUploadResults(output) finish = true if runtime.GOOS == "windows" || runtime.GOOS == "darwin" { fmt.Println("Press Enter to exit...") diff --git a/memorytest/memorytest.go b/memorytest/memorytest.go index 5085fd8..4b9591e 100644 --- a/memorytest/memorytest.go +++ b/memorytest/memorytest.go @@ -31,5 +31,5 @@ func MemoryTest(language, testMethod string) { if !strings.Contains(res, "\n") && res != "" { res += "\n" } - fmt.Printf(res) + fmt.Printf("%s", res) } diff --git a/unlocktest/media_test.go b/unlocktest/media_test.go index 843faea..4aee5a9 100644 --- a/unlocktest/media_test.go +++ b/unlocktest/media_test.go @@ -6,5 +6,5 @@ import ( ) func Test(t *testing.T) { - fmt.Printf(MediaTest("zh")) + fmt.Printf("%s", MediaTest("zh")) } diff --git a/utils/utils.go b/utils/utils.go index 7661ec2..9bd660c 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -3,13 +3,11 @@ package utils import ( "bufio" "bytes" + "context" "fmt" - "github.com/imroc/req/v3" - "github.com/oneclickvirt/UnlockTests/uts" - "github.com/oneclickvirt/basics/system" - . "github.com/oneclickvirt/defaultset" - "github.com/oneclickvirt/security/network" "io" + "net" + "net/http" "os" "path/filepath" "regexp" @@ -17,6 +15,12 @@ import ( "sync" "time" "unicode/utf8" + + "github.com/imroc/req/v3" + "github.com/oneclickvirt/UnlockTests/uts" + "github.com/oneclickvirt/basics/system" + . "github.com/oneclickvirt/defaultset" + "github.com/oneclickvirt/security/network" ) // PrintCenteredTitle 根据指定的宽度打印居中标题 @@ -95,14 +99,14 @@ func CheckChina(enableLogger bool) bool { } // BasicsAndSecurityCheck 执行安全检查 -func BasicsAndSecurityCheck(language, nt3CheckType string, securtyCheckStatus bool) (string, string, string) { +func BasicsAndSecurityCheck(language, nt3CheckType string, securityCheckStatus bool) (string, string, string) { var wgt sync.WaitGroup var ipInfo, securityInfo, systemInfo string var err error wgt.Add(1) go func() { defer wgt.Done() - ipInfo, securityInfo, err = network.NetworkCheck("both", securtyCheckStatus, language) + ipInfo, securityInfo, err = network.NetworkCheck("both", securityCheckStatus, language) if err != nil { fmt.Println(err.Error()) } @@ -330,3 +334,159 @@ func ProcessAndUpload(output string, filePath string, enableUplaod bool) (string } return "", "" } + +// ============================= 前置联网能力检测 ============================= + +var StackType string + +type NetCheckResult struct { + HasIPv4 bool + HasIPv6 bool + Connected bool + StackType string // "IPv4", "IPv6", "DualStack", "None" +} + +func makeResolver(proto, dnsAddr string) *net.Resolver { + return &net.Resolver{ + PreferGo: true, + Dial: func(ctx context.Context, network, address string) (net.Conn, error) { + d := net.Dialer{ + Timeout: 5 * time.Second, + } + return d.DialContext(ctx, proto, dnsAddr) + }, + } +} + +func CheckPublicAccess(timeout time.Duration) NetCheckResult { + if timeout < 2*time.Second { + timeout = 2 * time.Second + } + var wg sync.WaitGroup + resultChan := make(chan string, 8) + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + checks := []struct { + Tag string + Addr string + Kind string // udp4, udp6, http4, http6 + }{ + // UDP DNS + {"IPv4", "223.5.5.5:53", "udp4"}, // 阿里 DNS + {"IPv4", "8.8.8.8:53", "udp4"}, // Google DNS + {"IPv6", "[2400:3200::1]:53", "udp6"}, // 阿里 IPv6 DNS + {"IPv6", "[2001:4860:4860::8888]:53", "udp6"}, // Google IPv6 DNS + // HTTP HEAD + {"IPv4", "https://www.baidu.com", "http4"}, // 百度 + {"IPv4", "https://1.1.1.1", "http4"}, // Cloudflare + {"IPv6", "https://[2400:3200::1]", "http6"}, // 阿里 IPv6 + {"IPv6", "https://[2606:4700::1111]", "http6"}, // Cloudflare IPv6 + } + for _, check := range checks { + wg.Add(1) + go func(tag, addr, kind string) { + defer wg.Done() + defer func() { + if r := recover(); r != nil { + } + }() + switch kind { + case "udp4", "udp6": + dialer := &net.Dialer{ + Timeout: timeout / 4, + } + conn, err := dialer.DialContext(ctx, kind, addr) + if err == nil && conn != nil { + conn.Close() + select { + case resultChan <- tag: + case <-ctx.Done(): + return + } + } + case "http4", "http6": + var resolver *net.Resolver + if kind == "http4" { + resolver = makeResolver("udp4", "223.5.5.5:53") + } else { + resolver = makeResolver("udp6", "[2400:3200::1]:53") + } + dialer := &net.Dialer{ + Timeout: timeout / 4, + Resolver: resolver, + } + transport := &http.Transport{ + DialContext: dialer.DialContext, + MaxIdleConns: 1, + MaxIdleConnsPerHost: 1, + IdleConnTimeout: time.Second, + TLSHandshakeTimeout: timeout / 4, + ResponseHeaderTimeout: timeout / 4, + DisableKeepAlives: true, + } + client := &http.Client{ + Timeout: timeout / 4, + Transport: transport, + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + } + req, err := http.NewRequestWithContext(ctx, "HEAD", addr, nil) + if err != nil { + return + } + resp, err := client.Do(req) + if err == nil && resp != nil { + if resp.Body != nil { + resp.Body.Close() + } + if resp.StatusCode < 500 { + select { + case resultChan <- tag: + case <-ctx.Done(): + return + } + } + } + } + }(check.Tag, check.Addr, check.Kind) + } + go func() { + wg.Wait() + close(resultChan) + }() + hasV4 := false + hasV6 := false + for { + select { + case res, ok := <-resultChan: + if !ok { + goto result + } + if res == "IPv4" { + hasV4 = true + } + if res == "IPv6" { + hasV6 = true + } + case <-ctx.Done(): + goto result + } + } +result: + stack := "None" + if hasV4 && hasV6 { + stack = "DualStack" + } else if hasV4 { + stack = "IPv4" + } else if hasV6 { + stack = "IPv6" + } + StackType = stack + return NetCheckResult{ + HasIPv4: hasV4, + HasIPv6: hasV6, + Connected: hasV4 || hasV6, + StackType: stack, + } +} diff --git a/utils/utils_test.go b/utils/utils_test.go new file mode 100644 index 0000000..5add1fe --- /dev/null +++ b/utils/utils_test.go @@ -0,0 +1,17 @@ +package utils + +import ( + "fmt" + "testing" + "time" +) + +func TestCheckPublicAccess(t *testing.T) { + timeout := 3 * time.Second + result := CheckPublicAccess(timeout) + if result.Connected { + fmt.Printf("✅ 本机有公网连接,类型: %s\n", result.StackType) + } else { + fmt.Println("❌ 本机未检测到公网连接") + } +}