Files
ecs/utils/utils.go
spiritsoul a85a06b440 v0.0.76
调整输出文本
2024-10-04 23:53:57 +08:00

334 lines
9.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package utils
import (
"bytes"
"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"
"os"
"path/filepath"
"regexp"
"strings"
"sync"
"time"
"unicode/utf8"
)
// PrintCenteredTitle 根据指定的宽度打印居中标题
func PrintCenteredTitle(title string, width int) {
// 计算字符串的字符数
titleLength := utf8.RuneCountInString(title)
totalPadding := width - titleLength
padding := totalPadding / 2
paddingStr := strings.Repeat("-", padding)
fmt.Println(paddingStr + title + paddingStr + strings.Repeat("-", totalPadding%2))
}
// PrintHead 根据语言打印头部信息
func PrintHead(language string, width int, ecsVersion string) {
if language == "zh" {
PrintCenteredTitle("VPS融合怪测试", width)
fmt.Printf("版本:%s\n", ecsVersion)
fmt.Println("测评频道: https://t.me/vps_reviews\n" +
"Go项目地址https://github.com/oneclickvirt/ecs\n" +
"Shell项目地址https://github.com/spiritLHLS/ecs")
} else {
PrintCenteredTitle("VPS Fusion Monster Test", width)
fmt.Printf("Version: %s\n", ecsVersion)
fmt.Println("Review Channel: https://t.me/vps_reviews\n" +
"Go Project: https://github.com/oneclickvirt/ecs\n" +
"Shell Project: https://github.com/spiritLHLS/ecs")
}
}
func CheckChina(enableLogger bool) bool {
if enableLogger {
InitLogger()
defer Logger.Sync()
}
var selectChina bool
client := req.C()
client.SetTimeout(6 * time.Second)
client.R().
SetRetryCount(2).
SetRetryBackoffInterval(1*time.Second, 3*time.Second).
SetRetryFixedInterval(2 * time.Second)
ipapiURL := "https://ipapi.co/json"
cipccURL := "http://cip.cc"
ipapiResp, err := client.R().Get(ipapiURL)
if err != nil {
if enableLogger {
Logger.Info("无法获取IP信息:" + err.Error())
}
} else {
defer ipapiResp.Body.Close()
var ipapiBody string
ipapiBody, err = ipapiResp.ToString()
if err != nil {
if enableLogger {
Logger.Info("无法读取IP信息响应:" + err.Error())
}
} else {
isInChina := strings.Contains(ipapiBody, "China")
if isInChina {
fmt.Println("根据ipapi.co提供的信息当前IP可能在中国")
var input string
fmt.Print("是否选用中国专项测试(无流媒体测试有三网Ping值测试)? ([y]/n) ")
fmt.Scanln(&input)
switch strings.ToLower(input) {
case "yes", "y":
fmt.Println("使用中国专项测试")
selectChina = true
case "no", "n":
fmt.Println("不使用中国专项测试")
default:
fmt.Println("使用中国专项测试")
selectChina = true
}
return selectChina
}
}
}
cipccResp, err := client.R().Get(cipccURL)
if err != nil {
if enableLogger {
Logger.Info("无法获取IP信息:" + err.Error())
}
return false
}
defer cipccResp.Body.Close()
cipccBody, err := cipccResp.ToString()
if err != nil {
if enableLogger {
Logger.Info("无法读取IP信息响应:" + err.Error())
}
return false
}
isInChina := strings.Contains(cipccBody, "中国")
if isInChina {
fmt.Println("根据cip.cc提供的信息当前IP可能在中国")
var input string
fmt.Print("是否选用中国专项测试(无流媒体测试有三网Ping值测试)? ([y]/n) ")
fmt.Scanln(&input)
switch strings.ToLower(input) {
case "yes", "y":
fmt.Println("使用中国专项测试")
selectChina = true
case "no", "n":
fmt.Println("不使用中国专项测试")
default:
fmt.Println("不使用中国专项测试")
selectChina = true
}
}
return selectChina
}
// SecurityCheck 执行安全检查
func SecurityCheck(language, nt3CheckType string, securtyCheckStatus bool) (string, string, string) {
var wgt sync.WaitGroup
var ipInfo, securityInfo, systemInfo string
var err error
wgt.Add(2)
go func() {
defer wgt.Done()
ipInfo, securityInfo, err = network.NetworkCheck("both", securtyCheckStatus, language)
if err != nil {
fmt.Println(err.Error())
}
}()
go func() {
defer wgt.Done()
systemInfo = system.CheckSystemInfo(language)
}()
wgt.Wait()
basicInfo := systemInfo + ipInfo
if strings.Contains(ipInfo, "IPV4") && strings.Contains(ipInfo, "IPV6") {
uts.IPV4 = true
uts.IPV6 = true
if nt3CheckType == "" {
nt3CheckType = "ipv4"
}
} else if strings.Contains(ipInfo, "IPV4") {
uts.IPV4 = true
uts.IPV6 = false
if nt3CheckType == "" {
nt3CheckType = "ipv4"
}
} else if strings.Contains(ipInfo, "IPV6") {
uts.IPV6 = true
uts.IPV4 = false
if nt3CheckType == "" {
nt3CheckType = "ipv6"
}
}
if nt3CheckType == "ipv4" && !strings.Contains(ipInfo, "IPV4") && strings.Contains(ipInfo, "IPV6") {
nt3CheckType = "ipv6"
} else if nt3CheckType == "ipv6" && !strings.Contains(ipInfo, "IPV6") && strings.Contains(ipInfo, "IPV4") {
nt3CheckType = "ipv4"
}
basicInfo = strings.ReplaceAll(basicInfo, "\n\n", "\n")
return basicInfo, securityInfo, nt3CheckType
}
// CaptureOutput 捕获函数输出和错误输出,实时输出,并返回字符串
func CaptureOutput(f func()) string {
// 保存旧的 stdout 和 stderr
oldStdout := os.Stdout
oldStderr := os.Stderr
// 创建管道
stdoutPipeR, stdoutPipeW, err := os.Pipe()
if err != nil {
return "Error creating stdout pipe"
}
stderrPipeR, stderrPipeW, err := os.Pipe()
if err != nil {
stdoutPipeW.Close()
stdoutPipeR.Close()
return "Error creating stderr pipe"
}
// 替换标准输出和标准错误输出为管道写入端
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{})
go func() {
multiWriter := io.MultiWriter(&stdoutBuf, oldStdout)
io.Copy(multiWriter, stdoutPipeR)
done <- struct{}{}
}()
go func() {
multiWriter := io.MultiWriter(&stderrBuf, oldStderr)
io.Copy(multiWriter, stderrPipeR)
done <- struct{}{}
}()
// 执行函数
f()
// 关闭管道写入端,让管道读取端可以读取所有数据
stdoutPipeW.Close()
stderrPipeW.Close()
// 等待两个 goroutine 完成
<-done
<-done
// 返回捕获的输出字符串
// stderrBuf.String()
return stdoutBuf.String()
}
// PrintAndCapture 捕获函数输出的同时打印内容
func PrintAndCapture(f func(), tempOutput, output string) string {
tempOutput = CaptureOutput(f)
output += tempOutput
return output
}
// UploadText 上传文本内容到指定URL
func UploadText(absPath string) (string, string, error) {
primaryURL := "http://hpaste.spiritlhl.net/api/upload"
backupURL := "https://paste.spiritlhl.net/api/upload"
token := network.SecurityUploadToken
client := req.DefaultClient()
client.SetTimeout(6 * time.Second)
client.R().
SetRetryCount(2).
SetRetryBackoffInterval(1*time.Second, 5*time.Second).
SetRetryFixedInterval(2 * time.Second)
file, err := os.Open(absPath)
if err != nil {
return "", "", err
}
defer file.Close()
upload := func(url string) (string, string, error) {
resp, err := client.R().
SetHeader("Authorization", token).
SetHeader("Format", "RANDOM").
SetHeader("Max-Views", "0").
SetHeader("UploadText", "true").
SetHeader("Content-Type", "multipart/form-data").
SetHeader("No-JSON", "true").
SetFileReader("file", "goecs.txt", file).
Post(url)
if err != nil {
return "", "", err
}
if resp.StatusCode >= 200 && resp.StatusCode <= 299 {
return strings.ReplaceAll(resp.String(), "https://paste.spiritlhl.net/", "http://hpaste.spiritlhl.net/"),
strings.ReplaceAll(resp.String(), "http://hpaste.spiritlhl.net/", "https://paste.spiritlhl.net/"), nil
} else {
return "", "", fmt.Errorf("upload failed with status code: %d", resp.StatusCode)
}
}
http_url, https_url, err := upload(primaryURL)
if err == nil {
return http_url, https_url, nil
}
http_url, https_url, err = upload(backupURL)
if err != nil {
return "", "", err
}
return http_url, https_url, nil
}
// ProcessAndUpload 创建结果文件并上传文件
func ProcessAndUpload(output string, filePath string, enableUplaod bool) {
// 检查文件是否存在
if _, err := os.Stat(filePath); err == nil {
// 文件存在,删除文件
err = os.Remove(filePath)
if err != nil {
fmt.Println("Cannot delete file:", err)
return
}
}
// 创建文件
file, err := os.Create(filePath)
if err != nil {
fmt.Println("Cannot create file:", err)
return
}
defer file.Close()
// 匹配 ANSI 转义序列
ansiRegex := regexp.MustCompile("\x1B\\[[0-9;]+[a-zA-Z]")
// 移除 ANSI 转义序列
cleanedOutput := ansiRegex.ReplaceAllString(output, "")
// 写入文件
_, err = file.WriteString(cleanedOutput)
if err != nil {
fmt.Println("Cannot write to file:", err)
return
} else {
fmt.Println("Write test result in ", filePath)
}
if enableUplaod {
// 获取文件的绝对路径
absPath, err2 := filepath.Abs(filePath)
if err2 != nil {
fmt.Println("Failed to get absolute file path:", err2)
return
}
// 上传文件并生成短链接
http_url, https_url, err3 := UploadText(absPath)
if err3 != nil {
fmt.Println("Upload failed, cannot generate short URL.")
fmt.Println(err3.Error())
return
}
fmt.Printf("Upload successful!\nHttp URL:%s\nHttps URL:%s\n", http_url, https_url)
}
}