fix:修复恶性BUG添加单项recover机制,优化整体执行的稳定性

This commit is contained in:
spiritlhl
2025-11-11 09:42:44 +00:00
parent 858585b4ff
commit 3b5b8a348e
12 changed files with 269 additions and 95 deletions

View File

@@ -27,7 +27,7 @@ import (
)
var (
ecsVersion = "v0.1.102" // 融合怪版本号
ecsVersion = "v0.1.103" // 融合怪版本号
configs = params.NewConfig(ecsVersion) // 全局配置实例
userSetFlags = make(map[string]bool) // 用于跟踪哪些参数是用户显式设置的
)
@@ -83,6 +83,7 @@ func main() {
basicInfo, securityInfo, emailInfo, mediaInfo, ptInfo string
output, tempOutput string
outputMutex sync.Mutex
infoMutex sync.Mutex // 保护并发字符串写入
)
startTime := time.Now()
uploadDone := make(chan bool, 1)
@@ -91,9 +92,9 @@ func main() {
go runner.HandleSignalInterrupt(sig, configs, &startTime, &output, tempOutput, uploadDone, &outputMutex)
switch configs.Language {
case "zh":
runner.RunChineseTests(preCheck, configs, &wg1, &wg2, &wg3, &basicInfo, &securityInfo, &emailInfo, &mediaInfo, &ptInfo, &output, tempOutput, startTime, &outputMutex)
runner.RunChineseTests(preCheck, configs, &wg1, &wg2, &wg3, &basicInfo, &securityInfo, &emailInfo, &mediaInfo, &ptInfo, &output, tempOutput, startTime, &outputMutex, &infoMutex)
case "en":
runner.RunEnglishTests(preCheck, configs, &wg1, &wg2, &wg3, &basicInfo, &securityInfo, &emailInfo, &mediaInfo, &ptInfo, &output, tempOutput, startTime, &outputMutex)
runner.RunEnglishTests(preCheck, configs, &wg1, &wg2, &wg3, &basicInfo, &securityInfo, &emailInfo, &mediaInfo, &ptInfo, &output, tempOutput, startTime, &outputMutex, &infoMutex)
default:
fmt.Println("Unsupported language")
}

View File

@@ -21,7 +21,7 @@ func GetMenuChoice(language string) string {
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
defer signal.Stop(sigChan)
inputChan := make(chan string, 1)
go func() {
select {
case <-sigChan:
@@ -31,43 +31,33 @@ func GetMenuChoice(language string) string {
return
}
}()
for {
go func() {
var input string
fmt.Print("请输入选项 / Please enter your choice: ")
fmt.Scanln(&input)
input = strings.TrimSpace(input)
input = strings.TrimRight(input, "\n")
select {
case inputChan <- input:
case <-ctx.Done():
return
}
}()
select {
case input := <-inputChan:
re := regexp.MustCompile(`^\d+$`)
if re.MatchString(input) {
inChoice := input
switch inChoice {
case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10":
return inChoice
default:
if language == "zh" {
fmt.Println("无效的选项")
} else {
fmt.Println("Invalid choice")
}
}
} else {
var input string
fmt.Print("请输入选项 / Please enter your choice: ")
fmt.Scanln(&input)
input = strings.TrimSpace(input)
input = strings.TrimRight(input, "\n")
re := regexp.MustCompile(`^\d+$`)
if re.MatchString(input) {
inChoice := input
switch inChoice {
case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10":
return inChoice
default:
if language == "zh" {
fmt.Println("输入错误,请输入一个纯数字")
fmt.Println("无效的选项")
} else {
fmt.Println("Invalid input, please enter a number")
fmt.Println("Invalid choice")
}
}
case <-ctx.Done():
return ""
} else {
if language == "zh" {
fmt.Println("输入错误,请输入一个纯数字")
} else {
fmt.Println("Invalid input, please enter a number")
}
}
}
}

View File

@@ -210,72 +210,116 @@ func (c *Config) SaveUserSetParams() map[string]interface{} {
// RestoreUserSetParams restores user-set parameters
func (c *Config) RestoreUserSetParams(saved map[string]interface{}) {
if val, ok := saved["basic"]; ok {
c.BasicStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.BasicStatus = boolVal
}
}
if val, ok := saved["cpu"]; ok {
c.CpuTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.CpuTestStatus = boolVal
}
}
if val, ok := saved["memory"]; ok {
c.MemoryTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.MemoryTestStatus = boolVal
}
}
if val, ok := saved["disk"]; ok {
c.DiskTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.DiskTestStatus = boolVal
}
}
if val, ok := saved["ut"]; ok {
c.UtTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.UtTestStatus = boolVal
}
}
if val, ok := saved["security"]; ok {
c.SecurityTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.SecurityTestStatus = boolVal
}
}
if val, ok := saved["email"]; ok {
c.EmailTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.EmailTestStatus = boolVal
}
}
if val, ok := saved["backtrace"]; ok {
c.BacktraceStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.BacktraceStatus = boolVal
}
}
if val, ok := saved["nt3"]; ok {
c.Nt3Status = val.(bool)
if boolVal, ok := val.(bool); ok {
c.Nt3Status = boolVal
}
}
if val, ok := saved["speed"]; ok {
c.SpeedTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.SpeedTestStatus = boolVal
}
}
if val, ok := saved["ping"]; ok {
c.PingTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.PingTestStatus = boolVal
}
}
if val, ok := saved["tgdc"]; ok {
c.TgdcTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.TgdcTestStatus = boolVal
}
}
if val, ok := saved["web"]; ok {
c.WebTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.WebTestStatus = boolVal
}
}
if val, ok := saved["cpum"]; ok {
c.CpuTestMethod = val.(string)
if strVal, ok := val.(string); ok {
c.CpuTestMethod = strVal
}
}
if val, ok := saved["cput"]; ok {
c.CpuTestThreadMode = val.(string)
if strVal, ok := val.(string); ok {
c.CpuTestThreadMode = strVal
}
}
if val, ok := saved["memorym"]; ok {
c.MemoryTestMethod = val.(string)
if strVal, ok := val.(string); ok {
c.MemoryTestMethod = strVal
}
}
if val, ok := saved["diskm"]; ok {
c.DiskTestMethod = val.(string)
if strVal, ok := val.(string); ok {
c.DiskTestMethod = strVal
}
}
if val, ok := saved["diskp"]; ok {
c.DiskTestPath = val.(string)
if strVal, ok := val.(string); ok {
c.DiskTestPath = strVal
}
}
if val, ok := saved["diskmc"]; ok {
c.DiskMultiCheck = val.(bool)
if boolVal, ok := val.(bool); ok {
c.DiskMultiCheck = boolVal
}
}
if val, ok := saved["nt3loc"]; ok {
if c.Choice != "10" {
c.Nt3Location = val.(string)
if strVal, ok := val.(string); ok {
c.Nt3Location = strVal
}
}
}
if val, ok := saved["nt3t"]; ok {
c.Nt3CheckType = val.(string)
if strVal, ok := val.(string); ok {
c.Nt3CheckType = strVal
}
}
if val, ok := saved["spnum"]; ok {
c.SpNum = val.(int)
if intVal, ok := val.(int); ok {
c.SpNum = intVal
}
}
c.ValidateParams()

View File

@@ -2,6 +2,7 @@ package runner
import (
"bufio"
"context"
"fmt"
"os"
"runtime"
@@ -17,7 +18,7 @@ import (
)
// RunChineseTests runs all tests in Chinese mode
func RunChineseTests(preCheck utils.NetCheckResult, config *params.Config, wg1, wg2, wg3 *sync.WaitGroup, basicInfo, securityInfo, emailInfo, mediaInfo, ptInfo *string, output *string, tempOutput string, startTime time.Time, outputMutex *sync.Mutex) {
func RunChineseTests(preCheck utils.NetCheckResult, config *params.Config, wg1, wg2, wg3 *sync.WaitGroup, basicInfo, securityInfo, emailInfo, mediaInfo, ptInfo *string, output *string, tempOutput string, startTime time.Time, outputMutex *sync.Mutex, infoMutex *sync.Mutex) {
*output = RunBasicTests(preCheck, config, basicInfo, securityInfo, *output, tempOutput, outputMutex)
*output = RunCPUTest(config, *output, tempOutput, outputMutex)
*output = RunMemoryTest(config, *output, tempOutput, outputMutex)
@@ -29,30 +30,39 @@ func RunChineseTests(preCheck utils.NetCheckResult, config *params.Config, wg1,
wg1.Add(1)
go func() {
defer wg1.Done()
*mediaInfo = tests.MediaTest(config.Language)
result := tests.MediaTest(config.Language)
infoMutex.Lock()
*mediaInfo = result
infoMutex.Unlock()
}()
}
if config.EmailTestStatus && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" {
wg2.Add(1)
go func() {
defer wg2.Done()
*emailInfo = email.EmailCheck()
result := email.EmailCheck()
infoMutex.Lock()
*emailInfo = result
infoMutex.Unlock()
}()
}
if (config.OnlyChinaTest || config.PingTestStatus) && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" {
wg3.Add(1)
go func() {
defer wg3.Done()
*ptInfo = pt.PingTest()
result := pt.PingTest()
infoMutex.Lock()
*ptInfo = result
infoMutex.Unlock()
}()
}
if preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" {
*output = RunStreamingTests(config, wg1, mediaInfo, *output, tempOutput, outputMutex)
*output = RunStreamingTests(config, wg1, mediaInfo, *output, tempOutput, outputMutex, infoMutex)
*output = RunSecurityTests(config, *securityInfo, *output, tempOutput, outputMutex)
*output = RunEmailTests(config, wg2, emailInfo, *output, tempOutput, outputMutex)
*output = RunEmailTests(config, wg2, emailInfo, *output, tempOutput, outputMutex, infoMutex)
}
if runtime.GOOS != "windows" && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" {
*output = RunNetworkTests(config, wg3, ptInfo, *output, tempOutput, outputMutex)
*output = RunNetworkTests(config, wg3, ptInfo, *output, tempOutput, outputMutex, infoMutex)
}
if preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" {
*output = RunSpeedTests(config, *output, tempOutput, outputMutex)
@@ -61,7 +71,7 @@ func RunChineseTests(preCheck utils.NetCheckResult, config *params.Config, wg1,
}
// RunEnglishTests runs all tests in English mode
func RunEnglishTests(preCheck utils.NetCheckResult, config *params.Config, wg1, wg2, wg3 *sync.WaitGroup, basicInfo, securityInfo, emailInfo, mediaInfo, ptInfo *string, output *string, tempOutput string, startTime time.Time, outputMutex *sync.Mutex) {
func RunEnglishTests(preCheck utils.NetCheckResult, config *params.Config, wg1, wg2, wg3 *sync.WaitGroup, basicInfo, securityInfo, emailInfo, mediaInfo, ptInfo *string, output *string, tempOutput string, startTime time.Time, outputMutex *sync.Mutex, infoMutex *sync.Mutex) {
*output = RunBasicTests(preCheck, config, basicInfo, securityInfo, *output, tempOutput, outputMutex)
*output = RunCPUTest(config, *output, tempOutput, outputMutex)
*output = RunMemoryTest(config, *output, tempOutput, outputMutex)
@@ -74,19 +84,25 @@ func RunEnglishTests(preCheck utils.NetCheckResult, config *params.Config, wg1,
wg1.Add(1)
go func() {
defer wg1.Done()
*mediaInfo = tests.MediaTest(config.Language)
result := tests.MediaTest(config.Language)
infoMutex.Lock()
*mediaInfo = result
infoMutex.Unlock()
}()
}
if config.EmailTestStatus {
wg2.Add(1)
go func() {
defer wg2.Done()
*emailInfo = email.EmailCheck()
result := email.EmailCheck()
infoMutex.Lock()
*emailInfo = result
infoMutex.Unlock()
}()
}
*output = RunStreamingTests(config, wg1, mediaInfo, *output, tempOutput, outputMutex)
*output = RunStreamingTests(config, wg1, mediaInfo, *output, tempOutput, outputMutex, infoMutex)
*output = RunSecurityTests(config, *securityInfo, *output, tempOutput, outputMutex)
*output = RunEmailTests(config, wg2, emailInfo, *output, tempOutput, outputMutex)
*output = RunEmailTests(config, wg2, emailInfo, *output, tempOutput, outputMutex, infoMutex)
*output = RunEnglishNetworkTests(config, wg3, ptInfo, *output, tempOutput, outputMutex)
*output = RunEnglishSpeedTests(config, *output, tempOutput, outputMutex)
}
@@ -218,7 +234,7 @@ func RunDiskTest(config *params.Config, output, tempOutput string, outputMutex *
}
// RunStreamingTests runs platform unlock tests
func RunStreamingTests(config *params.Config, wg1 *sync.WaitGroup, mediaInfo *string, output, tempOutput string, outputMutex *sync.Mutex) string {
func RunStreamingTests(config *params.Config, wg1 *sync.WaitGroup, mediaInfo *string, output, tempOutput string, outputMutex *sync.Mutex, infoMutex *sync.Mutex) string {
outputMutex.Lock()
defer outputMutex.Unlock()
return utils.PrintAndCapture(func() {
@@ -229,7 +245,10 @@ func RunStreamingTests(config *params.Config, wg1 *sync.WaitGroup, mediaInfo *st
} else {
utils.PrintCenteredTitle("Cross-Border-Platform-Unlock", config.Width)
}
fmt.Printf("%s", *mediaInfo)
infoMutex.Lock()
info := *mediaInfo
infoMutex.Unlock()
fmt.Printf("%s", info)
}
}, tempOutput, output)
}
@@ -251,7 +270,7 @@ func RunSecurityTests(config *params.Config, securityInfo, output, tempOutput st
}
// RunEmailTests runs email port tests
func RunEmailTests(config *params.Config, wg2 *sync.WaitGroup, emailInfo *string, output, tempOutput string, outputMutex *sync.Mutex) string {
func RunEmailTests(config *params.Config, wg2 *sync.WaitGroup, emailInfo *string, output, tempOutput string, outputMutex *sync.Mutex, infoMutex *sync.Mutex) string {
outputMutex.Lock()
defer outputMutex.Unlock()
return utils.PrintAndCapture(func() {
@@ -262,13 +281,16 @@ func RunEmailTests(config *params.Config, wg2 *sync.WaitGroup, emailInfo *string
} else {
utils.PrintCenteredTitle("Email-Port-Check", config.Width)
}
fmt.Println(*emailInfo)
infoMutex.Lock()
info := *emailInfo
infoMutex.Unlock()
fmt.Println(info)
}
}, tempOutput, output)
}
// RunNetworkTests runs network tests (Chinese mode)
func RunNetworkTests(config *params.Config, wg3 *sync.WaitGroup, ptInfo *string, output, tempOutput string, outputMutex *sync.Mutex) string {
func RunNetworkTests(config *params.Config, wg3 *sync.WaitGroup, ptInfo *string, output, tempOutput string, outputMutex *sync.Mutex, infoMutex *sync.Mutex) string {
outputMutex.Lock()
defer outputMutex.Unlock()
return utils.PrintAndCapture(func() {
@@ -280,15 +302,18 @@ func RunNetworkTests(config *params.Config, wg3 *sync.WaitGroup, ptInfo *string,
utils.PrintCenteredTitle("三网回程路由检测", config.Width)
tests.NextTrace3Check(config.Language, config.Nt3Location, config.Nt3CheckType)
}
if config.OnlyChinaTest && *ptInfo != "" {
infoMutex.Lock()
info := *ptInfo
infoMutex.Unlock()
if config.OnlyChinaTest && info != "" {
wg3.Wait()
utils.PrintCenteredTitle("PING值检测", config.Width)
fmt.Println(*ptInfo)
fmt.Println(info)
}
if config.PingTestStatus && *ptInfo != "" {
if config.PingTestStatus && info != "" {
wg3.Wait()
utils.PrintCenteredTitle("PING值检测", config.Width)
fmt.Println(*ptInfo)
fmt.Println(info)
if config.TgdcTestStatus {
fmt.Println(pt.TelegramDCTest())
}
@@ -414,16 +439,26 @@ func HandleSignalInterrupt(sig chan os.Signal, config *params.Config, startTime
httpsURL string
}, 1)
if config.EnableUpload {
// 使用context来控制上传goroutine
uploadCtx, uploadCancel := context.WithTimeout(context.Background(), 30*time.Second)
defer uploadCancel()
go func() {
httpURL, httpsURL := utils.ProcessAndUpload(finalOutput, config.FilePath, config.EnableUpload)
resultChan <- struct {
select {
case resultChan <- struct {
httpURL string
httpsURL string
}{httpURL, httpsURL}
uploadDone <- true
}{httpURL, httpsURL}:
case <-uploadCtx.Done():
// 上传被取消或超时,直接返回
return
}
}()
select {
case result := <-resultChan:
uploadCancel() // 成功完成取消context
if result.httpURL != "" || result.httpsURL != "" {
if config.Language == "en" {
fmt.Printf("Upload successfully!\nHttp URL: %s\nHttps URL: %s\n", result.httpURL, result.httpsURL)
@@ -437,7 +472,7 @@ func HandleSignalInterrupt(sig chan os.Signal, config *params.Config, startTime
fmt.Scanln()
}
os.Exit(0)
case <-time.After(30 * time.Second):
case <-uploadCtx.Done():
if config.Language == "en" {
fmt.Println("Upload timeout, program exit")
} else {

View File

@@ -1,6 +1,8 @@
package tests
import (
"fmt"
"os"
"runtime"
"strings"
@@ -8,6 +10,14 @@ import (
)
func CpuTest(language, testMethod, testThread string) (realTestMethod, res string) {
defer func() {
if r := recover(); r != nil {
fmt.Fprintf(os.Stderr, "[WARN] CpuTest panic: %v\n", r)
res = fmt.Sprintf("\nCPU test failed: %v\n", r)
realTestMethod = "error"
}
}()
if runtime.GOOS == "windows" {
if testMethod != "winsat" && testMethod != "" {
// res = "Detected host is Windows, using Winsat for testing.\n"

View File

@@ -1,6 +1,8 @@
package tests
import (
"fmt"
"os"
"runtime"
"strings"
@@ -8,6 +10,14 @@ import (
)
func DiskTest(language, testMethod, testPath string, isMultiCheck bool, autoChange bool) (realTestMethod, res string) {
defer func() {
if r := recover(); r != nil {
fmt.Fprintf(os.Stderr, "[WARN] DiskTest panic: %v\n", r)
res = fmt.Sprintf("\nDisk test failed: %v\n", r)
realTestMethod = "error"
}
}()
switch testMethod {
case "fio":
res = disk.FioTest(language, isMultiCheck, testPath)

View File

@@ -1,6 +1,8 @@
package tests
import (
"fmt"
"os"
"runtime"
"strings"
@@ -8,6 +10,14 @@ import (
)
func MemoryTest(language, testMethod string) (realTestMethod, res string) {
defer func() {
if r := recover(); r != nil {
fmt.Fprintf(os.Stderr, "[WARN] MemoryTest panic: %v\n", r)
res = fmt.Sprintf("\nMemory test failed: %v\n", r)
realTestMethod = "error"
}
}()
testMethod = strings.ToLower(testMethod)
if testMethod == "" {
testMethod = "auto"

View File

@@ -2,14 +2,43 @@ package tests
import (
"fmt"
"os"
"strings"
"github.com/oneclickvirt/nt3/nt"
)
func NextTrace3Check(language, nt3Location, nt3CheckType string) {
// 添加panic恢复机制防止因权限问题导致程序崩溃
defer func() {
if r := recover(); r != nil {
if language == "zh" {
fmt.Println("\n路由追踪测试出现错误可能因为权限不足已跳过")
fmt.Fprintf(os.Stderr, "[WARN] 路由追踪panic: %v\n", r)
} else {
fmt.Println("\nRoute tracing test failed (possibly due to insufficient permissions), skipped")
fmt.Fprintf(os.Stderr, "[WARN] Route tracing panic: %v\n", r)
}
}
}()
resultChan := make(chan nt.TraceResult, 100)
go nt.TraceRoute(language, nt3Location, nt3CheckType, resultChan)
go func() {
// 在goroutine中也添加错误恢复
defer func() {
if r := recover(); r != nil {
// 发送错误结果并关闭channel
resultChan <- nt.TraceResult{
Index: -1,
ISPName: "Error",
Output: []string{fmt.Sprintf("Route tracing error: %v", r)},
}
close(resultChan)
}
}()
nt.TraceRoute(language, nt3Location, nt3CheckType, resultChan)
}()
for result := range resultChan {
if result.Index == -1 {
for index, res := range result.Output {

View File

@@ -1,6 +1,8 @@
package tests
import (
"fmt"
"os"
"runtime"
"strings"
@@ -9,10 +11,20 @@ import (
)
func ShowHead(language string) {
defer func() {
if r := recover(); r != nil {
fmt.Fprintf(os.Stderr, "[WARN] ShowHead panic: %v\n", r)
}
}()
sp.ShowHead(language)
}
func NearbySP() {
defer func() {
if r := recover(); r != nil {
fmt.Fprintf(os.Stderr, "[WARN] NearbySP panic: %v\n", r)
}
}()
if runtime.GOOS == "windows" || sp.OfficialAvailableTest() != nil {
sp.NearbySpeedTest()
} else {
@@ -21,6 +33,11 @@ func NearbySP() {
}
func CustomSP(platform, operator string, num int, language string) {
defer func() {
if r := recover(); r != nil {
fmt.Fprintf(os.Stderr, "[WARN] CustomSP panic: %v\n", r)
}
}()
var url, parseType string
if strings.ToLower(platform) == "cn" {
if strings.ToLower(operator) == "cmcc" {

View File

@@ -1,12 +1,21 @@
package tests
import (
"fmt"
"os"
"github.com/oneclickvirt/UnlockTests/executor"
"github.com/oneclickvirt/UnlockTests/utils"
"github.com/oneclickvirt/defaultset"
)
func MediaTest(language string) string {
defer func() {
if r := recover(); r != nil {
fmt.Fprintf(os.Stderr, "[WARN] MediaTest panic: %v\n", r)
}
}()
var res string
readStatus := executor.ReadSelect(language, "0")
if !readStatus {

View File

@@ -2,6 +2,7 @@ package tests
import (
"fmt"
"os"
"sync"
"time"
@@ -29,12 +30,25 @@ type ConcurrentResults struct {
var IPV4, IPV6 string
func UpstreamsCheck() {
// 添加panic恢复机制
defer func() {
if r := recover(); r != nil {
fmt.Println("\n上游检测出现错误已跳过")
fmt.Fprintf(os.Stderr, "[WARN] Upstream check panic: %v\n", r)
}
}()
results := ConcurrentResults{}
var wg sync.WaitGroup
if IPV4 != "" {
wg.Add(1)
go func() {
defer wg.Done()
defer func() {
if r := recover(); r != nil {
fmt.Fprintf(os.Stderr, "[WARN] BGP info panic: %v\n", r)
}
}()
for i := 0; i < 2; i++ {
result, err := bgptools.GetPoPInfo(IPV4)
results.bgpError = err
@@ -51,6 +65,11 @@ func UpstreamsCheck() {
wg.Add(1)
go func() {
defer wg.Done()
defer func() {
if r := recover(); r != nil {
fmt.Fprintf(os.Stderr, "[WARN] Backtrace panic: %v\n", r)
}
}()
result := backtrace.BackTrace(executor.IPV6)
results.backtraceResult = result
}()

View File

@@ -203,19 +203,10 @@ func CaptureOutput(f func()) string {
// 替换标准输出和标准错误输出为管道写入端
os.Stdout = stdoutPipeW
os.Stderr = stderrPipeW
// 恢复标准输出和标准错误输出
defer func() {
os.Stdout = oldStdout
os.Stderr = oldStderr
stdoutPipeW.Close()
stderrPipeW.Close()
stdoutPipeR.Close()
stderrPipeR.Close()
}()
// 缓冲区
var stdoutBuf, stderrBuf bytes.Buffer
// 并发读取 stdout 和 stderr
done := make(chan struct{})
done := make(chan struct{}, 2)
go func() {
multiWriter := io.MultiWriter(&stdoutBuf, oldStdout)
io.Copy(multiWriter, stdoutPipeR)
@@ -234,6 +225,11 @@ func CaptureOutput(f func()) string {
// 等待两个 goroutine 完成
<-done
<-done
// 恢复标准输出和标准错误输出,并关闭管道读取端
os.Stdout = oldStdout
os.Stderr = oldStderr
stdoutPipeR.Close()
stderrPipeR.Close()
// 返回捕获的输出字符串
// stderrBuf.String()
return stdoutBuf.String()
@@ -317,7 +313,9 @@ func ProcessAndUpload(output string, filePath string, enableUplaod bool) (string
// 使用 defer 来处理 panic
defer func() {
if r := recover(); r != nil {
fmt.Printf("处理上传时发生错误: %v\n", r)
fmt.Fprintf(os.Stderr, "[ERROR] 处理上传时发生严重错误: %v\n", r)
// 可以选择打印堆栈信息以便调试
// debug.PrintStack()
}
}()
// 检查文件是否存在
@@ -425,6 +423,8 @@ func CheckPublicAccess(timeout time.Duration) NetCheckResult {
defer wg.Done()
defer func() {
if r := recover(); r != nil {
// 记录panic但不影响其他检查输出到stderr避免污染主输出
fmt.Fprintf(os.Stderr, "[WARN] Panic in network check for %s (%s): %v\n", tag, addr, r)
}
}()
switch kind {