mirror of
				https://github.com/oneclickvirt/ecs.git
				synced 2025-10-31 10:56:37 +08:00 
			
		
		
		
	Compare commits
	
		
			88 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 57e87348d4 | ||
|   | d40bf5a195 | ||
|   | 753738931d | ||
|   | a702c5416a | ||
| ![github-actions[bot]](/assets/img/avatar_default.png)  | a587d71348 | ||
|   | 110e6d34f9 | ||
|   | 4d18497dd3 | ||
|   | c676cd83cb | ||
|   | 58e1de4487 | ||
|   | 89eecd2acc | ||
|   | 194dee49fd | ||
|   | 1e88513b8e | ||
|   | f84023d18b | ||
| ![github-actions[bot]](/assets/img/avatar_default.png)  | 2cfd5af3c0 | ||
|   | ed66e2804a | ||
|   | 174bf303af | ||
|   | b75f42ffe5 | ||
| ![github-actions[bot]](/assets/img/avatar_default.png)  | 56b71ac53f | ||
|   | 1045d3fab8 | ||
| ![github-actions[bot]](/assets/img/avatar_default.png)  | 7bd2b59d58 | ||
|   | cc1da7ea7c | ||
| ![github-actions[bot]](/assets/img/avatar_default.png)  | 1a002a1681 | ||
|   | ee2b55e7eb | ||
|   | a55cebf94b | ||
|   | 0571a8df13 | ||
|   | f29a2829f3 | ||
|   | 33b8e0396f | ||
|   | c259073d1b | ||
|   | 07ebc8cab5 | ||
|   | 1824051e53 | ||
|   | 9f93a2e59d | ||
|   | 8cd09182da | ||
|   | 9bb776d411 | ||
|   | 12f2da9da2 | ||
| ![github-actions[bot]](/assets/img/avatar_default.png)  | 7aa70ac1fd | ||
|   | 04ce926582 | ||
|   | 73eb38eed1 | ||
|   | 9bc8a934b1 | ||
|   | 7b729e073b | ||
|   | 111126ae90 | ||
|   | 9397f789be | ||
|   | 5a1dda6483 | ||
|   | e322c717c0 | ||
|   | 778b33142b | ||
|   | aa9f361380 | ||
| ![github-actions[bot]](/assets/img/avatar_default.png)  | 3236c60359 | ||
|   | 73b0f30ddc | ||
|   | 825da78bd5 | ||
|   | 5d2f3c7f96 | ||
|   | 61247a206e | ||
|   | f0daad1360 | ||
| ![github-actions[bot]](/assets/img/avatar_default.png)  | 2d23fb55a0 | ||
|   | a73dbf2d0b | ||
|   | b38dd713d9 | ||
| ![github-actions[bot]](/assets/img/avatar_default.png)  | e66ef1f106 | ||
|   | f6ee1e40ec | ||
|   | cb2bf0a7e5 | ||
|   | ad017db5a6 | ||
|   | a99f58518a | ||
|   | 2e59bac322 | ||
|   | 4132b1daff | ||
| ![github-actions[bot]](/assets/img/avatar_default.png)  | 53296b745a | ||
|   | 74630e9615 | ||
|   | 5ec7924214 | ||
|   | 7a7fdc26a0 | ||
|   | d4c855de92 | ||
|   | 7c22dee443 | ||
| ![github-actions[bot]](/assets/img/avatar_default.png)  | 797496b640 | ||
|   | 5b686abdc8 | ||
|   | f99a37edbe | ||
|   | 4ff49c8b90 | ||
|   | 1d9257beb3 | ||
|   | fc6ccb9f92 | ||
| ![github-actions[bot]](/assets/img/avatar_default.png)  | 88a2a7fdc9 | ||
|   | 5ff18ed7c7 | ||
|   | df897db244 | ||
|   | 9a8680491c | ||
|   | 33f81fd6aa | ||
| ![github-actions[bot]](/assets/img/avatar_default.png)  | 940703c3f9 | ||
|   | 1c2e9cdab9 | ||
|   | 3e6524fa0e | ||
|   | 026f40dc4c | ||
| ![github-actions[bot]](/assets/img/avatar_default.png)  | 110c58d401 | ||
|   | 06e76a9c33 | ||
|   | 6b88a81c02 | ||
|   | 5482506bab | ||
|   | b7130db8ce | ||
| ![github-actions[bot]](/assets/img/avatar_default.png)  | dc5e3b7852 | 
							
								
								
									
										14
									
								
								.back/OldFunction.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								.back/OldFunction.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| // clearScreen 清屏 | ||||
| func clearScreen() { | ||||
| 	var cmd *exec.Cmd | ||||
| 	switch runtime.GOOS { | ||||
| 	case "windows": | ||||
| 		cmd = exec.Command("cmd", "/c", "cls") | ||||
| 	case "darwin": | ||||
| 		cmd = exec.Command("clear") | ||||
| 	default: | ||||
| 		cmd = exec.Command("clear") | ||||
| 	} | ||||
| 	cmd.Stdout = os.Stdout | ||||
| 	_ = cmd.Run() | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| package backtrace | ||||
|  | ||||
| import ( | ||||
| 	"github.com/oneclickvirt/backtrace/bk" | ||||
| ) | ||||
|  | ||||
| func BackTrace(enableIpv6 bool) { | ||||
| 	backtrace.BackTrace(enableIpv6) | ||||
| } | ||||
| @@ -1,21 +0,0 @@ | ||||
| package backtrace | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| //func TestGeneratePrefixMap(t *testing.T) { | ||||
| //	prefix := "223.119.8.0/21" | ||||
| //	prefixList := GeneratePrefixList(prefix) | ||||
| //	if prefixList != nil { | ||||
| //		// 打印生成的IP地址前缀列表 | ||||
| //		for _, ip := range prefixList { | ||||
| //			fmt.Println(ip) | ||||
| //		} | ||||
| //	} | ||||
| //} | ||||
|  | ||||
| // 本包仅测试,无实际使用 | ||||
| func TestBackTrace(t *testing.T) { | ||||
| 	BackTrace(false) | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| package ntrace | ||||
|  | ||||
| import ( | ||||
| 	"github.com/oneclickvirt/nt3/nt" | ||||
| ) | ||||
|  | ||||
| func TraceRoute3(language, location, checkType string) { | ||||
| 	nt.TraceRoute(language, location, checkType) | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| package ntrace | ||||
|  | ||||
| import "testing" | ||||
|  | ||||
| // https://github.com/nxtrace/NTrace-core/blob/main/fast_trace/fast_trace.go | ||||
| // 本包仅测试无实际使用 | ||||
| func TestTraceRoute(t *testing.T) { | ||||
| 	TraceRoute3("en", "GZ", "ipv4") | ||||
| } | ||||
							
								
								
									
										19
									
								
								.github/workflows/build_docker.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								.github/workflows/build_docker.yaml
									
									
									
									
										vendored
									
									
								
							| @@ -1,33 +1,30 @@ | ||||
| name: Build and Push Docker Image | ||||
|  | ||||
| on: | ||||
|   workflow_run: | ||||
|     workflows: ["Build and Release"] | ||||
|     types: | ||||
|       - completed | ||||
|   workflow_dispatch: | ||||
|  | ||||
| jobs: | ||||
|   build: | ||||
|     runs-on: ubuntu-latest | ||||
|     permissions: | ||||
|       contents: read | ||||
|       packages: write | ||||
|     steps: | ||||
|       - name: Checkout repository | ||||
|         uses: actions/checkout@v2 | ||||
|  | ||||
|       - name: Set up QEMU | ||||
|         uses: docker/setup-qemu-action@v2 | ||||
|         with: | ||||
|           platforms: all | ||||
|  | ||||
|       - name: Set up Docker Buildx | ||||
|         uses: docker/setup-buildx-action@v2 | ||||
|  | ||||
|       - name: Log in to Docker Hub | ||||
|         uses: docker/login-action@v2 | ||||
|         with: | ||||
|           username: ${{ secrets.DOCKER_USERNAME }} | ||||
|           password: ${{ secrets.DOCKER_PASSWORD }} | ||||
|  | ||||
|       # - name: Login to CNB Registry | ||||
|       #   uses: docker/login-action@v2 | ||||
|       #   with: | ||||
| @@ -41,7 +38,14 @@ jobs: | ||||
|           registry: crpi-8tmognxgyb86bm61.cn-guangzhou.personal.cr.aliyuncs.com | ||||
|           username: ${{ secrets.ALIYUN_USERNAME }} | ||||
|           password: ${{ secrets.ALIYUN_PASSWORD }} | ||||
|  | ||||
|        | ||||
|       - name: Log in to GitHub Container Registry | ||||
|         uses: docker/login-action@v2 | ||||
|         with: | ||||
|           registry: ghcr.io | ||||
|           username: ${{ github.actor }} | ||||
|           password: ${{ secrets.GITHUB_TOKEN }} | ||||
|        | ||||
|       - name: Build and push Docker images | ||||
|         uses: docker/build-push-action@v4 | ||||
|         with: | ||||
| @@ -54,3 +58,4 @@ jobs: | ||||
|           tags: | | ||||
|             ${{ secrets.DOCKER_USERNAME }}/goecs:latest | ||||
|             crpi-8tmognxgyb86bm61.cn-guangzhou.personal.cr.aliyuncs.com/oneclickvirt/ecs:latest | ||||
|             ghcr.io/${{ github.repository_owner }}/goecs:latest | ||||
|   | ||||
							
								
								
									
										108
									
								
								.github/workflows/build_public.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								.github/workflows/build_public.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | ||||
| name: Public Build | ||||
| on: | ||||
|   workflow_run: | ||||
|     workflows: ["Build and Release"] | ||||
|     types: | ||||
|       - completed | ||||
|   workflow_dispatch: | ||||
| jobs: | ||||
|   build: | ||||
|     runs-on: ubuntu-latest | ||||
|      | ||||
|     steps: | ||||
|     - uses: actions/checkout@v4 | ||||
|       with: | ||||
|         fetch-depth: 0 | ||||
|     - name: Set up Go | ||||
|       uses: actions/setup-go@v5 | ||||
|       with: | ||||
|         go-version: '1.24.5' | ||||
|          | ||||
|     - name: Update master branch README files | ||||
|       run: | | ||||
|         git config --global user.name 'GitHub Actions' | ||||
|         git config --global user.email 'actions@github.com' | ||||
|          | ||||
|         if [ -f "go.mod" ]; then | ||||
|           GO_VERSION=$(grep "^go " go.mod | head -n 1 | awk '{print $2}') | ||||
|           echo "提取到的 Go 版本: $GO_VERSION" | ||||
|           if [ -n "$GO_VERSION" ] && [[ "$GO_VERSION" =~ ^[0-9]+\.[0-9]+(\.[0-9]+)?$ ]]; then | ||||
|             echo "版本验证成功,开始替换..." | ||||
|             if [ -f "README.md" ]; then | ||||
|               sed -i "s/选择 go [0-9]\+\.[0-9]\+\.[0-9]\+ 的版本进行安装/选择 go $GO_VERSION 的版本进行安装/g" README.md | ||||
|               sed -i 's|但二进制文件编译至 \[securityCheck\].*)|但已开源|g' README.md | ||||
|               sed -i 's|security.*Enable/Disable security test (default true)|security        Enable/Disable security test (default false)|g' README.md | ||||
|               echo "已更新 README.md" | ||||
|             fi | ||||
|             if [ -f "README_EN.md" ]; then | ||||
|               sed -i "s/Select go [0-9]\+\.[0-9]\+\.[0-9]\+ version to install/Select go $GO_VERSION version to install/g" README_EN.md | ||||
|               sed -i 's|but binary files compiled in \[securityCheck\].*)|but open sourced|g' README_EN.md | ||||
|               sed -i 's|security.*Enable/Disable security test (default true)|security        Enable/Disable security test (default false)|g' README_EN.md | ||||
|               echo "已更新 README_EN.md" | ||||
|             fi | ||||
|             git add README.md README_EN.md | ||||
|             git commit -m "Auto update README files" || echo "No changes to commit" | ||||
|             git push origin ${{ github.ref_name }} | ||||
|           else | ||||
|             echo "错误:未能提取到有效的 Go 版本号或版本号格式不正确" | ||||
|             exit 1 | ||||
|           fi | ||||
|         else | ||||
|           echo "错误:未找到 go.mod 文件" | ||||
|           exit 1 | ||||
|         fi | ||||
|          | ||||
|     - name: Create public branch | ||||
|       run: | | ||||
|         git checkout -b public || git checkout public | ||||
|         git merge ${{ github.ref_name }} --no-edit || true | ||||
|          | ||||
|     - name: Remove security package references | ||||
|       run: | | ||||
|         find . -type f -name "*.go" -exec sed -i 's|"github.com/oneclickvirt/security/network"|"github.com/oneclickvirt/basics/network"|g' {} + | ||||
|         sed -i '/SecurityUploadToken/d' utils/utils.go | ||||
|         sed -i 's|"github.com/oneclickvirt/security/network"|"github.com/oneclickvirt/basics/network"|g' utils/utils.go | ||||
|         sed -i '/^import/,/^)/{/^)/a\'$'\n''const token = "OvwKx5qgJtf7PZgCKbtyojSU.MTcwMTUxNzY1MTgwMw"'$'\n''}' utils/utils.go | ||||
|         sed -i '/github.com\/oneclickvirt\/security/d' go.mod | ||||
|         sed -i 's|var securityFlag = flag.Bool("security", true,|var securityFlag = flag.Bool("security", false,|g' goecs.go | ||||
|         sed -i 's|VPS融合怪测试|VPS融合怪测试(非官方编译)|g' utils/utils.go | ||||
|         sed -i 's|VPS Fusion Monster Test|VPS Fusion Monster Test (Unofficial)|g' utils/utils.go | ||||
|         go mod tidy | ||||
|         sed -i 's|但二进制文件编译至 \[securityCheck\].*)|但已开源|g' README.md | ||||
|         sed -i 's|but binary files compiled in \[securityCheck\].*)|but open sourced|g' README_EN.md | ||||
|         sed -i 's|security.*Enable/Disable security test (default true)|security        Enable/Disable security test (default false)|g' README.md | ||||
|         sed -i 's|security.*Enable/Disable security test (default true)|security        Enable/Disable security test (default false)|g' README_EN.md | ||||
|     - name: Update Go version in README files | ||||
|       run: | | ||||
|         if [ -f "go.mod" ]; then | ||||
|           GO_VERSION=$(grep "^go " go.mod | head -n 1 | awk '{print $2}') | ||||
|           echo "提取到的 Go 版本: $GO_VERSION" | ||||
|           if [ -n "$GO_VERSION" ] && [[ "$GO_VERSION" =~ ^[0-9]+\.[0-9]+(\.[0-9]+)?$ ]]; then | ||||
|             echo "版本验证成功,开始替换..." | ||||
|             if [ -f "README.md" ]; then | ||||
|               sed -i "s/选择 go [0-9]\+\.[0-9]\+\.[0-9]\+ 的版本进行安装/选择 go $GO_VERSION 的版本进行安装/g" README.md | ||||
|               echo "已更新 README.md" | ||||
|             fi | ||||
|             if [ -f "README_EN.md" ]; then | ||||
|               sed -i "s/Select go [0-9]\+\.[0-9]\+\.[0-9]\+ version to install/Select go $GO_VERSION version to install/g" README_EN.md | ||||
|               echo "已更新 README_EN.md" | ||||
|             fi | ||||
|           else | ||||
|             echo "错误:未能提取到有效的 Go 版本号或版本号格式不正确" | ||||
|             exit 1 | ||||
|           fi | ||||
|         else | ||||
|           echo "错误:未找到 go.mod 文件" | ||||
|           exit 1 | ||||
|         fi | ||||
|     - name: Build and Test | ||||
|       run: | | ||||
|         go build -o maintest | ||||
|         ./maintest -menu=false -l en -security=false -upload=false || exit 1 | ||||
|         rm -rf maintest | ||||
|          | ||||
|     - name: Commit and push changes | ||||
|       run: | | ||||
|         git add . | ||||
|         git commit -m "Auto update public version (no security package)" || echo "No changes to commit" | ||||
|         git push -f origin public | ||||
							
								
								
									
										55
									
								
								.github/workflows/public_build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										55
									
								
								.github/workflows/public_build.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,55 +0,0 @@ | ||||
| name: Public Build | ||||
|  | ||||
| on: | ||||
|   workflow_run: | ||||
|     workflows: ["Build and Release"] | ||||
|     types: | ||||
|       - completed | ||||
|   workflow_dispatch: | ||||
|  | ||||
| jobs: | ||||
|   build: | ||||
|     runs-on: ubuntu-latest | ||||
|      | ||||
|     steps: | ||||
|     - uses: actions/checkout@v4 | ||||
|       with: | ||||
|         fetch-depth: 0 | ||||
|  | ||||
|     - name: Set up Go | ||||
|       uses: actions/setup-go@v5 | ||||
|       with: | ||||
|         go-version: '1.24.5' | ||||
|          | ||||
|     - name: Create public branch | ||||
|       run: | | ||||
|         git config --global user.name 'GitHub Actions' | ||||
|         git config --global user.email 'actions@github.com' | ||||
|         git checkout -b public || git checkout public | ||||
|         git merge ${{ github.ref_name }} --no-edit || true | ||||
|          | ||||
|     - name: Remove security package references | ||||
|       run: | | ||||
|         find . -type f -name "*.go" -exec sed -i 's|"github.com/oneclickvirt/security/network"|"github.com/oneclickvirt/basics/network"|g' {} + | ||||
|         sed -i '/SecurityUploadToken/d' utils/utils.go | ||||
|         sed -i 's|"github.com/oneclickvirt/security/network"|"github.com/oneclickvirt/basics/network"|g' utils/utils.go | ||||
|         sed -i '/^import/,/^)/{/^)/a\'$'\n''const token = "OvwKx5qgJtf7PZgCKbtyojSU.MTcwMTUxNzY1MTgwMw"'$'\n''}' utils/utils.go | ||||
|         sed -i '/github.com\/oneclickvirt\/security/d' go.mod | ||||
|         sed -i 's|var securityFlag = flag.Bool("security", true,|var securityFlag = flag.Bool("security", false,|g' goecs.go | ||||
|         go mod tidy | ||||
|         sed -i 's|但二进制文件编译至 \[securityCheck\].*)|但已开源|g' README.md | ||||
|         sed -i 's|but binary files compiled in \[securityCheck\].*)|but open sourced|g' README_EN.md | ||||
|         sed -i 's|security.*Enable/Disable security test (default true)|security        Enable/Disable security test (default false)|g' README.md | ||||
|         sed -i 's|security.*Enable/Disable security test (default true)|security        Enable/Disable security test (default false)|g' README_EN.md | ||||
|  | ||||
|     - name: Build and Test | ||||
|       run: | | ||||
|         go build -o maintest | ||||
|         ./maintest -menu=false -l en -security=false -upload=false || exit 1 | ||||
|         rm -rf maintest | ||||
|          | ||||
|     - name: Commit and push changes | ||||
|       run: | | ||||
|         git add . | ||||
|         git commit -m "Auto update public version (no security package)" || echo "No changes to commit" | ||||
|         git push -f origin public | ||||
							
								
								
									
										35
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								README.md
									
									
									
									
									
								
							| @@ -4,7 +4,7 @@ | ||||
|  | ||||
| [](https://app.fossa.com/projects/git%2Bgithub.com%2Foneclickvirt%2Fecs?ref=badge_shield) | ||||
|  | ||||
| [](https://hits.spiritlhl.net) | ||||
| [](https://hits.spiritlhl.net) [](https://github.com/oneclickvirt/ecs/releases) | ||||
|  | ||||
| 融合怪测评项目 - GO版本 | ||||
|  | ||||
| @@ -47,25 +47,24 @@ Shell 版本:[https://github.com/spiritLHLS/ecs](https://github.com/spiritLHLS | ||||
| |----------------|---------------------------| | ||||
| | Android(arm64) | 存在权限问题未修复,非安卓系统的ARM架构无问题      | | ||||
| | OpenBSD/NetBSD | 部分Goalng的官方库未支持本系统(尤其是net相关项目)  | | ||||
| | Windows虚拟机   | 非物理机器不支持winsat测试硬件性能(硬盘和内存测试) | | ||||
| | Windows物理机(非Admin下)   | 无Admin权限不支持winsat测试硬件性能(硬盘和内存测试) | | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## **功能** | ||||
|  | ||||
| - 系统基础信息查询,IP基础信息并发查询:[basics](https://github.com/oneclickvirt/basics)、[gostun](https://github.com/oneclickvirt/gostun) | ||||
| - CPU 测试:[cputest](https://github.com/oneclickvirt/cputest),支持 sysbench(lua/golang版本)、geekbench、winsat | ||||
| - 内存测试:[memorytest](https://github.com/oneclickvirt/memorytest),支持 sysbench、dd | ||||
| - 内存测试:[memorytest](https://github.com/oneclickvirt/memorytest),支持 sysbench、dd、winsat、mbw、stream | ||||
| - 硬盘测试:[disktest](https://github.com/oneclickvirt/disktest),支持 dd、fio、winsat | ||||
| - 流媒体解锁信息并发查询:[netflix-verify](https://github.com/sjlleo/netflix-verify) 等逻辑,开发至 [CommonMediaTests](https://github.com/oneclickvirt/CommonMediaTests) | ||||
| - 常见流媒体测试并发查询:[UnlockTests](https://github.com/oneclickvirt/UnlockTests),逻辑借鉴 [RegionRestrictionCheck](https://github.com/lmc999/RegionRestrictionCheck) 等 | ||||
| - IP 质量/安全信息并发查询:二进制文件编译至 [securityCheck](https://github.com/oneclickvirt/securityCheck) | ||||
| - 邮件端口测试:[portchecker](https://github.com/oneclickvirt/portchecker) | ||||
| - 三网回程测试:借鉴 [zhanghanyun/backtrace](https://github.com/zhanghanyun/backtrace),二次开发至 [oneclickvirt/backtrace](https://github.com/oneclickvirt/backtrace) | ||||
| - 上游及回程路由线路检测:借鉴 [zhanghanyun/backtrace](https://github.com/zhanghanyun/backtrace),二次开发至 [oneclickvirt/backtrace](https://github.com/oneclickvirt/backtrace) | ||||
| - 三网路由测试:基于 [NTrace-core](https://github.com/nxtrace/NTrace-core),二次开发至 [nt3](https://github.com/oneclickvirt/nt3) | ||||
| - 网速测试:基于 [speedtest.net](https://github.com/spiritLHLS/speedtest.net-CN-ID) 和 [speedtest.cn](https://github.com/spiritLHLS/speedtest.cn-CN-ID) 数据,开发至 [oneclickvirt/speedtest](https://github.com/oneclickvirt/speedtest) | ||||
| - 三网 Ping 值测试:借鉴 [ecsspeed](https://github.com/spiritLHLS/ecsspeed),二次开发至 [pingtest](https://github.com/oneclickvirt/pingtest) | ||||
| - 支持root或admin环境下测试,支持非root或非admin环境下测试,支持离线环境下进行测试,**暂未**支持无DNS环境下进行测试 | ||||
| - 支持root或admin环境下测试,支持非root或非admin环境下测试,支持离线环境下进行测试,**暂未**支持无DNS的在线环境下进行测试 | ||||
|  | ||||
| **本项目初次使用建议查看说明:[跳转](https://github.com/oneclickvirt/ecs/blob/master/README_NEW_USER.md)** | ||||
|  | ||||
| @@ -82,25 +81,25 @@ Shell 版本:[https://github.com/spiritLHLS/ecs](https://github.com/spiritLHLS | ||||
| - **国际用户无加速:** | ||||
|  | ||||
|   ```bash | ||||
|   export noninteractive=true && curl -L https://raw.githubusercontent.com/oneclickvirt/ecs/master/goecs.sh -o goecs.sh && chmod +x goecs.sh && bash goecs.sh env && bash goecs.sh install && goecs | ||||
|   export noninteractive=true && curl -L https://raw.githubusercontent.com/oneclickvirt/ecs/master/goecs.sh -o goecs.sh && chmod +x goecs.sh && ./goecs.sh env && ./goecs.sh install && goecs | ||||
|   ``` | ||||
|  | ||||
| - **国际/国内使用 CDN 加速:** | ||||
|  | ||||
|   ```bash | ||||
|   export noninteractive=true && curl -L https://cdn.spiritlhl.net/https://raw.githubusercontent.com/oneclickvirt/ecs/master/goecs.sh -o goecs.sh && chmod +x goecs.sh && bash goecs.sh env && bash goecs.sh install && goecs | ||||
|   export noninteractive=true && curl -L https://cdn.spiritlhl.net/https://raw.githubusercontent.com/oneclickvirt/ecs/master/goecs.sh -o goecs.sh && chmod +x goecs.sh && ./goecs.sh env && ./goecs.sh install && goecs | ||||
|   ``` | ||||
|  | ||||
| - **国内用户使用 CNB 加速:** | ||||
|  | ||||
|   ```bash | ||||
|   export noninteractive=true && curl -L https://cnb.cool/oneclickvirt/ecs/-/git/raw/main/goecs.sh -o goecs.sh && chmod +x goecs.sh && bash goecs.sh env && bash goecs.sh install && goecs | ||||
|   export noninteractive=true && curl -L https://cnb.cool/oneclickvirt/ecs/-/git/raw/main/goecs.sh -o goecs.sh && chmod +x goecs.sh && ./goecs.sh env && ./goecs.sh install && goecs | ||||
|   ``` | ||||
|  | ||||
| - **短链接:** | ||||
|  | ||||
|   ```bash | ||||
|   export noninteractive=true && curl -L https://bash.spiritlhl.net/goecs -o goecs.sh && chmod +x goecs.sh && bash goecs.sh env && bash goecs.sh install && goecs | ||||
|   export noninteractive=true && curl -L https://bash.spiritlhl.net/goecs -o goecs.sh && chmod +x goecs.sh && ./goecs.sh env && ./goecs.sh install && goecs | ||||
|   ``` | ||||
|  | ||||
| #### **详细说明** | ||||
| @@ -243,6 +242,8 @@ Usage: goecs [options] | ||||
| 1. 下载带 exe 文件的压缩包:[Releases](https://github.com/oneclickvirt/ecs/releases) | ||||
| 2. 解压后,右键以管理员模式运行。 | ||||
|  | ||||
| PS:如果是虚拟机环境,不以管理员模式运行也行,因为虚拟机无原生的测试工具,将自动启用替代方法测试。 | ||||
|  | ||||
| --- | ||||
|  | ||||
| ### **Docker** | ||||
| @@ -302,11 +303,11 @@ cd ecs | ||||
| ``` | ||||
|  | ||||
| 2. 安装 Go 环境(如已安装可跳过) | ||||
|  | ||||
| 选择 go 1.24.5 的版本进行安装 | ||||
|  | ||||
| ```bash | ||||
| # 下载并安装 Go | ||||
| wget https://go.dev/dl/go1.23.4.linux-amd64.tar.gz | ||||
| rm -rf /usr/local/go && tar -C /usr/local -xzf go1.23.4.linux-amd64.tar.gz | ||||
| export PATH=$PATH:/usr/local/go/bin | ||||
| curl -L https://cdn.spiritlhl.net/https://raw.githubusercontent.com/spiritLHLS/one-click-installation-script/main/install_scripts/go.sh -o go.sh && chmod +x go.sh && bash go.sh  | ||||
| ``` | ||||
|  | ||||
| 3. 编译 | ||||
| @@ -374,7 +375,7 @@ GOOS=darwin GOARCH=amd64 go build -o goecs_darwin | ||||
|  | ||||
| ## 致谢 | ||||
|  | ||||
| 感谢 [he.net](https://he.net) [bgp.tools](https://bgp.tools) [ipinfo.io](https://ipinfo.io) [maxmind.com](https://www.maxmind.com/en/home) [cloudflare.com](https://www.cloudflare.com/) [ip.sb](https://ip.sb) [scamalytics.com](https://scamalytics.com) [abuseipdb.com](https://www.abuseipdb.com/) [ip2location.com](https://ip2location.com/) [ip-api.com](https://ip-api.com) [ipregistry.co](https://ipregistry.co/) [ipdata.co](https://ipdata.co/) [ipgeolocation.io](https://ipgeolocation.io) [ipwhois.io](https://ipwhois.io) [ipapi.com](https://ipapi.com/) [ipapi.is](https://ipapi.is/) [ipqualityscore.com](https://www.ipqualityscore.com/) [bigdatacloud.com](https://www.bigdatacloud.com/) [dkly.net](https://data.dkly.net) [virustotal.com](https://www.virustotal.com/) 等网站提供的API进行检测,感谢互联网各网站提供的查询资源 | ||||
| 感谢 [he.net](https://he.net) [bgp.tools](https://bgp.tools) [ipinfo.io](https://ipinfo.io) [maxmind.com](https://www.maxmind.com/en/home) [cloudflare.com](https://www.cloudflare.com/) [ip.sb](https://ip.sb) [scamalytics.com](https://scamalytics.com) [abuseipdb.com](https://www.abuseipdb.com/) [ip2location.com](https://ip2location.com/) [ip-api.com](https://ip-api.com) [ipregistry.co](https://ipregistry.co/) [ipdata.co](https://ipdata.co/) [ipgeolocation.io](https://ipgeolocation.io) [ipwhois.io](https://ipwhois.io) [ipapi.com](https://ipapi.com/) [ipapi.is](https://ipapi.is/) [ipqualityscore.com](https://www.ipqualityscore.com/) [bigdatacloud.com](https://www.bigdatacloud.com/) [dkly.net](https://data.dkly.net) [virustotal.com](https://www.virustotal.com/) [ipfighter.com](https://ipfighter.com/) [getipintel.net](http://check.getipintel.net/) [fraudlogix.com](https://fraudlogix.com) 等网站提供的API进行检测,感谢互联网各网站提供的查询资源 | ||||
|  | ||||
| 感谢 | ||||
|  | ||||
| @@ -398,6 +399,10 @@ GOOS=darwin GOARCH=amd64 go build -o goecs_darwin | ||||
|   <img src="https://console.zmto.com/templates/2019/dist/images/logo_dark.svg" alt="zmto" style="height: 50px;"> | ||||
| </a> | ||||
|  | ||||
| ## History Usage | ||||
|  | ||||
|  | ||||
|  | ||||
| ## Stargazers over time | ||||
|  | ||||
| [](https://www.spiritlhl.net) | ||||
|   | ||||
							
								
								
									
										38
									
								
								README_EN.md
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								README_EN.md
									
									
									
									
									
								
							| @@ -1,8 +1,10 @@ | ||||
| # ecs | ||||
| # ECS | ||||
|  | ||||
| [](https://github.com/oneclickvirt/ecs/actions/workflows/build_binary.yaml) | ||||
|  | ||||
| [](https://hits.spiritlhl.net) | ||||
| [](https://app.fossa.com/projects/git%2Bgithub.com%2Foneclickvirt%2Fecs?ref=badge_shield) | ||||
|  | ||||
| [](https://hits.spiritlhl.net) [](https://github.com/oneclickvirt/ecs/releases) | ||||
|  | ||||
| Fusion Monster Evaluation Project - GO Version | ||||
|  | ||||
| @@ -45,8 +47,6 @@ Shell version: [https://github.com/spiritLHLS/ecs/blob/main/README_EN.md](https: | ||||
| |--------|-------------------------------------------------------------------------------------------------| | ||||
| | Android(arm64) | Permission issues that are not fixed, no problems with ARM architecture for non-Android systems    | | ||||
| | OpenBSD/NetBSD | Some of Goalng's official libraries do not support this system (especially net-related items) | | ||||
| | Windows(Virtual Machines) | Non-Physical Machines do not support winsat to test hardware performance (hard disk and memory tests) |  | ||||
| | Windows(Physical Machines)(not under Admin) | No Admin privileges do not support winsat to test hardware performance (hard disk and memory tests) | | ||||
|  | ||||
| --- | ||||
|  | ||||
| @@ -54,7 +54,7 @@ Shell version: [https://github.com/spiritLHLS/ecs/blob/main/README_EN.md](https: | ||||
|  | ||||
| - System basic information query and concurrent IP basic information query: Self-developed [basics](https://github.com/oneclickvirt/basics), [gostun](https://github.com/oneclickvirt/gostun) | ||||
| - CPU test: Self-developed [cputest](https://github.com/oneclickvirt/cputest) supporting sysbench(lua/golang version), geekbench, winsat | ||||
| - Memory test: Self-developed [memorytest](https://github.com/oneclickvirt/memorytest) supporting sysbench, dd | ||||
| - Memory test: Self-developed [memorytest](https://github.com/oneclickvirt/memorytest) supporting sysbench, dd, winsat, mbw, stream | ||||
| - Disk test: Self-developed [disktest](https://github.com/oneclickvirt/disktest) supporting dd, fio, winsat | ||||
| - Streaming media unlock information concurrent query: Modified from [netflix-verify](https://github.com/sjlleo/netflix-verify) and more to [CommonMediaTests](https://github.com/oneclickvirt/CommonMediaTests) | ||||
| - Common streaming media tests concurrent query: Self-developed to [UnlockTests](https://github.com/oneclickvirt/UnlockTests), logic modified from [RegionRestrictionCheck](https://github.com/lmc999/RegionRestrictionCheck) and others | ||||
| @@ -64,7 +64,7 @@ Shell version: [https://github.com/spiritLHLS/ecs/blob/main/README_EN.md](https: | ||||
| - Three-network route test: Modified from [NTrace-core](https://github.com/nxtrace/NTrace-core) to [nt3](https://github.com/oneclickvirt/nt3) | ||||
| - Speed test: Based on data from [speedtest.net](https://github.com/spiritLHLS/speedtest.net-CN-ID) and [speedtest.cn](https://github.com/spiritLHLS/speedtest.cn-CN-ID), developed to [oneclickvirt/speedtest](https://github.com/oneclickvirt/speedtest) | ||||
| - Three-network Ping test: Modified from [ecsspeed](https://github.com/spiritLHLS/ecsspeed) to [pingtest](https://github.com/oneclickvirt/pingtest) | ||||
| - Support root or admin environment testing, support non-root or non-admin environment testing, support offline environment for testing, not support no DNS environment for testing | ||||
| - Support root or admin environment testing, support non-root or non-admin environment testing, support offline environment for testing, **not yet** support no DNS online environment for testing | ||||
|  | ||||
| **For first-time users of this project, it is recommended to check the instructions: [Jump to](https://github.com/oneclickvirt/ecs/blob/master/README_NEW_USER.md)** | ||||
|  | ||||
| @@ -81,19 +81,19 @@ Shell version: [https://github.com/spiritLHLS/ecs/blob/main/README_EN.md](https: | ||||
| - **International users without acceleration:** | ||||
|  | ||||
|   ```bash | ||||
|   export noninteractive=true && curl -L https://raw.githubusercontent.com/oneclickvirt/ecs/master/goecs.sh -o goecs.sh && chmod +x goecs.sh && bash goecs.sh env && bash goecs.sh install && goecs -l en | ||||
|   export noninteractive=true && curl -L https://raw.githubusercontent.com/oneclickvirt/ecs/master/goecs.sh -o goecs.sh && chmod +x goecs.sh && ./goecs.sh env && ./goecs.sh install && goecs | ||||
|   ``` | ||||
|  | ||||
| - **International/domestic users with CDN acceleration:** | ||||
|  | ||||
|   ```bash | ||||
|   export noninteractive=true && curl -L https://cdn.spiritlhl.net/https://raw.githubusercontent.com/oneclickvirt/ecs/master/goecs.sh -o goecs.sh && chmod +x goecs.sh && bash goecs.sh env && bash goecs.sh install && goecs -l en | ||||
|   export noninteractive=true && curl -L https://cdn.spiritlhl.net/https://raw.githubusercontent.com/oneclickvirt/ecs/master/goecs.sh -o goecs.sh && chmod +x goecs.sh && ./goecs.sh env && ./goecs.sh install && goecs | ||||
|   ``` | ||||
|  | ||||
| - **Domestic users with CNB acceleration:** | ||||
|  | ||||
|   ```bash | ||||
|   export noninteractive=true && curl -L https://cnb.cool/oneclickvirt/ecs/-/git/raw/main/goecs.sh -o goecs.sh && chmod +x goecs.sh && bash goecs.sh env && bash goecs.sh install && goecs -l en | ||||
|   export noninteractive=true && curl -L https://cnb.cool/oneclickvirt/ecs/-/git/raw/main/goecs.sh -o goecs.sh && chmod +x goecs.sh && ./goecs.sh env && ./goecs.sh install && goecs | ||||
|   ``` | ||||
|  | ||||
| - **Short Link:** | ||||
| @@ -241,6 +241,8 @@ Usage: goecs [options] | ||||
| 1. Download the compressed file with the .exe file: [Releases](https://github.com/oneclickvirt/ecs/releases) | ||||
| 2. After unzipping, right-click and run as administrator. | ||||
|  | ||||
| PS: If it's a VM environment, it's OK not to run it in administrator mode, because VMs have no native testing tools and will automatically enable alternative methods for testing. | ||||
|  | ||||
| --- | ||||
|  | ||||
| ### **Docker** | ||||
| @@ -298,11 +300,11 @@ cd ecs | ||||
| ``` | ||||
|  | ||||
| 2. Install Go environment (skip if already installed) | ||||
|  | ||||
| Select go 1.24.5 version to install  | ||||
|  | ||||
| ```bash | ||||
| # Download and install Go | ||||
| wget https://go.dev/dl/go1.23.4.linux-amd64.tar.gz | ||||
| rm -rf /usr/local/go && tar -C /usr/local -xzf go1.23.4.linux-amd64.tar.gz | ||||
| export PATH=$PATH:/usr/local/go/bin | ||||
| curl -L https://cdn.spiritlhl.net/https://raw.githubusercontent.com/spiritLHLS/one-click-installation-script/main/install_scripts/go.sh -o go.sh && chmod +x go.sh && bash go.sh  | ||||
| ``` | ||||
|  | ||||
| 3. Compile | ||||
| @@ -344,6 +346,7 @@ GOOS=darwin GOARCH=amd64 go build -o goecs_darwin | ||||
| | Test stability | Core test components unchanged for 10+ years | Each major version updates test items, making scores hard to compare between versions (each version benchmarks against current best CPUs) | | ||||
| | Test content | Only tests computing performance | Covers multiple performance aspects with weighted scores, though some tests aren't commonly used | | ||||
| | Suitable scenarios | Good for quick tests, focuses on computing performance | Good for comprehensive testing | | ||||
| | Ranking         | [sysbench.spiritlhl.net](https://sysbench.spiritlhl.net/) | [browser.geekbench.com](https://browser.geekbench.com/) | | ||||
|  | ||||
| Note that `goecs` allows you to specify CPU test method via parameters. The default is chosen for faster testing across more systems. | ||||
|  | ||||
| @@ -369,7 +372,7 @@ Note that `goecs` allows you to specify CPU test method via parameters. The defa | ||||
|  | ||||
| ## Thanks | ||||
|  | ||||
| Thank [he.net](https://he.net) [bgp.tools](https://bgp.tools) [ipinfo.io](https://ipinfo.io) [maxmind.com](https://www.maxmind.com/en/home) [cloudflare.com](https://www.cloudflare.com/) [ip.sb](https://ip.sb) [scamalytics.com](https://scamalytics.com) [abuseipdb.com](https://www.abuseipdb.com/) [ip2location.com](https://ip2location.com/) [ip-api.com](https://ip-api.com) [ipregistry.co](https://ipregistry.co/) [ipdata.co](https://ipdata.co/) [ipgeolocation.io](https://ipgeolocation.io) [ipwhois.io](https://ipwhois.io) [ipapi.com](https://ipapi.com/) [ipapi.is](https://ipapi.is/) [ipqualityscore.com](https://www.ipqualityscore.com/) [bigdatacloud.com](https://www.bigdatacloud.com/) [dkly.net](https://data.dkly.net) [virustotal.com](https://www.virustotal.com/) and others for providing APIs for testing, and thanks to various websites on the Internet for providing query resources. | ||||
| Thank [he.net](https://he.net) [bgp.tools](https://bgp.tools) [ipinfo.io](https://ipinfo.io) [maxmind.com](https://www.maxmind.com/en/home) [cloudflare.com](https://www.cloudflare.com/) [ip.sb](https://ip.sb) [scamalytics.com](https://scamalytics.com) [abuseipdb.com](https://www.abuseipdb.com/) [ip2location.com](https://ip2location.com/) [ip-api.com](https://ip-api.com) [ipregistry.co](https://ipregistry.co/) [ipdata.co](https://ipdata.co/) [ipgeolocation.io](https://ipgeolocation.io) [ipwhois.io](https://ipwhois.io) [ipapi.com](https://ipapi.com/) [ipapi.is](https://ipapi.is/) [ipqualityscore.com](https://www.ipqualityscore.com/) [bigdatacloud.com](https://www.bigdatacloud.com/) [dkly.net](https://data.dkly.net) [virustotal.com](https://www.virustotal.com/) [ipfighter.com](https://ipfighter.com/) [getipintel.net](http://check.getipintel.net/) [fraudlogix.com](https://fraudlogix.com) and others for providing APIs for testing, and thanks to various websites on the Internet for providing query resources. | ||||
|  | ||||
| Thank | ||||
|  | ||||
| @@ -393,6 +396,13 @@ Thanks also to the following platforms for editorial and testing support | ||||
|   <img src="https://console.zmto.com/templates/2019/dist/images/logo_dark.svg" alt="zmto" style="height: 50px;"> | ||||
| </a> | ||||
|  | ||||
| ## History Usage | ||||
|  | ||||
|  | ||||
|  | ||||
| ## Stargazers over time | ||||
|  | ||||
| [](https://www.spiritlhl.net) | ||||
|  | ||||
| ## License | ||||
| [](https://app.fossa.com/projects/git%2Bgithub.com%2Foneclickvirt%2Fecs?ref=badge_large) | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -8,36 +8,30 @@ import ( | ||||
| ) | ||||
|  | ||||
| func DiskTest(language, testMethod, testPath string, isMultiCheck bool, autoChange bool) (realTestMethod, res string) { | ||||
| 	if runtime.GOOS == "windows" { | ||||
| 		if testMethod != "winsat" && testMethod != "" { | ||||
| 			// res = "Detected host is Windows, using Winsat for testing.\n" | ||||
| 			realTestMethod = "winsat" | ||||
| 		} | ||||
| 		res = disk.WinsatTest(language, isMultiCheck, testPath) | ||||
| 	} else { | ||||
| 		switch testMethod { | ||||
| 		case "fio": | ||||
| 			res = disk.FioTest(language, isMultiCheck, testPath) | ||||
| 			if res == "" && autoChange { | ||||
| 				// res = "Fio test failed, switching to DD for testing.\n" | ||||
| 				res += disk.DDTest(language, isMultiCheck, testPath) | ||||
| 				realTestMethod = "dd" | ||||
| 			} else { | ||||
| 				realTestMethod = "fio" | ||||
| 			} | ||||
| 		case "dd": | ||||
| 			res = disk.DDTest(language, isMultiCheck, testPath) | ||||
| 			if res == "" && autoChange { | ||||
| 				// res = "DD test failed, switching to Fio for testing.\n" | ||||
| 				res += disk.FioTest(language, isMultiCheck, testPath) | ||||
| 				realTestMethod = "fio" | ||||
| 			} else { | ||||
| 				realTestMethod = "dd" | ||||
| 			} | ||||
| 		default: | ||||
| 			// res = "Unsupported test method specified, switching to DD for testing.\n" | ||||
| 	switch testMethod { | ||||
| 	case "fio": | ||||
| 		res = disk.FioTest(language, isMultiCheck, testPath) | ||||
| 		if res == "" && autoChange { | ||||
| 			res += disk.DDTest(language, isMultiCheck, testPath) | ||||
| 			realTestMethod = "dd" | ||||
| 		} else { | ||||
| 			realTestMethod = "fio" | ||||
| 		} | ||||
| 	case "dd": | ||||
| 		res = disk.DDTest(language, isMultiCheck, testPath) | ||||
| 		if res == "" && autoChange { | ||||
| 			res += disk.FioTest(language, isMultiCheck, testPath) | ||||
| 			realTestMethod = "fio" | ||||
| 		} else { | ||||
| 			realTestMethod = "dd" | ||||
| 		} | ||||
| 	default: | ||||
| 		if runtime.GOOS == "windows" { | ||||
| 			realTestMethod = "winsat" | ||||
| 			res = disk.WinsatTest(language, isMultiCheck, testPath) | ||||
| 		} else { | ||||
| 			res = disk.DDTest(language, isMultiCheck, testPath) | ||||
| 			realTestMethod = "dd" | ||||
| 		} | ||||
| 	} | ||||
| 	if !strings.Contains(res, "\n") && res != "" { | ||||
|   | ||||
							
								
								
									
										21
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								go.mod
									
									
									
									
									
								
							| @@ -5,18 +5,18 @@ go 1.24.5 | ||||
| require ( | ||||
| 	github.com/imroc/req/v3 v3.54.0 | ||||
| 	github.com/oneclickvirt/CommonMediaTests v0.0.4-20250329123841 | ||||
| 	github.com/oneclickvirt/UnlockTests v0.0.28-20250727155204 | ||||
| 	github.com/oneclickvirt/backtrace v0.0.5-20250727160732 | ||||
| 	github.com/oneclickvirt/basics v0.0.15-20250728021329 | ||||
| 	github.com/oneclickvirt/UnlockTests v0.0.29-20251030094944 | ||||
| 	github.com/oneclickvirt/backtrace v0.0.7-20250811023541 | ||||
| 	github.com/oneclickvirt/basics v0.0.16-20251030093657 | ||||
| 	github.com/oneclickvirt/cputest v0.0.12-20250720122317 | ||||
| 	github.com/oneclickvirt/defaultset v0.0.2-20240624082446 | ||||
| 	github.com/oneclickvirt/disktest v0.0.8-20250701092629 | ||||
| 	github.com/oneclickvirt/disktest v0.0.10-20250924030424 | ||||
| 	github.com/oneclickvirt/gostun v0.0.5-20250727155022 | ||||
| 	github.com/oneclickvirt/memorytest v0.0.9-20250720135728 | ||||
| 	github.com/oneclickvirt/nt3 v0.0.6-20250726150925 | ||||
| 	github.com/oneclickvirt/memorytest v0.0.10-20250924154648 | ||||
| 	github.com/oneclickvirt/nt3 v0.0.8-20250811123903 | ||||
| 	github.com/oneclickvirt/pingtest v0.0.8-20250728015259 | ||||
| 	github.com/oneclickvirt/portchecker v0.0.3-20250728015900 | ||||
| 	github.com/oneclickvirt/security v0.0.6-20250727160145 | ||||
| 	github.com/oneclickvirt/security v0.0.7-20251030094114 | ||||
| 	github.com/oneclickvirt/speedtest v0.0.10-20250728015734 | ||||
| ) | ||||
|  | ||||
| @@ -58,9 +58,10 @@ require ( | ||||
| 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect | ||||
| 	github.com/modern-go/reflect2 v1.0.2 // indirect | ||||
| 	github.com/nxtrace/NTrace-core v1.4.2 // indirect | ||||
| 	github.com/oneclickvirt/dd v0.0.2-20250701085922 // indirect | ||||
| 	github.com/oneclickvirt/fio v0.0.2-20250701085933 // indirect | ||||
| 	github.com/oneclickvirt/mbw v0.0.1-20250630140849 // indirect | ||||
| 	github.com/oneclickvirt/dd v0.0.2-20250808062818 // indirect | ||||
| 	github.com/oneclickvirt/fio v0.0.2-20250808045755 // indirect | ||||
| 	github.com/oneclickvirt/mbw v0.0.1-20250808061222 // indirect | ||||
| 	github.com/oneclickvirt/stream v0.0.2-20250924154001 // indirect | ||||
| 	github.com/oschwald/maxminddb-golang v1.13.1 // indirect | ||||
| 	github.com/pelletier/go-toml/v2 v2.2.4 // indirect | ||||
| 	github.com/pion/dtls/v2 v2.2.7 // indirect | ||||
|   | ||||
							
								
								
									
										42
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								go.sum
									
									
									
									
									
								
							| @@ -96,38 +96,40 @@ github.com/nxtrace/NTrace-core v1.4.2 h1:dSRP18Bn3VGf5CZBzKt8gQWW9mDkq62Np9TCF9R | ||||
| github.com/nxtrace/NTrace-core v1.4.2/go.mod h1:wIDOlccuYzY3wBqU89pv2KGHT41i3JA0eRqJU/x9eX4= | ||||
| github.com/oneclickvirt/CommonMediaTests v0.0.4-20250329123841 h1:Zef93z9UiZQwRAKnnZYALmpBKvvuVaq34MEsuWwk6nc= | ||||
| github.com/oneclickvirt/CommonMediaTests v0.0.4-20250329123841/go.mod h1:DAmFPRjFV5p9fEzUUSml5jJGn2f1NZJQCzTxITHDjc4= | ||||
| github.com/oneclickvirt/UnlockTests v0.0.28-20250727155204 h1:apFaEbHGKflYMZzK17nXzEai4GG873mTd+d9hCO/KdY= | ||||
| github.com/oneclickvirt/UnlockTests v0.0.28-20250727155204/go.mod h1:oOa6wj/qECtRMxwBO6D7o0L0F0Q/5sQ747OCnFQqoGE= | ||||
| github.com/oneclickvirt/backtrace v0.0.5-20250727160732 h1:izs46j9hYYOOXcdtBX7y9PSlzLlxWSiC2+4rQ8P0DxA= | ||||
| github.com/oneclickvirt/backtrace v0.0.5-20250727160732/go.mod h1:yxL1ixDmOmEt8NkHnMIetsTXJW8xMslUpEY2L8sYZ4Y= | ||||
| github.com/oneclickvirt/basics v0.0.15-20250728021329 h1:bXat5W1twZdOdzJ15BFZUYsjAEcTH9ly9oMDIg5+Rbo= | ||||
| github.com/oneclickvirt/basics v0.0.15-20250728021329/go.mod h1:2PV+1ge01zb0Sqzj2V2I7P0wAdFSLF1XgAiumchJJbg= | ||||
| github.com/oneclickvirt/UnlockTests v0.0.29-20251030094944 h1:c81MmwD3yO/7kkKN+j88VfBuRQcr3zKp0wGTu1zjUug= | ||||
| github.com/oneclickvirt/UnlockTests v0.0.29-20251030094944/go.mod h1:oOa6wj/qECtRMxwBO6D7o0L0F0Q/5sQ747OCnFQqoGE= | ||||
| github.com/oneclickvirt/backtrace v0.0.7-20250811023541 h1:GzkzvUC6U9b6Dkz/Bl4JRPeQ7XBGoW7Qw1aWqzhF+MQ= | ||||
| github.com/oneclickvirt/backtrace v0.0.7-20250811023541/go.mod h1:/+KUtOWz48TyiTTbhVTsp3D6b5WY+4pCgvFBYtUGtns= | ||||
| github.com/oneclickvirt/basics v0.0.16-20251030093657 h1:6SWWILNjJfMTXbspqYRpktUEOe/QIVhGonKO8ODC7n4= | ||||
| github.com/oneclickvirt/basics v0.0.16-20251030093657/go.mod h1:2PV+1ge01zb0Sqzj2V2I7P0wAdFSLF1XgAiumchJJbg= | ||||
| github.com/oneclickvirt/cputest v0.0.12-20250720122317 h1:toiwAK1hZE5b8klu2mOQ7J4sv5yV9lpPKwgPahfRYBQ= | ||||
| github.com/oneclickvirt/cputest v0.0.12-20250720122317/go.mod h1:vjlH8tkPFft1tlLOpeNskXVvurxkHaJ3+dgFxQGLXY4= | ||||
| github.com/oneclickvirt/dd v0.0.2-20250701085922 h1:WiWZwcnCPhRc8hLZdvkjD2kOEpnqn1S31z1j0x3V4l0= | ||||
| github.com/oneclickvirt/dd v0.0.2-20250701085922/go.mod h1:tImu9sPTkLWo2tf1dEN1xQzrylWKauj9hbU8PHfyAeU= | ||||
| github.com/oneclickvirt/dd v0.0.2-20250808062818 h1:0KHrKkdpL5oBE1OHsrRd2siRw4/2k6f9LBaP7T4JpOc= | ||||
| github.com/oneclickvirt/dd v0.0.2-20250808062818/go.mod h1:tImu9sPTkLWo2tf1dEN1xQzrylWKauj9hbU8PHfyAeU= | ||||
| github.com/oneclickvirt/defaultset v0.0.2-20240624082446 h1:5Pg3mK/u/vQvSz7anu0nxzrNdELi/AcDAU1mMsmPzyc= | ||||
| github.com/oneclickvirt/defaultset v0.0.2-20240624082446/go.mod h1:e9Jt4tf2sbemCtc84/XgKcHy9EZ2jkc5x2sW1NiJS+E= | ||||
| github.com/oneclickvirt/disktest v0.0.8-20250701092629 h1:B/gA6SOr4qL5pQmVpHl9m5bn3paDcL7wJ1SZ7aY66M8= | ||||
| github.com/oneclickvirt/disktest v0.0.8-20250701092629/go.mod h1:6YCvGr+Z0tvcP4Ue8bezZqm/GqS/dSyEnSUhvS3Q03o= | ||||
| github.com/oneclickvirt/fio v0.0.2-20250701085933 h1:4P7QcOTxbqyx5DhHdFvyeRSsdNajSo9l/H2XK0vICIc= | ||||
| github.com/oneclickvirt/fio v0.0.2-20250701085933/go.mod h1:NIq+XYTey68KNERGIy/oRDlzpwLzBVoHOCiqX8didsE= | ||||
| github.com/oneclickvirt/disktest v0.0.10-20250924030424 h1:56Aq2xygO/vA/co5vJ7/MQTNijIDl8eYbVk8uCWN4mI= | ||||
| github.com/oneclickvirt/disktest v0.0.10-20250924030424/go.mod h1:Vp3iMVBD4ccReDJz5n5SlzUdq0kDuVhpRklQk21KT+8= | ||||
| github.com/oneclickvirt/fio v0.0.2-20250808045755 h1:eWihCRWcalJjPIdrF8dMe68ZiPnMkSfHC8ENvElp/xE= | ||||
| github.com/oneclickvirt/fio v0.0.2-20250808045755/go.mod h1:NIq+XYTey68KNERGIy/oRDlzpwLzBVoHOCiqX8didsE= | ||||
| github.com/oneclickvirt/gostun v0.0.5-20250727155022 h1:/e3gSUrOp1tg/1NTRx+P8B51OGcP26Q6//5EoSIjOvk= | ||||
| github.com/oneclickvirt/gostun v0.0.5-20250727155022/go.mod h1:pfp7MFZJK9n/KTLAVqqFcCAns4xqMykmjI+1UeF/vdE= | ||||
| github.com/oneclickvirt/mbw v0.0.1-20250630140849 h1:p6RMhOPBnQKAm9+VEQ2axAFsidrdSdrhXMyheIyv2a8= | ||||
| github.com/oneclickvirt/mbw v0.0.1-20250630140849/go.mod h1:0Vq6NRpyLmGUdfHfL3uDcFsuZhi7KlG+OCs5ky2757Y= | ||||
| github.com/oneclickvirt/memorytest v0.0.9-20250720135728 h1:RusZfaESDXK+k5YYfVXTCW5zLeQEd/dYY80a6xievE0= | ||||
| github.com/oneclickvirt/memorytest v0.0.9-20250720135728/go.mod h1:7xMacjQobvFAtODht2hxTsB9hM2IFS7vZk3gxx+bsjo= | ||||
| github.com/oneclickvirt/nt3 v0.0.6-20250726150925 h1:M+9kEpMp+O2a//yp9zJ11DleK7hxEmFd5jOWKNrSlmY= | ||||
| github.com/oneclickvirt/nt3 v0.0.6-20250726150925/go.mod h1:O7YkaOMFihB8hwQiD74WTbDlyoTieDwTDBR6jbkZaP0= | ||||
| github.com/oneclickvirt/mbw v0.0.1-20250808061222 h1:WGXOe6QvHiDRhPVMI0VcctjzW08kGvJf50yq5YeZCtw= | ||||
| github.com/oneclickvirt/mbw v0.0.1-20250808061222/go.mod h1:0Vq6NRpyLmGUdfHfL3uDcFsuZhi7KlG+OCs5ky2757Y= | ||||
| github.com/oneclickvirt/memorytest v0.0.10-20250924154648 h1:trk6oZ7xs1eVtr+6oIv5IX8LDVtEMG+E6GVzQ810BtU= | ||||
| github.com/oneclickvirt/memorytest v0.0.10-20250924154648/go.mod h1:4kiHsEWkW9r3/1ZcV5xIweU0smiKP0IRfQj74AUIiVI= | ||||
| github.com/oneclickvirt/nt3 v0.0.8-20250811123903 h1:ubSPLh/DSrXj+tOgmRABgi2vrVmbmjjSne+NrVFNmNc= | ||||
| github.com/oneclickvirt/nt3 v0.0.8-20250811123903/go.mod h1:F1v+6xInBKnbUa8gV1M40R1HOzxg+obtduNhx3CTnmA= | ||||
| github.com/oneclickvirt/pingtest v0.0.8-20250728015259 h1:egoxZRZBOWN3JqBwqEsULDyRo2/dpGMeWcmV3U87zig= | ||||
| github.com/oneclickvirt/pingtest v0.0.8-20250728015259/go.mod h1:gxwsxxwitNQiGq2OI0ZogYoOLwc8DtuOdSRe6/EvRqs= | ||||
| github.com/oneclickvirt/portchecker v0.0.3-20250728015900 h1:AomzdppSOFB70AJESQhlp0IPbsHTTJGimAWDk2TzCWM= | ||||
| github.com/oneclickvirt/portchecker v0.0.3-20250728015900/go.mod h1:9sjMDPCd4Z40wkYB0S9gQPGH8YPtnNE1ZJthVIuHUzA= | ||||
| github.com/oneclickvirt/security v0.0.6-20250727160145 h1://sqEyAITvv04zXZwWurTkMDMD4nUAl7Wukj5lEDALI= | ||||
| github.com/oneclickvirt/security v0.0.6-20250727160145/go.mod h1:WpzPJsQFP0uOHmUUsqT9sjNhD5b+1LFd90HiM8cz4nM= | ||||
| github.com/oneclickvirt/security v0.0.7-20251030094114 h1:Ax8J1TYqprXyiWNAIJJ3xhoyGhvBlKw4m9j6va5Q2nM= | ||||
| github.com/oneclickvirt/security v0.0.7-20251030094114/go.mod h1:YfDilPFW22szjdUNgv4VOuSwHnZzsFsdPOfRYiMoc3I= | ||||
| github.com/oneclickvirt/speedtest v0.0.10-20250728015734 h1:HKO7/JQ74ueXA8Wo8NIvcK9DphbEG/YTfAAVz/akSiY= | ||||
| github.com/oneclickvirt/speedtest v0.0.10-20250728015734/go.mod h1:0W8vnMbA3iucXLXFdGfe9Ia6RPS0izRO7jvu/SnH1P8= | ||||
| github.com/oneclickvirt/stream v0.0.2-20250924154001 h1:GuJWdiPkoK84+y/+oHKr2Ghl3c/MzS9Z5m1nM+lMmy4= | ||||
| github.com/oneclickvirt/stream v0.0.2-20250924154001/go.mod h1:oWaizaHTC2VQciBC9RfaLbAOf8qeR6n20/gY7QxriDE= | ||||
| github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE= | ||||
| github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8= | ||||
| github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= | ||||
|   | ||||
							
								
								
									
										186
									
								
								goecs.go
									
									
									
									
									
								
							
							
						
						
									
										186
									
								
								goecs.go
									
									
									
									
									
								
							| @@ -17,8 +17,6 @@ import ( | ||||
|  | ||||
| 	"github.com/oneclickvirt/CommonMediaTests/commediatests" | ||||
| 	unlocktestmodel "github.com/oneclickvirt/UnlockTests/model" | ||||
| 	"github.com/oneclickvirt/UnlockTests/uts" | ||||
| 	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,13 +24,14 @@ import ( | ||||
| 	"github.com/oneclickvirt/ecs/cputest" | ||||
| 	"github.com/oneclickvirt/ecs/disktest" | ||||
| 	"github.com/oneclickvirt/ecs/memorytest" | ||||
| 	"github.com/oneclickvirt/ecs/nexttrace" | ||||
| 	"github.com/oneclickvirt/ecs/speedtest" | ||||
| 	"github.com/oneclickvirt/ecs/unlocktest" | ||||
| 	"github.com/oneclickvirt/ecs/upstreams" | ||||
| 	"github.com/oneclickvirt/ecs/utils" | ||||
| 	gostunmodel "github.com/oneclickvirt/gostun/model" | ||||
| 	memorytestmodel "github.com/oneclickvirt/memorytest/memory" | ||||
| 	nt3model "github.com/oneclickvirt/nt3/model" | ||||
| 	"github.com/oneclickvirt/nt3/nt" | ||||
| 	ptmodel "github.com/oneclickvirt/pingtest/model" | ||||
| 	"github.com/oneclickvirt/pingtest/pt" | ||||
| 	"github.com/oneclickvirt/portchecker/email" | ||||
| @@ -40,7 +39,7 @@ import ( | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	ecsVersion                                                        = "v0.1.71" | ||||
| 	ecsVersion                                                        = "v0.1.91" | ||||
| 	menuMode                                                          bool | ||||
| 	onlyChinaTest                                                     bool | ||||
| 	input, choice                                                     string | ||||
| @@ -60,7 +59,7 @@ var ( | ||||
| 	autoChangeDiskTestMethod                                          = true | ||||
| 	filePath                                                          = "goecs.txt" | ||||
| 	enabelUpload                                                      = true | ||||
| 	help                                                              bool | ||||
| 	onlyIpInfoCheckStatus, help                                       bool | ||||
| 	goecsFlag                                                         = flag.NewFlagSet("goecs", flag.ContinueOnError) | ||||
| 	finish                                                            bool | ||||
| ) | ||||
| @@ -100,7 +99,7 @@ func getMenuChoice(language string) string { | ||||
| 			if re.MatchString(input) { | ||||
| 				inChoice := input | ||||
| 				switch inChoice { | ||||
| 				case "1", "2", "3", "4", "5", "6", "7", "8", "9", "10": | ||||
| 				case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10": | ||||
| 					return inChoice | ||||
| 				default: | ||||
| 					if language == "zh" { | ||||
| @@ -140,11 +139,11 @@ func parseFlags() { | ||||
| 	goecsFlag.BoolVar(&speedTestStatus, "speed", true, "Enable/Disable speed test") | ||||
| 	goecsFlag.StringVar(&cpuTestMethod, "cpum", "sysbench", "Set CPU test method (supported: sysbench, geekbench, winsat)") | ||||
| 	goecsFlag.StringVar(&cpuTestThreadMode, "cput", "multi", "Set CPU test thread mode (supported: single, multi)") | ||||
| 	goecsFlag.StringVar(&memoryTestMethod, "memorym", "sysbench", "Set memory test method (supported: sysbench, dd, winsat)") | ||||
| 	goecsFlag.StringVar(&memoryTestMethod, "memorym", "stream", "Set memory test method (supported: stream, sysbench, dd, winsat, auto)") | ||||
| 	goecsFlag.StringVar(&diskTestMethod, "diskm", "fio", "Set disk test method (supported: fio, dd, winsat)") | ||||
| 	goecsFlag.StringVar(&diskTestPath, "diskp", "", "Set disk test path, e.g., -diskp /root") | ||||
| 	goecsFlag.BoolVar(&diskMultiCheck, "diskmc", false, "Enable/Disable multiple disk checks, e.g., -diskmc=false") | ||||
| 	goecsFlag.StringVar(&nt3Location, "nt3loc", "GZ", "Specify NT3 test location (supported: GZ, SH, BJ, CD for Guangzhou, Shanghai, Beijing, Chengdu)") | ||||
| 	goecsFlag.StringVar(&nt3Location, "nt3loc", "GZ", "Specify NT3 test location (supported: GZ, SH, BJ, CD, ALL for Guangzhou, Shanghai, Beijing, Chengdu and all)") | ||||
| 	goecsFlag.StringVar(&nt3CheckType, "nt3t", "ipv4", "Set NT3 test type (supported: both, ipv4, ipv6)") | ||||
| 	goecsFlag.IntVar(&spNum, "spnum", 2, "Set the number of servers per operator for speed test") | ||||
| 	goecsFlag.BoolVar(&enableLogger, "log", false, "Enable/Disable logging in the current path") | ||||
| @@ -186,11 +185,13 @@ func handleMenuMode(preCheck utils.NetCheckResult) { | ||||
| 	commTestStatus, utTestStatus, securityTestStatus, emailTestStatus = false, false, false, false | ||||
| 	backtraceStatus, nt3Status, speedTestStatus = false, false, false | ||||
| 	autoChangeDiskTestMethod = true | ||||
| 	printMenuOptions() | ||||
| 	printMenuOptions(preCheck) | ||||
| Loop: | ||||
| 	for { | ||||
| 		choice = getMenuChoice(language) | ||||
| 		switch choice { | ||||
| 		case "0": | ||||
| 			os.Exit(0) | ||||
| 		case "1": | ||||
| 			setFullTestStatus(preCheck) | ||||
| 			onlyChinaTest = utils.CheckChina(enableLogger) | ||||
| @@ -236,6 +237,7 @@ Loop: | ||||
| 				fmt.Println("Can not test without network connection!") | ||||
| 				return | ||||
| 			} | ||||
| 			nt3Location = "ALL" | ||||
| 			setRouteTestStatus() | ||||
| 			break Loop | ||||
| 		default: | ||||
| @@ -244,23 +246,83 @@ Loop: | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func printMenuOptions() { | ||||
| func printMenuOptions(preCheck utils.NetCheckResult) { | ||||
| 	var stats *utils.StatsResponse | ||||
| 	var statsErr error | ||||
| 	var githubInfo *utils.GitHubRelease | ||||
| 	var githubErr error | ||||
| 	// 只有在网络连接正常时才获取统计信息和版本信息 | ||||
| 	if preCheck.Connected { | ||||
| 		var pwg sync.WaitGroup | ||||
| 		pwg.Add(2) | ||||
| 		go func() { | ||||
| 			defer pwg.Done() | ||||
| 			stats, statsErr = utils.GetGoescStats() | ||||
| 		}() | ||||
| 		go func() { | ||||
| 			defer pwg.Done() | ||||
| 			githubInfo, githubErr = utils.GetLatestEcsRelease() | ||||
| 		}() | ||||
| 		pwg.Wait() | ||||
| 	} else { | ||||
| 		statsErr = fmt.Errorf("network not connected") | ||||
| 		githubErr = fmt.Errorf("network not connected") | ||||
| 	} | ||||
| 	var statsInfo string | ||||
| 	var cmp int | ||||
| 	if preCheck.Connected { | ||||
| 		// 网络连接正常时处理统计信息和版本比较 | ||||
| 		if statsErr != nil { | ||||
| 			statsInfo = "NULL" | ||||
| 		} else { | ||||
| 			switch language { | ||||
| 			case "zh": | ||||
| 				statsInfo = fmt.Sprintf("总使用量: %s | 今日使用: %s", | ||||
| 					utils.FormatGoecsNumber(stats.Total), | ||||
| 					utils.FormatGoecsNumber(stats.Daily)) | ||||
| 			case "en": | ||||
| 				statsInfo = fmt.Sprintf("Total Usage: %s | Daily Usage: %s", | ||||
| 					utils.FormatGoecsNumber(stats.Total), | ||||
| 					utils.FormatGoecsNumber(stats.Daily)) | ||||
| 			} | ||||
| 		} | ||||
| 		if githubErr == nil { | ||||
| 			cmp = utils.CompareVersions(ecsVersion, githubInfo.TagName) | ||||
| 		} else { | ||||
| 			cmp = 0 | ||||
| 		} | ||||
| 	} | ||||
| 	switch language { | ||||
| 	case "zh": | ||||
| 		fmt.Println("VPS融合怪版本: ", ecsVersion) | ||||
| 		fmt.Println("1. 融合怪完全体") | ||||
| 		fmt.Printf("VPS融合怪版本: %s\n", ecsVersion) | ||||
| 		if preCheck.Connected { | ||||
| 			switch cmp { | ||||
| 			case -1: | ||||
| 				fmt.Printf("检测到新版本 %s 如有必要请更新!\n", githubInfo.TagName) | ||||
| 			} | ||||
| 			fmt.Printf("使用统计: %s\n", statsInfo) | ||||
| 		} | ||||
| 		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("6. 网络单项(IP质量检测+上游及三网回程+广州三网回程详细路由+全国延迟+测速节点11个)") | ||||
| 		fmt.Println("7. 解锁单项(御三家解锁+常用流媒体解锁)") | ||||
| 		fmt.Println("8. 硬件单项(系统信息+CPU+内存+dd磁盘测试+fio磁盘测试)") | ||||
| 		fmt.Println("9. IP质量检测(15个数据库的IP检测+邮件端口检测)") | ||||
| 		fmt.Println("10. 三网回程线路+广州三网路由+全国三网延迟") | ||||
| 		fmt.Println("8. 硬件单项(系统信息+CPU+dd磁盘测试+fio磁盘测试)") | ||||
| 		fmt.Println("9. IP质量检测(15个数据库的IP质量检测+邮件端口检测)") | ||||
| 		fmt.Println("10. 三网回程线路检测+三网回程详细路由(北京上海广州成都)+三网延迟测试(全国)") | ||||
| 		fmt.Println("0. 退出程序") | ||||
| 	case "en": | ||||
| 		fmt.Println("VPS Fusion Monster Test Version: ", ecsVersion) | ||||
| 		fmt.Println("1. VPS Fusion Monster Test Comprehensive Test Suite") | ||||
| 		fmt.Printf("VPS Fusion Monster Test Version: %s\n", ecsVersion) | ||||
| 		if preCheck.Connected { | ||||
| 			switch cmp { | ||||
| 			case -1: | ||||
| 				fmt.Printf("New version detected %s update if necessary!\n", githubInfo.TagName) | ||||
| 			} | ||||
| 			fmt.Printf("%s\n", statsInfo) | ||||
| 		} | ||||
| 		fmt.Println("1. VPS Fusion Monster Test (Full Test)") | ||||
| 		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)") | ||||
| @@ -269,6 +331,7 @@ func printMenuOptions() { | ||||
| 		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)") | ||||
| 		fmt.Println("0. Exit Program") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -335,16 +398,18 @@ func setUnlockFocusedTestStatus(preCheck utils.NetCheckResult) { | ||||
| } | ||||
|  | ||||
| func setNetworkOnlyTestStatus() { | ||||
| 	onlyIpInfoCheckStatus = true | ||||
| 	securityTestStatus = true | ||||
| 	speedTestStatus = true | ||||
| 	backtraceStatus = true | ||||
| 	nt3Status = true | ||||
| 	pingTestStatus = true | ||||
| } | ||||
|  | ||||
| func setUnlockOnlyTestStatus() { | ||||
| 	onlyIpInfoCheckStatus = true | ||||
| 	commTestStatus = true | ||||
| 	utTestStatus = true | ||||
| 	enabelUpload = false | ||||
| } | ||||
|  | ||||
| func setHardwareOnlyTestStatus(preCheck utils.NetCheckResult) { | ||||
| @@ -358,15 +423,16 @@ func setHardwareOnlyTestStatus(preCheck utils.NetCheckResult) { | ||||
| } | ||||
|  | ||||
| func setIPQualityTestStatus() { | ||||
| 	onlyIpInfoCheckStatus = true | ||||
| 	securityTestStatus = true | ||||
| 	emailTestStatus = true | ||||
| } | ||||
|  | ||||
| func setRouteTestStatus() { | ||||
| 	onlyIpInfoCheckStatus = true | ||||
| 	backtraceStatus = true | ||||
| 	nt3Status = true | ||||
| 	pingTestStatus = true | ||||
| 	enabelUpload = false | ||||
| } | ||||
|  | ||||
| func printInvalidChoice() { | ||||
| @@ -387,7 +453,7 @@ func handleLanguageSpecificSettings() { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func handleSignalInterrupt(sig chan os.Signal, startTime *time.Time, output *string, tempOutput string, uploadDone chan bool, outputMutex *sync.Mutex) { | ||||
| func handleSignalInterrupt(sig chan os.Signal, startTime *time.Time, output *string, _ string, uploadDone chan bool, outputMutex *sync.Mutex) { | ||||
| 	select { | ||||
| 	case <-sig: | ||||
| 		if !finish { | ||||
| @@ -468,11 +534,14 @@ func runChineseTests(preCheck utils.NetCheckResult, wg1, wg2, wg3 *sync.WaitGrou | ||||
| 	*output = runCPUTest(*output, tempOutput, outputMutex) | ||||
| 	*output = runMemoryTest(*output, tempOutput, outputMutex) | ||||
| 	*output = runDiskTest(*output, tempOutput, outputMutex) | ||||
| 	if (onlyChinaTest || pingTestStatus) && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" { | ||||
| 		wg3.Add(1) | ||||
| 	if onlyIpInfoCheckStatus && !basicStatus && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" { | ||||
| 		*output = runIpInfoCheck(*output, tempOutput, outputMutex) | ||||
| 	} | ||||
| 	if utTestStatus && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" && !onlyChinaTest { | ||||
| 		wg1.Add(1) | ||||
| 		go func() { | ||||
| 			defer wg3.Done() | ||||
| 			*ptInfo = pt.PingTest() | ||||
| 			defer wg1.Done() | ||||
| 			*mediaInfo = unlocktest.MediaTest(language) | ||||
| 		}() | ||||
| 	} | ||||
| 	if emailTestStatus && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" { | ||||
| @@ -482,11 +551,11 @@ func runChineseTests(preCheck utils.NetCheckResult, wg1, wg2, wg3 *sync.WaitGrou | ||||
| 			*emailInfo = email.EmailCheck() | ||||
| 		}() | ||||
| 	} | ||||
| 	if utTestStatus && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" && !onlyChinaTest { | ||||
| 		wg1.Add(1) | ||||
| 	if (onlyChinaTest || pingTestStatus) && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" { | ||||
| 		wg3.Add(1) | ||||
| 		go func() { | ||||
| 			defer wg1.Done() | ||||
| 			*mediaInfo = unlocktest.MediaTest(language) | ||||
| 			defer wg3.Done() | ||||
| 			*ptInfo = pt.PingTest() | ||||
| 		}() | ||||
| 	} | ||||
| 	if preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" { | ||||
| @@ -508,6 +577,9 @@ func runEnglishTests(preCheck utils.NetCheckResult, wg1, wg2 *sync.WaitGroup, ba | ||||
| 	*output = runCPUTest(*output, tempOutput, outputMutex) | ||||
| 	*output = runMemoryTest(*output, tempOutput, outputMutex) | ||||
| 	*output = runDiskTest(*output, tempOutput, outputMutex) | ||||
| 	if onlyIpInfoCheckStatus && !basicStatus && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" { | ||||
| 		*output = runIpInfoCheck(*output, tempOutput, outputMutex) | ||||
| 	} | ||||
| 	if preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" { | ||||
| 		if utTestStatus { | ||||
| 			wg1.Add(1) | ||||
| @@ -531,6 +603,24 @@ func runEnglishTests(preCheck utils.NetCheckResult, wg1, wg2 *sync.WaitGroup, ba | ||||
| 	*output = appendTimeInfo(*output, tempOutput, startTime, outputMutex) | ||||
| } | ||||
|  | ||||
| // runIpInfoCheck 系统和网络基础信息检测不进行测试的时候,该函数检测取得本机IP信息并显示(单项测试中输出) | ||||
| func runIpInfoCheck(output, tempOutput string, outputMutex *sync.Mutex) string { | ||||
| 	outputMutex.Lock() | ||||
| 	defer outputMutex.Unlock() | ||||
| 	return utils.PrintAndCapture(func() { | ||||
| 		var ipinfo string | ||||
| 		upstreams.IPV4, upstreams.IPV6, ipinfo = utils.OnlyBasicsIpInfo(language) | ||||
| 		if ipinfo != "" { | ||||
| 			if language == "zh" { | ||||
| 				utils.PrintCenteredTitle("IP信息", width) | ||||
| 			} else { | ||||
| 				utils.PrintCenteredTitle("IP-Information", width) | ||||
| 			} | ||||
| 			fmt.Printf("%s", ipinfo) | ||||
| 		} | ||||
| 	}, tempOutput, output) | ||||
| } | ||||
|  | ||||
| func runBasicTests(preCheck utils.NetCheckResult, basicInfo, securityInfo *string, output, tempOutput string, outputMutex *sync.Mutex) string { | ||||
| 	outputMutex.Lock() | ||||
| 	defer outputMutex.Unlock() | ||||
| @@ -545,13 +635,13 @@ func runBasicTests(preCheck utils.NetCheckResult, basicInfo, securityInfo *strin | ||||
| 				} | ||||
| 			} | ||||
| 			if preCheck.Connected && preCheck.StackType == "DualStack" { | ||||
| 				*basicInfo, *securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, nt3CheckType, securityTestStatus) | ||||
| 				upstreams.IPV4, upstreams.IPV6, *basicInfo, *securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, nt3CheckType, securityTestStatus) | ||||
| 			} else if preCheck.Connected && preCheck.StackType == "IPv4" { | ||||
| 				*basicInfo, *securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, "ipv4", securityTestStatus) | ||||
| 				upstreams.IPV4, upstreams.IPV6, *basicInfo, *securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, "ipv4", securityTestStatus) | ||||
| 			} else if preCheck.Connected && preCheck.StackType == "IPv6" { | ||||
| 				*basicInfo, *securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, "ipv6", securityTestStatus) | ||||
| 				upstreams.IPV4, upstreams.IPV6, *basicInfo, *securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, "ipv6", securityTestStatus) | ||||
| 			} else { | ||||
| 				*basicInfo, *securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, "", false) | ||||
| 				upstreams.IPV4, upstreams.IPV6, *basicInfo, *securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, "", false) | ||||
| 				securityTestStatus = false | ||||
| 			} | ||||
| 			if basicStatus { | ||||
| @@ -689,24 +779,16 @@ func runEmailTests(wg2 *sync.WaitGroup, emailInfo *string, output, tempOutput st | ||||
| func runNetworkTests(wg3 *sync.WaitGroup, ptInfo *string, output, tempOutput string, outputMutex *sync.Mutex) string { | ||||
| 	outputMutex.Lock() | ||||
| 	defer outputMutex.Unlock() | ||||
| 	output = utils.PrintAndCapture(func() { | ||||
| 	return utils.PrintAndCapture(func() { | ||||
| 		if backtraceStatus && !onlyChinaTest { | ||||
| 			utils.PrintCenteredTitle("三网回程线路检测", width) | ||||
| 			if uts.IPV6 { | ||||
| 				backtrace.BackTrace(true) | ||||
| 			} else { | ||||
| 				backtrace.BackTrace(false) | ||||
| 			} | ||||
| 			utils.PrintCenteredTitle("上游及回程线路检测", width) | ||||
| 			upstreams.UpstreamsCheck() // 不能在重定向的同时外部并发,此处仅可以顺序执行 | ||||
| 		} | ||||
| 	}, tempOutput, output) | ||||
| 	output = utils.PrintAndCapture(func() { | ||||
| 		if nt3Status && !onlyChinaTest { | ||||
| 			utils.PrintCenteredTitle("三网回程路由检测", width) | ||||
| 			nt.TraceRoute(language, nt3Location, nt3CheckType) | ||||
| 			nexttrace.NextTrace3Check(language, nt3Location, nt3CheckType) // 不能在重定向的同时外部并发,此处仅可以顺序执行 | ||||
| 		} | ||||
| 	}, tempOutput, output) | ||||
| 	return utils.PrintAndCapture(func() { | ||||
| 		if onlyChinaTest || pingTestStatus { | ||||
| 		if (onlyChinaTest || pingTestStatus) && *ptInfo != "" { | ||||
| 			wg3.Wait() | ||||
| 			utils.PrintCenteredTitle("三网ICMP的PING值检测", width) | ||||
| 			fmt.Println(*ptInfo) | ||||
| @@ -775,8 +857,10 @@ func handleUploadResults(output string) { | ||||
| 	if httpURL != "" || httpsURL != "" { | ||||
| 		if language == "en" { | ||||
| 			fmt.Printf("Upload successfully!\nHttp URL:  %s\nHttps URL: %s\n", httpURL, httpsURL) | ||||
| 			fmt.Println("Each Test Benchmark: https://bash.spiritlhl.net/ecsguide") | ||||
| 		} else { | ||||
| 			fmt.Printf("上传成功!\nHttp URL:  %s\nHttps URL: %s\n", httpURL, httpsURL) | ||||
| 			fmt.Println("每项测试基准见: https://bash.spiritlhl.net/ecsguide") | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -787,12 +871,16 @@ func main() { | ||||
| 		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) | ||||
| 	go func() { | ||||
| 		if preCheck.Connected { | ||||
| 			http.Get("https://hits.spiritlhl.net/goecs.svg?action=hit&title=Hits&title_bg=%23555555&count_bg=%230eecf8&edge_flat=false") | ||||
| 		} | ||||
| 	}() | ||||
| 	if menuMode { | ||||
| 		handleMenuMode(preCheck) | ||||
| 	} else { | ||||
| 		onlyIpInfoCheckStatus = true | ||||
| 	} | ||||
| 	handleLanguageSpecificSettings() | ||||
| 	if !preCheck.Connected { | ||||
|   | ||||
							
								
								
									
										377
									
								
								goecs.sh
									
									
									
									
									
								
							
							
						
						
									
										377
									
								
								goecs.sh
									
									
									
									
									
								
							| @@ -1,6 +1,6 @@ | ||||
| #!/bin/bash | ||||
| #!/bin/sh | ||||
| # From https://github.com/oneclickvirt/ecs | ||||
| # 2025.06.29 | ||||
| # 2025.10.08 | ||||
|  | ||||
| # curl -L https://raw.githubusercontent.com/oneclickvirt/ecs/master/goecs.sh -o goecs.sh && chmod +x goecs.sh | ||||
| # 或 | ||||
| @@ -20,22 +20,27 @@ cd /root >/dev/null 2>&1 | ||||
| if [ ! -d "/usr/bin/" ]; then | ||||
|     mkdir -p "/usr/bin/" | ||||
| fi | ||||
| _red() { echo -e "\033[31m\033[01m$@\033[0m"; } | ||||
| _green() { echo -e "\033[32m\033[01m$@\033[0m"; } | ||||
| _yellow() { echo -e "\033[33m\033[01m$@\033[0m"; } | ||||
| _blue() { echo -e "\033[36m\033[01m$@\033[0m"; } | ||||
| reading() { read -rp "$(_green "$1")" "$2"; } | ||||
| _red() { printf "\033[31m\033[01m%s\033[0m\n" "$*"; } | ||||
| _green() { printf "\033[32m\033[01m%s\033[0m\n" "$*"; } | ||||
| _yellow() { printf "\033[33m\033[01m%s\033[0m\n" "$*"; } | ||||
| _blue() { printf "\033[36m\033[01m%s\033[0m\n" "$*"; } | ||||
| reading() {  | ||||
|     printf "\033[32m\033[01m%s\033[0m" "$1" | ||||
|     read "$2" | ||||
| } | ||||
|  | ||||
| check_cdn() { | ||||
|     local o_url=$1 | ||||
|     for cdn_url in "${cdn_urls[@]}"; do | ||||
|         if curl -sL -k "$cdn_url$o_url" --max-time 6 | grep -q "success" >/dev/null 2>&1; then | ||||
|             export cdn_success_url="$cdn_url" | ||||
|             return | ||||
|     local o_url="$1" | ||||
|     local cdn_url | ||||
|     for cdn_url in $cdn_urls; do | ||||
|         if curl -4 -sL -k "$cdn_url$o_url" --max-time 6 | grep -q "success" >/dev/null 2>&1; then | ||||
|             cdn_success_url="$cdn_url" | ||||
|             return 0 | ||||
|         fi | ||||
|         sleep 0.5 | ||||
|     done | ||||
|     export cdn_success_url="" | ||||
|     cdn_success_url="" | ||||
|     return 1 | ||||
| } | ||||
|  | ||||
| check_cdn_file() { | ||||
| @@ -50,9 +55,9 @@ check_cdn_file() { | ||||
| download_file() { | ||||
|     local url="$1" | ||||
|     local output="$2" | ||||
|     if ! wget -O "$output" "$url"; then | ||||
|     if ! wget -O "$output" "$url" 2>/dev/null; then | ||||
|         _yellow "wget failed, trying curl..." | ||||
|         if ! curl -L -o "$output" "$url"; then | ||||
|         if ! curl -L -o "$output" "$url" 2>/dev/null; then | ||||
|             _red "Both wget and curl failed. Unable to download the file." | ||||
|             return 1 | ||||
|         fi | ||||
| @@ -62,8 +67,7 @@ download_file() { | ||||
|  | ||||
| check_china() { | ||||
|     _yellow "正在检测IP所在区域......" | ||||
|     if [[ -z "${CN}" ]]; then | ||||
|         # 首先尝试通过 ipapi.co 检测 | ||||
|     if [ -z "${CN}" ]; then | ||||
|         if curl -m 6 -s https://ipapi.co/json | grep -q 'China'; then | ||||
|             _yellow "根据ipapi.co提供的信息,当前IP可能在中国" | ||||
|             if [ "$noninteractive" != "true" ]; then | ||||
| @@ -94,28 +98,33 @@ check_china() { | ||||
|  | ||||
| get_memory_size() { | ||||
|     if [ -f /proc/meminfo ]; then | ||||
|         local mem_kb=$(grep MemTotal /proc/meminfo | awk '{print $2}') | ||||
|         local mem_kb | ||||
|         mem_kb=$(grep MemTotal /proc/meminfo | awk '{print $2}') | ||||
|         echo $((mem_kb / 1024)) # Convert to MB | ||||
|         return | ||||
|         return 0 | ||||
|     fi | ||||
|     if command -v free >/dev/null 2>&1; then | ||||
|         local mem_kb=$(free -m | awk '/^Mem:/ {print $2}') | ||||
|         local mem_kb | ||||
|         mem_kb=$(free -m | awk '/^Mem:/ {print $2}') | ||||
|         echo "$mem_kb" # Already in MB | ||||
|         return | ||||
|         return 0 | ||||
|     fi | ||||
|     if command -v sysctl >/dev/null 2>&1; then | ||||
|         local mem_bytes=$(sysctl -n hw.memsize 2>/dev/null || sysctl -n hw.physmem 2>/dev/null) | ||||
|         local mem_bytes | ||||
|         mem_bytes=$(sysctl -n hw.memsize 2>/dev/null || sysctl -n hw.physmem 2>/dev/null) | ||||
|         if [ -n "$mem_bytes" ]; then | ||||
|             echo $((mem_bytes / 1024 / 1024)) # Convert to MB | ||||
|             return | ||||
|             return 0 | ||||
|         fi | ||||
|     fi | ||||
|     echo 0 | ||||
|     return 1 | ||||
| } | ||||
|  | ||||
| cleanup_epel() { | ||||
|     _yellow "Cleaning up EPEL repositories..." | ||||
|     rm -f /etc/yum.repos.d/*epel* | ||||
|     yum clean all | ||||
|     yum clean all >/dev/null 2>&1 | ||||
| } | ||||
|  | ||||
| goecs_check() { | ||||
| @@ -143,7 +152,7 @@ goecs_check() { | ||||
|     os=$(uname -s 2>/dev/null || echo "Unknown") | ||||
|     arch=$(uname -m 2>/dev/null || echo "Unknown") | ||||
|     check_china | ||||
|     ECS_VERSION="0.1.70" | ||||
|     ECS_VERSION="0.1.90" | ||||
|     for api in \ | ||||
|         "https://api.github.com/repos/oneclickvirt/ecs/releases/latest" \ | ||||
|         "https://githubapi.spiritlhl.workers.dev/repos/oneclickvirt/ecs/releases/latest" \ | ||||
| @@ -155,23 +164,24 @@ goecs_check() { | ||||
|         sleep 1 | ||||
|     done | ||||
|     if [ -z "$ECS_VERSION" ]; then | ||||
|         _yellow "Unable to get version info, using default version 0.1.70" | ||||
|         ECS_VERSION="0.1.70" | ||||
|         _yellow "Unable to get version info, using default version 0.1.90" | ||||
|         ECS_VERSION="0.1.90" | ||||
|     fi | ||||
|     version_output="" | ||||
|     for cmd_path in "goecs" "./goecs" "/usr/bin/goecs" "/usr/local/bin/goecs"; do | ||||
|         if [ -x "$(command -v $cmd_path 2>/dev/null)" ]; then | ||||
|         if command -v "$cmd_path" >/dev/null 2>&1; then | ||||
|             version_output=$($cmd_path -v command 2>/dev/null) | ||||
|             break | ||||
|         fi | ||||
|     done | ||||
|     if [ -n "$version_output" ]; then | ||||
|         extracted_version=${version_output//v/} | ||||
|         extracted_version=${version_output#*v} | ||||
|         extracted_version=${extracted_version#v} | ||||
|         if [ -n "$extracted_version" ]; then | ||||
|             ecs_version=$ECS_VERSION | ||||
|             if [[ "$(echo -e "$extracted_version\n$ecs_version" | sort -V | tail -n 1)" == "$extracted_version" ]]; then | ||||
|             if [ "$(printf '%s\n%s\n' "$extracted_version" "$ecs_version" | sort -V | tail -n 1)" = "$extracted_version" ]; then | ||||
|                 _green "goecs version ($extracted_version) is up to date, no upgrade needed" | ||||
|                 return | ||||
|                 return 0 | ||||
|             else | ||||
|                 _yellow "goecs version ($extracted_version) < $ecs_version, upgrade needed, starting in 5 seconds" | ||||
|                 rm -rf /usr/bin/goecs /usr/local/bin/goecs ./goecs | ||||
| @@ -181,11 +191,11 @@ goecs_check() { | ||||
|         _green "goecs not found, installation needed, starting in 5 seconds" | ||||
|     fi | ||||
|     sleep 5 | ||||
|     if [[ "$CN" == true ]]; then | ||||
|     if [ "$CN" = "true" ]; then | ||||
|         _yellow "Using China mirror for download..." | ||||
|         base_url="https://cnb.cool/oneclickvirt/ecs/-/git/raw/main" | ||||
|     else | ||||
|         cdn_urls=("https://cdn0.spiritlhl.top/" "http://cdn3.spiritlhl.net/" "http://cdn1.spiritlhl.net/" "http://cdn2.spiritlhl.net/") | ||||
|         cdn_urls="https://cdn0.spiritlhl.top/ http://cdn3.spiritlhl.net/ http://cdn1.spiritlhl.net/ http://cdn2.spiritlhl.net/" | ||||
|         check_cdn_file | ||||
|         if [ -n "$cdn_success_url" ]; then | ||||
|             base_url="${cdn_success_url}https://github.com/oneclickvirt/ecs/releases/download/v${ECS_VERSION}" | ||||
| @@ -301,169 +311,188 @@ InstallSysbench() { | ||||
|     else | ||||
|         Var_OSRelease="unknown" # 未知系统分支 | ||||
|     fi | ||||
|     local mem_size=$(get_memory_size) | ||||
|     local mem_size | ||||
|     mem_size=$(get_memory_size) | ||||
|     if [ -z "$mem_size" ] || [ "$mem_size" -eq 0 ]; then | ||||
|         echo "Error: Unable to determine memory size or memory size is zero." | ||||
|     elif [ $mem_size -lt 1024 ]; then | ||||
|     elif [ "$mem_size" -lt 1024 ]; then | ||||
|         _red "Warning: Your system has less than 1GB RAM (${mem_size}MB)" | ||||
|         if [ "$noninteractive" != "true" ]; then | ||||
|             reading "Do you want to continue with EPEL installation? (y/N): " confirm | ||||
|             if [[ ! $confirm =~ ^[Yy]$ ]]; then | ||||
|                 _yellow "Skipping EPEL installation" | ||||
|                 return 1 | ||||
|             fi | ||||
|             case "$confirm" in | ||||
|                 [Yy]*) | ||||
|                     ;; | ||||
|                 *) | ||||
|                     _yellow "Skipping EPEL installation" | ||||
|                     return 1 | ||||
|                     ;; | ||||
|             esac | ||||
|         fi | ||||
|         case "$Var_OSRelease" in | ||||
|         ubuntu | debian | astra) | ||||
|             ! apt-get install -y sysbench && apt-get --fix-broken install -y && apt-get install --no-install-recommends -y sysbench ;; | ||||
|             if ! apt-get install -y sysbench; then | ||||
|                 apt-get --fix-broken install -y | ||||
|                 apt-get install --no-install-recommends -y sysbench | ||||
|             fi | ||||
|             ;; | ||||
|         centos | rhel | almalinux | redhat | opencloudos) | ||||
|             (yum -y install epel-release && yum -y install sysbench) || (dnf install epel-release -y && dnf install sysbench -y) ;; | ||||
|             if ! yum -y install epel-release || ! yum -y install sysbench; then | ||||
|                 if command -v dnf >/dev/null 2>&1; then | ||||
|                     dnf install epel-release -y | ||||
|                     dnf install sysbench -y | ||||
|                 fi | ||||
|             fi | ||||
|             ;; | ||||
|         fedora) | ||||
|             dnf -y install sysbench ;; | ||||
|         arch) | ||||
|             pacman -S --needed --noconfirm sysbench && pacman -S --needed --noconfirm libaio && ldconfig ;; | ||||
|             pacman -S --needed --noconfirm sysbench | ||||
|             pacman -S --needed --noconfirm libaio | ||||
|             ldconfig | ||||
|             ;; | ||||
|         freebsd) | ||||
|             pkg install -y sysbench ;; | ||||
|         alpinelinux) | ||||
|             if [ "$noninteractive" != "true" ]; then | ||||
|                 reading "Do you want to continue with sysbench installation? (y/N): " confirm | ||||
|                 if [[ ! $confirm =~ ^[Yy]$ ]]; then | ||||
|                     _yellow "Skipping sysbench installation" | ||||
|                     return 1 | ||||
|                 fi | ||||
|                 case "$confirm" in | ||||
|                     [Yy]*) | ||||
|                         ;; | ||||
|                     *) | ||||
|                         _yellow "Skipping sysbench installation" | ||||
|                         return 1 | ||||
|                         ;; | ||||
|                 esac | ||||
|             fi | ||||
|             ALPINE_VERSION=$(grep -o '^[0-9]\+\.[0-9]\+' /etc/alpine-release) | ||||
|             COMMUNITY_REPO="http://dl-cdn.alpinelinux.org/alpine/v${ALPINE_VERSION}/community" | ||||
|             if grep -q "^${COMMUNITY_REPO}" /etc/apk/repositories; then | ||||
|                 echo "Community repository is already enabled." | ||||
|             else | ||||
|             if ! grep -q "^${COMMUNITY_REPO}" /etc/apk/repositories; then | ||||
|                 echo "Enabling community repository..." | ||||
|                 echo "${COMMUNITY_REPO}" >> /etc/apk/repositories | ||||
|                 echo "Community repository has been added." | ||||
|                 echo "Updating apk package index..." | ||||
|                 apk update && echo "Package index updated successfully." | ||||
|             else | ||||
|                 echo "Community repository is already enabled." | ||||
|             fi | ||||
|             if apk info sysbench >/dev/null 2>&1; then | ||||
|                 echo -e "${Msg_Info}Sysbench already installed." | ||||
|                 echo "Sysbench already installed." | ||||
|             else | ||||
|                 apk add --no-cache sysbench | ||||
|                 if [ $? -ne 0 ]; then | ||||
|                     echo -e "${Msg_Warning}Sysbench Module not found, installing ..." && echo -e "${Msg_Warning}SysBench Current not support Alpine Linux, Skipping..." && Var_Skip_SysBench="1" | ||||
|                 if ! apk add --no-cache sysbench; then | ||||
|                     echo "Sysbench Module not found, installing ..." | ||||
|                     echo "SysBench Current not support Alpine Linux, Skipping..." | ||||
|                     Var_Skip_SysBench="1" | ||||
|                 else | ||||
|                     echo -e "${Msg_Success}Sysbench installed successfully." | ||||
|                     echo "Sysbench installed successfully." | ||||
|                 fi | ||||
|             fi ;; | ||||
|             fi | ||||
|             ;; | ||||
|         *) | ||||
|             _red "Sysbench Install Error: Unknown OS release: $Var_OSRelease" ;; | ||||
|         esac | ||||
|         if [[ $SYSTEM =~ ^(CentOS|RHEL|AlmaLinux)$ ]]; then | ||||
|         _yellow "Installing EPEL repository..." | ||||
|             if ! yum -y install epel-release; then | ||||
|                 _red "EPEL installation failed!" | ||||
|                 cleanup_epel | ||||
|                 _yellow "Attempting to continue without EPEL..." | ||||
|             fi | ||||
|         fi | ||||
|     fi | ||||
| } | ||||
|  | ||||
| Check_SysBench() { | ||||
|     if [ ! -f "/usr/bin/sysbench" ] && [ ! -f "/usr/local/bin/sysbench" ]; then | ||||
|         InstallSysbench | ||||
|     fi | ||||
|     # 尝试编译安装 | ||||
|     if [ ! -f "/usr/bin/sysbench" ] && [ ! -f "/usr/local/bin/sysbench" ]; then | ||||
|         echo -e "${Msg_Warning}Sysbench Module install Failure, trying compile modules ..." | ||||
|         Check_Sysbench_InstantBuild | ||||
|     fi | ||||
|     source ~/.bashrc | ||||
|     # 最终检测 | ||||
|     if [ "$(command -v sysbench)" ] || [ -f "/usr/bin/sysbench" ] || [ -f "/usr/local/bin/sysbench" ]; then | ||||
|         _yellow "Install sysbench successfully!" | ||||
|     else | ||||
|         _red "SysBench Moudle install Failure! Try Restart Bench or Manually install it! (/usr/bin/sysbench)" | ||||
|         _blue "Will try to test with geekbench5 instead later." | ||||
|     fi | ||||
|     sleep 3 | ||||
| } | ||||
|  | ||||
| Check_Sysbench_InstantBuild() { | ||||
|     if [ "${Var_OSRelease}" = "centos" ] || [ "${Var_OSRelease}" = "rhel" ] || [ "${Var_OSRelease}" = "almalinux" ] || [ "${Var_OSRelease}" = "ubuntu" ] || [ "${Var_OSRelease}" = "debian" ] || [ "${Var_OSRelease}" = "fedora" ] || [ "${Var_OSRelease}" = "arch" ] || [ "${Var_OSRelease}" = "astra" ]; then | ||||
|         local os_sysbench=${Var_OSRelease} | ||||
|         if [ "$os_sysbench" = "astra" ]; then | ||||
|             os_sysbench="debian" | ||||
|         fi | ||||
|         if [ "$os_sysbench" = "opencloudos" ]; then | ||||
|             os_sysbench="centos" | ||||
|         fi | ||||
|         echo -e "${Msg_Info}Release Detected: ${os_sysbench}" | ||||
|         echo -e "${Msg_Info}Preparing compile enviorment ..." | ||||
|         prepare_compile_env "${os_sysbench}" | ||||
|         echo -e "${Msg_Info}Downloading Source code (Version 1.0.20)..." | ||||
|         mkdir -p /tmp/sysbench_install/src/ | ||||
|         mv /tmp/sysbench-1.0.20 /tmp/sysbench_install/src/ | ||||
|         echo -e "${Msg_Info}Compiling Sysbench Module ..." | ||||
|         cd /tmp/sysbench_install/src/sysbench-1.0.20 | ||||
|         ./autogen.sh && ./configure --without-mysql && make -j8 && make install | ||||
|         echo -e "${Msg_Info}Cleaning up ..." | ||||
|         cd /tmp && rm -rf /tmp/sysbench_install/src/sysbench* | ||||
|     else | ||||
|         echo -e "${Msg_Warning}Unsupported operating system: ${Var_OSRelease}" | ||||
|     fi | ||||
| } | ||||
|  | ||||
| prepare_compile_env() { | ||||
|     local system="$1" | ||||
|     if [ "${system}" = "centos" ] || [ "${system}" = "rhel" ] || [ "${system}" = "almalinux" ]; then | ||||
|         yum install -y epel-release | ||||
|         yum install -y wget curl make gcc gcc-c++ make automake libtool pkgconfig libaio-devel | ||||
|     elif [ "${system}" = "ubuntu" ] || [ "${system}" = "debian" ]; then | ||||
|         ! apt-get update && apt-get --fix-broken install -y && apt-get update | ||||
|         ! apt-get -y install --no-install-recommends curl wget make automake libtool pkg-config libaio-dev unzip && apt-get --fix-broken install -y && apt-get -y install --no-install-recommends curl wget make automake libtool pkg-config libaio-dev unzip | ||||
|     elif [ "${system}" = "fedora" ]; then | ||||
|         dnf install -y wget curl gcc gcc-c++ make automake libtool pkgconfig libaio-devel | ||||
|     elif [ "${system}" = "arch" ]; then | ||||
|         pacman -S --needed --noconfirm wget curl gcc gcc make automake libtool pkgconfig libaio lib32-libaio | ||||
|     else | ||||
|         echo -e "${Msg_Warning}Unsupported operating system: ${system}" | ||||
|         case "$SYSTEM" in | ||||
|             CentOS|RHEL|AlmaLinux) | ||||
|                 _yellow "Installing EPEL repository..." | ||||
|                 if ! yum -y install epel-release; then | ||||
|                     _red "EPEL installation failed!" | ||||
|                     cleanup_epel | ||||
|                     _yellow "Attempting to continue without EPEL..." | ||||
|                 fi | ||||
|                 ;; | ||||
|         esac | ||||
|     fi | ||||
| } | ||||
|  | ||||
| env_check() { | ||||
|     REGEX=("debian|astra" "ubuntu" "centos|red hat|kernel|oracle linux|alma|rocky" "'amazon linux'" "fedora" "arch" "freebsd" "alpine" "openbsd" "opencloudos") | ||||
|     RELEASE=("Debian" "Ubuntu" "CentOS" "CentOS" "Fedora" "Arch" "FreeBSD" "Alpine" "OpenBSD" "OpenCloudOS") | ||||
|     PACKAGE_UPDATE=("apt-get update" "apt-get update" "yum -y update" "yum -y update" "yum -y update" "pacman -Sy" "pkg update" "apk update" "pkg_add -qu" "yum -y update") | ||||
|     PACKAGE_INSTALL=("apt-get -y install" "apt-get -y install" "yum -y install" "yum -y install" "yum -y install" "pacman -Sy --noconfirm --needed" "pkg install -y" "apk add --no-cache" "pkg_add -I" "yum -y install") | ||||
|     PACKAGE_REMOVE=("apt-get -y remove" "apt-get -y remove" "yum -y remove" "yum -y remove" "yum -y remove" "pacman -Rsc --noconfirm" "pkg delete" "apk del" "pkg_delete -I" "yum -y remove") | ||||
|     PACKAGE_UNINSTALL=("apt-get -y autoremove" "apt-get -y autoremove" "yum -y autoremove" "yum -y autoremove" "yum -y autoremove" "pacman -Rns --noconfirm" "pkg autoremove" "apk autoremove" "pkg_delete -a" "yum -y autoremove") | ||||
|     # 检测是否为 macOS 系统 | ||||
|     if [ "$(uname -s)" = "Darwin" ]; then | ||||
|         _green "Detected macOS system" | ||||
|         _green "macOS has built-in tools, skipping dependency installation" | ||||
|         _green "Environment preparation complete." | ||||
|         _green "Next command is: ./goecs.sh install" | ||||
|         return 0 | ||||
|     fi | ||||
|      | ||||
|     if [ -f /etc/opencloudos-release ]; then | ||||
|         SYS="opencloudos" | ||||
|     elif [ -s /etc/os-release ]; then | ||||
|         SYS="$(grep -i pretty_name /etc/os-release | cut -d \" -f2)" | ||||
|     elif [ -x "$(type -p hostnamectl)" ]; then | ||||
|         SYS="$(hostnamectl | grep -i system | cut -d : -f2 | xargs)" | ||||
|     elif [ -x "$(type -p lsb_release)" ]; then | ||||
|     elif command -v hostnamectl >/dev/null 2>&1; then | ||||
|         SYS="$(hostnamectl | grep -i system | cut -d : -f2 | sed 's/^ *//')" | ||||
|     elif command -v lsb_release >/dev/null 2>&1; then | ||||
|         SYS="$(lsb_release -sd)" | ||||
|     elif [ -s /etc/lsb-release ]; then | ||||
|         SYS="$(grep -i description /etc/lsb-release | cut -d \" -f2)" | ||||
|     elif [ -s /etc/redhat-release ]; then | ||||
|         SYS="$(grep . /etc/redhat-release)" | ||||
|         SYS="$(cat /etc/redhat-release)" | ||||
|     elif [ -s /etc/issue ]; then | ||||
|         SYS="$(grep . /etc/issue | cut -d '\' -f1 | sed '/^[ ]*$/d')" | ||||
|         SYS="$(head -n1 /etc/issue | cut -d '\' -f1 | sed '/^[ ]*$/d')" | ||||
|     else | ||||
|         SYS="$(uname -s)" | ||||
|     fi | ||||
|     SYSTEM="" | ||||
|     for ((int = 0; int < ${#REGEX[@]}; int++)); do | ||||
|         if [[ $(echo "$SYS" | tr '[:upper:]' '[:lower:]') =~ ${REGEX[int]} ]]; then | ||||
|             SYSTEM="${RELEASE[int]}" | ||||
|             UPDATE_CMD=${PACKAGE_UPDATE[int]} | ||||
|             INSTALL_CMD=${PACKAGE_INSTALL[int]} | ||||
|             REMOVE_CMD=${PACKAGE_REMOVE[int]} | ||||
|             UNINSTALL_CMD=${PACKAGE_UNINSTALL[int]} | ||||
|             break | ||||
|         fi | ||||
|     done | ||||
|     sys_lower=$(echo "$SYS" | tr '[:upper:]' '[:lower:]') | ||||
|     if echo "$sys_lower" | grep -E "debian|astra" >/dev/null 2>&1; then | ||||
|         SYSTEM="Debian" | ||||
|         UPDATE_CMD="apt-get update" | ||||
|         INSTALL_CMD="apt-get -y install" | ||||
|         REMOVE_CMD="apt-get -y remove" | ||||
|         UNINSTALL_CMD="apt-get -y autoremove" | ||||
|     elif echo "$sys_lower" | grep -E "ubuntu" >/dev/null 2>&1; then | ||||
|         SYSTEM="Ubuntu" | ||||
|         UPDATE_CMD="apt-get update" | ||||
|         INSTALL_CMD="apt-get -y install" | ||||
|         REMOVE_CMD="apt-get -y remove" | ||||
|         UNINSTALL_CMD="apt-get -y autoremove" | ||||
|     elif echo "$sys_lower" | grep -E "centos|red hat|kernel|oracle linux|alma|rocky" >/dev/null 2>&1; then | ||||
|         SYSTEM="CentOS" | ||||
|         UPDATE_CMD="yum -y update" | ||||
|         INSTALL_CMD="yum -y install" | ||||
|         REMOVE_CMD="yum -y remove" | ||||
|         UNINSTALL_CMD="yum -y autoremove" | ||||
|     elif echo "$sys_lower" | grep -E "amazon linux" >/dev/null 2>&1; then | ||||
|         SYSTEM="CentOS" | ||||
|         UPDATE_CMD="yum -y update" | ||||
|         INSTALL_CMD="yum -y install" | ||||
|         REMOVE_CMD="yum -y remove" | ||||
|         UNINSTALL_CMD="yum -y autoremove" | ||||
|     elif echo "$sys_lower" | grep -E "fedora" >/dev/null 2>&1; then | ||||
|         SYSTEM="Fedora" | ||||
|         UPDATE_CMD="yum -y update" | ||||
|         INSTALL_CMD="yum -y install" | ||||
|         REMOVE_CMD="yum -y remove" | ||||
|         UNINSTALL_CMD="yum -y autoremove" | ||||
|     elif echo "$sys_lower" | grep -E "arch" >/dev/null 2>&1; then | ||||
|         SYSTEM="Arch" | ||||
|         UPDATE_CMD="pacman -Sy" | ||||
|         INSTALL_CMD="pacman -Sy --noconfirm --needed" | ||||
|         REMOVE_CMD="pacman -Rsc --noconfirm" | ||||
|         UNINSTALL_CMD="pacman -Rns --noconfirm" | ||||
|     elif echo "$sys_lower" | grep -E "freebsd" >/dev/null 2>&1; then | ||||
|         SYSTEM="FreeBSD" | ||||
|         UPDATE_CMD="pkg update" | ||||
|         INSTALL_CMD="pkg install -y" | ||||
|         REMOVE_CMD="pkg delete" | ||||
|         UNINSTALL_CMD="pkg autoremove" | ||||
|     elif echo "$sys_lower" | grep -E "alpine" >/dev/null 2>&1; then | ||||
|         SYSTEM="Alpine" | ||||
|         UPDATE_CMD="apk update" | ||||
|         INSTALL_CMD="apk add --no-cache" | ||||
|         REMOVE_CMD="apk del" | ||||
|         UNINSTALL_CMD="apk autoremove" | ||||
|     elif echo "$sys_lower" | grep -E "openbsd" >/dev/null 2>&1; then | ||||
|         SYSTEM="OpenBSD" | ||||
|         UPDATE_CMD="pkg_add -qu" | ||||
|         INSTALL_CMD="pkg_add -I" | ||||
|         REMOVE_CMD="pkg_delete -I" | ||||
|         UNINSTALL_CMD="pkg_delete -a" | ||||
|     elif echo "$sys_lower" | grep -E "opencloudos" >/dev/null 2>&1; then | ||||
|         SYSTEM="OpenCloudOS" | ||||
|         UPDATE_CMD="yum -y update" | ||||
|         INSTALL_CMD="yum -y install" | ||||
|         REMOVE_CMD="yum -y remove" | ||||
|         UNINSTALL_CMD="yum -y autoremove" | ||||
|     fi | ||||
|     if [ -z "$SYSTEM" ]; then | ||||
|         _yellow "Unable to recognize system, trying common package managers..." | ||||
|         if command -v apt-get >/dev/null 2>&1; then | ||||
| @@ -510,7 +539,7 @@ env_check() { | ||||
|     _green "System information: $SYSTEM" | ||||
|     _green "Update command: $UPDATE_CMD" | ||||
|     _green "Install command: $INSTALL_CMD" | ||||
|     cdn_urls=("https://cdn0.spiritlhl.top/" "http://cdn3.spiritlhl.net/" "http://cdn1.spiritlhl.net/" "http://cdn2.spiritlhl.net/") | ||||
|     cdn_urls="https://cdn0.spiritlhl.top/ http://cdn3.spiritlhl.net/ http://cdn1.spiritlhl.net/ http://cdn2.spiritlhl.net/" | ||||
|     check_cdn_file | ||||
|     _yellow "Warning: System update will be performed" | ||||
|     _yellow "This operation may:" | ||||
| @@ -520,15 +549,18 @@ env_check() { | ||||
|     _yellow "4. Affect subsequent system startups" | ||||
|     if [ "$noninteractive" != "true" ]; then | ||||
|         reading "Continue with system update? (y/N): " update_confirm | ||||
|         if [[ ! $update_confirm =~ ^[Yy]$ ]]; then | ||||
|             _yellow "Skipping system update" | ||||
|             _yellow "Note: Some packages may fail to install" | ||||
|         else | ||||
|             _green "Updating system package manager..." | ||||
|             if ! ${UPDATE_CMD} 2>/dev/null; then | ||||
|                 _red "System update failed!" | ||||
|             fi | ||||
|         fi | ||||
|         case "$update_confirm" in | ||||
|             [Yy]*) | ||||
|                 _green "Updating system package manager..." | ||||
|                 if ! ${UPDATE_CMD} 2>/dev/null; then | ||||
|                     _red "System update failed!" | ||||
|                 fi | ||||
|                 ;; | ||||
|             *) | ||||
|                 _yellow "Skipping system update" | ||||
|                 _yellow "Note: Some packages may fail to install" | ||||
|                 ;; | ||||
|         esac | ||||
|     fi | ||||
|     for cmd in sudo wget tar unzip iproute2 systemd-detect-virt dd fio; do | ||||
|         if ! command -v "$cmd" >/dev/null 2>&1; then | ||||
| @@ -538,44 +570,31 @@ env_check() { | ||||
|     done | ||||
|     if ! command -v sysbench >/dev/null 2>&1; then | ||||
|         _green "Installing sysbench" | ||||
|         ${INSTALL_CMD} sysbench | ||||
|         if [ $? -ne 0 ]; then | ||||
|             echo "Unable to download sysbench through package manager, attempting compilation..." | ||||
|             wget -O /tmp/sysbench.zip "${cdn_success_url}https://github.com/akopytov/sysbench/archive/1.0.20.zip" || curl -Lk -o /tmp/sysbench.zip "${cdn_success_url}https://github.com/akopytov/sysbench/archive/1.0.20.zip" | ||||
|             if [ ! -f /tmp/sysbench.zip ]; then | ||||
|                 wget -q -O /tmp/sysbench.zip "https://hub.fgit.cf/akopytov/sysbench/archive/1.0.20.zip" | ||||
|             fi | ||||
|             chmod +x /tmp/sysbench.zip | ||||
|             unzip /tmp/sysbench.zip -d /tmp | ||||
|             Check_SysBench | ||||
|         if ! ${INSTALL_CMD} sysbench; then | ||||
|             _red "Unable to install sysbench through package manager" | ||||
|             _yellow "Sysbench installation skipped" | ||||
|         fi | ||||
|     fi | ||||
|     if ! command -v geekbench >/dev/null 2>&1; then | ||||
|         _green "Installing geekbench" | ||||
|         curl -L "${cdn_success_url}https://raw.githubusercontent.com/oneclickvirt/cputest/main/dgb.sh" -o dgb.sh && chmod +x dgb.sh | ||||
|         bash dgb.sh -v gb5 | ||||
|         sh dgb.sh -v gb5 | ||||
|         rm -rf dgb.sh | ||||
|     fi | ||||
|     if ! command -v speedtest >/dev/null 2>&1; then | ||||
|         _green "Installing speedtest" | ||||
|         curl -L "${cdn_success_url}https://raw.githubusercontent.com/oneclickvirt/speedtest/main/dspt.sh" -o dspt.sh && chmod +x dspt.sh | ||||
|         bash dspt.sh | ||||
|         sh dspt.sh | ||||
|         rm -rf dspt.sh | ||||
|         rm -rf speedtest.tar.gz | ||||
|     fi | ||||
|     if ! command -v ping >/dev/null 2>&1; then | ||||
|         _green "Installing ping" | ||||
|         ${INSTALL_CMD} iputils-ping >/dev/null 2>&1 | ||||
|         ${INSTALL_CMD} ping >/dev/null 2>&1 | ||||
|         ${INSTALL_CMD} iputils-ping >/dev/null 2>&1 || ${INSTALL_CMD} ping >/dev/null 2>&1 | ||||
|     fi | ||||
|     if [ "$(uname -s)" = "Darwin" ]; then | ||||
|         echo "Detected MacOS, installing sysbench iproute2mac..." | ||||
|         brew install --force sysbench iproute2mac | ||||
|     else | ||||
|         if ! grep -q "^net.ipv4.ping_group_range = 0 2147483647$" /etc/sysctl.conf; then | ||||
|             echo "net.ipv4.ping_group_range = 0 2147483647" >> /etc/sysctl.conf | ||||
|             sysctl -p | ||||
|         fi | ||||
|     if ! grep -q "^net.ipv4.ping_group_range = 0 2147483647$" /etc/sysctl.conf 2>/dev/null; then | ||||
|         echo "net.ipv4.ping_group_range = 0 2147483647" >> /etc/sysctl.conf 2>/dev/null | ||||
|         sysctl -p >/dev/null 2>&1 | ||||
|     fi | ||||
|     _green "Environment preparation complete." | ||||
|     _green "Next command is: ./goecs.sh install" | ||||
| @@ -592,6 +611,7 @@ show_help() { | ||||
| 可用命令: | ||||
|  | ||||
| ./goecs.sh env            检查并安装依赖包 | ||||
|                           注意: macOS系统会自动跳过依赖安装 | ||||
|                           警告: 此命令会执行系统更新(可选择),可能: | ||||
|                           1. 耗时较长 | ||||
|                           2. 导致网络短暂中断 | ||||
| @@ -619,6 +639,7 @@ show_help() { | ||||
| Available commands: | ||||
|  | ||||
| ./goecs.sh env             Check and Install dependencies | ||||
|                            Note: macOS systems will skip dependency installation | ||||
|                            Warning: This command performs system update(optional), which may: | ||||
|                            1. Take considerable time | ||||
|                            2. Cause temporary network interruptions | ||||
|   | ||||
| @@ -8,30 +8,78 @@ import ( | ||||
| ) | ||||
|  | ||||
| func MemoryTest(language, testMethod string) (realTestMethod, res string) { | ||||
| 	testMethod = strings.ToLower(testMethod) | ||||
| 	if testMethod == "" { | ||||
| 		testMethod = "auto" | ||||
| 	} | ||||
| 	if runtime.GOOS == "windows" { | ||||
| 		if testMethod != "winsat" && testMethod != "" { | ||||
| 			// res = "Detected host is Windows, using Winsat for testing.\n" | ||||
| 		switch testMethod { | ||||
| 		case "stream": | ||||
| 			res = memory.WinsatTest(language) | ||||
| 			realTestMethod = "winsat" | ||||
| 		case "dd": | ||||
| 			res = memory.WindowsDDTest(language) | ||||
| 			if res == "" || strings.TrimSpace(res) == "" { | ||||
| 				res += memory.WinsatTest(language) | ||||
| 				realTestMethod = "winsat" | ||||
| 			} else { | ||||
| 				realTestMethod = "dd" | ||||
| 			} | ||||
| 		case "sysbench": | ||||
| 			res = memory.WinsatTest(language) | ||||
| 			realTestMethod = "winsat" | ||||
| 		case "auto", "winsat": | ||||
| 			res = memory.WinsatTest(language) | ||||
| 			realTestMethod = "winsat" | ||||
| 		default: | ||||
| 			res = memory.WinsatTest(language) | ||||
| 			realTestMethod = "winsat" | ||||
| 		} | ||||
| 		res += memory.WinsatTest(language) | ||||
| 	} else { | ||||
| 		switch testMethod { | ||||
| 		case "stream": | ||||
| 			res = memory.StreamTest(language) | ||||
| 			if res == "" || strings.TrimSpace(res) == "" { | ||||
| 				res += memory.DDTest(language) | ||||
| 				realTestMethod = "dd" | ||||
| 			} else { | ||||
| 				realTestMethod = "stream" | ||||
| 			} | ||||
| 		case "dd": | ||||
| 			res = memory.DDTest(language) | ||||
| 			realTestMethod = "dd" | ||||
| 		case "sysbench": | ||||
| 			res = memory.SysBenchTest(language) | ||||
| 			if res == "" { | ||||
| 				// res = "sysbench test failed, switch to use dd test.\n" | ||||
| 			if res == "" || strings.TrimSpace(res) == "" { | ||||
| 				res += memory.DDTest(language) | ||||
| 				realTestMethod = "dd" | ||||
| 			} else { | ||||
| 				realTestMethod = "sysbench" | ||||
| 			} | ||||
| 		case "dd": | ||||
| 		case "auto": | ||||
| 			res = memory.StreamTest(language) | ||||
| 			if res == "" || strings.TrimSpace(res) == "" { | ||||
| 				res = memory.DDTest(language) | ||||
| 				if res == "" || strings.TrimSpace(res) == "" { | ||||
| 					res = memory.SysBenchTest(language) | ||||
| 					if res == "" || strings.TrimSpace(res) == "" { | ||||
| 						realTestMethod = "" | ||||
| 					} else { | ||||
| 						realTestMethod = "sysbench" | ||||
| 					} | ||||
| 				} else { | ||||
| 					realTestMethod = "dd" | ||||
| 				} | ||||
| 			} else { | ||||
| 				realTestMethod = "stream" | ||||
| 			} | ||||
| 		case "winsat": | ||||
| 			// winsat 仅 Windows 支持,非 Windows fallback 到 dd | ||||
| 			res = memory.DDTest(language) | ||||
| 			realTestMethod = "dd" | ||||
| 		default: | ||||
| 			// res = "Unsupported test method, switch to use dd test.\n" | ||||
| 			res += memory.DDTest(language) | ||||
| 			realTestMethod = "dd" | ||||
| 			res = "Unsupported test method" | ||||
| 			realTestMethod = "" | ||||
| 		} | ||||
| 	} | ||||
| 	if !strings.Contains(res, "\n") && res != "" { | ||||
|   | ||||
| @@ -6,6 +6,6 @@ import ( | ||||
| ) | ||||
|  | ||||
| func Test(t *testing.T) { | ||||
| 	_, res := MemoryTest("zh", "sysbench") | ||||
| 	_, res := MemoryTest("zh", "stream") | ||||
| 	fmt.Print(res) | ||||
| } | ||||
|   | ||||
							
								
								
									
										44
									
								
								nexttrace/nexttrace.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								nexttrace/nexttrace.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| package nexttrace | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/oneclickvirt/nt3/nt" | ||||
| ) | ||||
|  | ||||
| func NextTrace3Check(language, nt3Location, nt3CheckType string) { | ||||
| 	resultChan := make(chan nt.TraceResult, 100) | ||||
| 	go nt.TraceRoute(language, nt3Location, nt3CheckType, resultChan) | ||||
| 	for result := range resultChan { | ||||
| 		if result.Index == -1 { | ||||
| 			for index, res := range result.Output { | ||||
| 				res = strings.TrimSpace(res) | ||||
| 				if res != "" && index == 0 { | ||||
| 					fmt.Println(res) | ||||
| 				} | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
| 		if result.ISPName == "Error" { | ||||
| 			for _, res := range result.Output { | ||||
| 				res = strings.TrimSpace(res) | ||||
| 				if res != "" { | ||||
| 					fmt.Println(res) | ||||
| 				} | ||||
| 			} | ||||
| 			return | ||||
| 		} | ||||
| 		for _, res := range result.Output { | ||||
| 			res = strings.TrimSpace(res) | ||||
| 			if res == "" { | ||||
| 				continue | ||||
| 			} | ||||
| 			if strings.Contains(res, "ICMP") { | ||||
| 				fmt.Print(res) | ||||
| 			} else { | ||||
| 				fmt.Println(res) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										13
									
								
								nexttrace/nexttrace_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								nexttrace/nexttrace_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| package nexttrace | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| func TestNextTrace3Check(t *testing.T) { | ||||
| 	start := time.Now() | ||||
| 	NextTrace3Check("zh", "ALL", "ipv4") | ||||
| 	duration := time.Since(start) | ||||
| 	t.Logf("执行耗时: %s", duration) | ||||
| } | ||||
| @@ -6,5 +6,5 @@ import ( | ||||
| ) | ||||
|  | ||||
| func Test(t *testing.T) { | ||||
| 	fmt.Print("%s", MediaTest("zh")) | ||||
| 	fmt.Printf("%s", MediaTest("zh")) | ||||
| } | ||||
|   | ||||
							
								
								
									
										66
									
								
								upstreams/upstreams.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								upstreams/upstreams.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | ||||
| package upstreams | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/oneclickvirt/UnlockTests/uts" | ||||
| 	bgptools "github.com/oneclickvirt/backtrace/bgptools" | ||||
| 	backtrace "github.com/oneclickvirt/backtrace/bk" | ||||
| 	. "github.com/oneclickvirt/defaultset" | ||||
| ) | ||||
|  | ||||
| type IpInfo struct { | ||||
| 	Ip      string `json:"ip"` | ||||
| 	City    string `json:"city"` | ||||
| 	Region  string `json:"region"` | ||||
| 	Country string `json:"country"` | ||||
| 	Org     string `json:"org"` | ||||
| } | ||||
|  | ||||
| type ConcurrentResults struct { | ||||
| 	bgpResult       string | ||||
| 	backtraceResult string | ||||
| 	bgpError        error | ||||
| 	// backtraceError  error | ||||
| } | ||||
|  | ||||
| var IPV4, IPV6 string | ||||
|  | ||||
| func UpstreamsCheck() { | ||||
| 	results := ConcurrentResults{} | ||||
| 	var wg sync.WaitGroup | ||||
| 	if IPV4 != "" { | ||||
| 		wg.Add(1) | ||||
| 		go func() { | ||||
| 			defer wg.Done() | ||||
| 			for i := 0; i < 2; i++ { | ||||
| 				result, err := bgptools.GetPoPInfo(IPV4) | ||||
| 				results.bgpError = err | ||||
| 				if err == nil && result.Result != "" { | ||||
| 					results.bgpResult = result.Result | ||||
| 					return | ||||
| 				} | ||||
| 				if i == 0 { | ||||
| 					time.Sleep(3 * time.Second) | ||||
| 				} | ||||
| 			} | ||||
| 		}() | ||||
| 	} | ||||
| 	wg.Add(1) | ||||
| 	go func() { | ||||
| 		defer wg.Done() | ||||
| 		result := backtrace.BackTrace(uts.IPV6) | ||||
| 		results.backtraceResult = result | ||||
| 	}() | ||||
| 	wg.Wait() | ||||
| 	if results.bgpResult != "" { | ||||
| 		fmt.Print(results.bgpResult) | ||||
| 	} | ||||
| 	if results.backtraceResult != "" { | ||||
| 		fmt.Printf("%s\n", results.backtraceResult) | ||||
| 	} | ||||
| 	fmt.Println(Yellow("准确线路自行查看详细路由,本测试结果仅作参考")) | ||||
| 	fmt.Println(Yellow("同一目标地址多个线路时,检测可能已越过汇聚层,除第一个线路外,后续信息可能无效")) | ||||
| } | ||||
							
								
								
									
										8
									
								
								upstreams/uptreams_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								upstreams/uptreams_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| package upstreams | ||||
|  | ||||
| import "testing" | ||||
|  | ||||
| func TestUpstreamsCheck(t *testing.T) { | ||||
| 	IPV4 = "148.100.85.25" | ||||
| 	UpstreamsCheck() | ||||
| } | ||||
							
								
								
									
										140
									
								
								utils/utils.go
									
									
									
									
									
								
							
							
						
						
									
										140
									
								
								utils/utils.go
									
									
									
									
									
								
							| @@ -11,6 +11,7 @@ import ( | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"regexp" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| @@ -18,12 +19,28 @@ import ( | ||||
|  | ||||
| 	"github.com/imroc/req/v3" | ||||
| 	"github.com/oneclickvirt/UnlockTests/uts" | ||||
| 	bnetwork "github.com/oneclickvirt/basics/network" | ||||
| 	"github.com/oneclickvirt/basics/system" | ||||
| 	butils "github.com/oneclickvirt/basics/utils" | ||||
| 	. "github.com/oneclickvirt/defaultset" | ||||
| 	"github.com/oneclickvirt/security/network" | ||||
| ) | ||||
|  | ||||
| // 获取本程序本日及总执行的统计信息 | ||||
| type StatsResponse struct { | ||||
| 	Counter   string `json:"counter"` | ||||
| 	Action    string `json:"action"` | ||||
| 	Total     int    `json:"total"` | ||||
| 	Daily     int    `json:"daily"` | ||||
| 	Date      string `json:"date"` | ||||
| 	Timestamp string `json:"timestamp"` | ||||
| } | ||||
|  | ||||
| // 获取最新的Github的仓库中的版本 | ||||
| type GitHubRelease struct { | ||||
| 	TagName string `json:"tag_name"` | ||||
| } | ||||
|  | ||||
| // PrintCenteredTitle 根据指定的宽度打印居中标题 | ||||
| func PrintCenteredTitle(title string, width int) { | ||||
| 	// 计算字符串的字符数 | ||||
| @@ -39,13 +56,13 @@ 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" + | ||||
| 		fmt.Println("测评频道: https://t.me/+UHVoo2U4VyA5NTQ1\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" + | ||||
| 		fmt.Println("Review Channel: https://t.me/+UHVoo2U4VyA5NTQ1\n" + | ||||
| 			"Go Project: https://github.com/oneclickvirt/ecs\n" + | ||||
| 			"Shell Project: https://github.com/spiritLHLS/ecs") | ||||
| 	} | ||||
| @@ -99,18 +116,38 @@ func CheckChina(enableLogger bool) bool { | ||||
| 	return selectChina | ||||
| } | ||||
|  | ||||
| // OnlyBasicsIpInfo 仅检查和输出IP信息 | ||||
| func OnlyBasicsIpInfo(language string) (string, string, string) { | ||||
| 	ipv4, ipv6, ipInfo, _, err := bnetwork.NetworkCheck("both", false, language) | ||||
| 	if err != nil { | ||||
| 		return "", "", "" | ||||
| 	} | ||||
| 	basicInfo := ipInfo | ||||
| 	if strings.Contains(ipInfo, "IPV4") && strings.Contains(ipInfo, "IPV6") && ipv4 != "" && ipv6 != "" { | ||||
| 		uts.IPV4 = true | ||||
| 		uts.IPV6 = true | ||||
| 	} else if strings.Contains(ipInfo, "IPV4") && ipv4 != "" { | ||||
| 		uts.IPV4 = true | ||||
| 		uts.IPV6 = false | ||||
| 	} else if strings.Contains(ipInfo, "IPV6") && ipv6 != "" { | ||||
| 		uts.IPV6 = true | ||||
| 		uts.IPV4 = false | ||||
| 	} | ||||
| 	basicInfo = strings.ReplaceAll(basicInfo, "\n\n", "\n") | ||||
| 	return ipv4, ipv6, basicInfo | ||||
| } | ||||
|  | ||||
| // BasicsAndSecurityCheck 执行安全检查 | ||||
| func BasicsAndSecurityCheck(language, nt3CheckType string, securityCheckStatus bool) (string, string, string) { | ||||
| func BasicsAndSecurityCheck(language, nt3CheckType string, securityCheckStatus bool) (string, string, string, string, string) { | ||||
| 	var wgt sync.WaitGroup | ||||
| 	var ipInfo, securityInfo, systemInfo string | ||||
| 	var err error | ||||
| 	var ipv4, ipv6, ipInfo, securityInfo, systemInfo string | ||||
| 	wgt.Add(1) | ||||
| 	go func() { | ||||
| 		defer wgt.Done() | ||||
| 		ipInfo, securityInfo, err = network.NetworkCheck("both", securityCheckStatus, language) | ||||
| 		if err != nil { | ||||
| 			fmt.Println(err.Error()) | ||||
| 		} | ||||
| 		ipv4, ipv6, ipInfo, securityInfo, _ = network.NetworkCheck("both", securityCheckStatus, language) | ||||
| 		// if err != nil { | ||||
| 		// 	fmt.Println(err.Error()) | ||||
| 		// } | ||||
| 	}() | ||||
| 	wgt.Add(1) | ||||
| 	go func() { | ||||
| @@ -119,19 +156,19 @@ func BasicsAndSecurityCheck(language, nt3CheckType string, securityCheckStatus b | ||||
| 	}() | ||||
| 	wgt.Wait() | ||||
| 	basicInfo := systemInfo + ipInfo | ||||
| 	if strings.Contains(ipInfo, "IPV4") && strings.Contains(ipInfo, "IPV6") { | ||||
| 	if strings.Contains(ipInfo, "IPV4") && strings.Contains(ipInfo, "IPV6") && ipv4 != "" && ipv6 != "" { | ||||
| 		uts.IPV4 = true | ||||
| 		uts.IPV6 = true | ||||
| 		if nt3CheckType == "" { | ||||
| 			nt3CheckType = "ipv4" | ||||
| 		} | ||||
| 	} else if strings.Contains(ipInfo, "IPV4") { | ||||
| 	} else if strings.Contains(ipInfo, "IPV4") && ipv4 != "" { | ||||
| 		uts.IPV4 = true | ||||
| 		uts.IPV6 = false | ||||
| 		if nt3CheckType == "" { | ||||
| 			nt3CheckType = "ipv4" | ||||
| 		} | ||||
| 	} else if strings.Contains(ipInfo, "IPV6") { | ||||
| 	} else if strings.Contains(ipInfo, "IPV6") && ipv6 != "" { | ||||
| 		uts.IPV6 = true | ||||
| 		uts.IPV4 = false | ||||
| 		if nt3CheckType == "" { | ||||
| @@ -144,7 +181,7 @@ func BasicsAndSecurityCheck(language, nt3CheckType string, securityCheckStatus b | ||||
| 		nt3CheckType = "ipv4" | ||||
| 	} | ||||
| 	basicInfo = strings.ReplaceAll(basicInfo, "\n\n", "\n") | ||||
| 	return basicInfo, securityInfo, nt3CheckType | ||||
| 	return ipv4, ipv6, basicInfo, securityInfo, nt3CheckType | ||||
| } | ||||
|  | ||||
| // CaptureOutput 捕获函数输出和错误输出,实时输出,并返回字符串 | ||||
| @@ -336,8 +373,6 @@ func ProcessAndUpload(output string, filePath string, enableUplaod bool) (string | ||||
| 	return "", "" | ||||
| } | ||||
|  | ||||
| // ============================= 前置联网能力检测 ============================= | ||||
|  | ||||
| var StackType string | ||||
|  | ||||
| type NetCheckResult struct { | ||||
| @@ -359,6 +394,7 @@ func makeResolver(proto, dnsAddr string) *net.Resolver { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // 前置联网能力检测 | ||||
| func CheckPublicAccess(timeout time.Duration) NetCheckResult { | ||||
| 	if timeout < 2*time.Second { | ||||
| 		timeout = 2 * time.Second | ||||
| @@ -492,3 +528,77 @@ result: | ||||
| 		StackType: stack, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // 获取每日/总的程序执行统计信息 | ||||
| func GetGoescStats() (*StatsResponse, error) { | ||||
| 	client := req.C().SetTimeout(5 * time.Second) | ||||
| 	var stats StatsResponse | ||||
| 	resp, err := client.R(). | ||||
| 		SetSuccessResult(&stats). | ||||
| 		Get("https://hits.spiritlhl.net/goecs") | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if !resp.IsSuccessState() { | ||||
| 		return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode) | ||||
| 	} | ||||
| 	return &stats, nil | ||||
| } | ||||
|  | ||||
| // 统计结果单位转换 | ||||
| func FormatGoecsNumber(num int) string { | ||||
| 	if num >= 1000000 { | ||||
| 		return fmt.Sprintf("%.1fM", float64(num)/1000000) | ||||
| 	} else if num >= 1000 { | ||||
| 		return fmt.Sprintf("%.1fK", float64(num)/1000) | ||||
| 	} | ||||
| 	return fmt.Sprintf("%d", num) | ||||
| } | ||||
|  | ||||
| // 通过Github的API检索仓库最新TAG的版本 | ||||
| func GetLatestEcsRelease() (*GitHubRelease, error) { | ||||
| 	urls := []string{ | ||||
| 		"https://api.github.com/repos/oneclickvirt/ecs/releases/latest", | ||||
| 		"https://fd.spiritlhl.top/https://api.github.com/repos/oneclickvirt/ecs/releases/latest", | ||||
| 		"https://githubapi.spiritlhl.top/repos/oneclickvirt/ecs/releases/latest", | ||||
| 		"https://githubapi.spiritlhl.workers.dev/repos/oneclickvirt/ecs/releases/latest", | ||||
| 	} | ||||
| 	client := req.C().SetTimeout(3 * time.Second) | ||||
| 	for _, url := range urls { | ||||
| 		var release GitHubRelease | ||||
| 		resp, err := client.R(). | ||||
| 			SetSuccessResult(&release). | ||||
| 			Get(url) | ||||
| 		if err != nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		if resp.IsSuccessState() && release.TagName != "" { | ||||
| 			return &release, nil | ||||
| 		} | ||||
| 	} | ||||
| 	return nil, fmt.Errorf("failed to fetch release from all sources") | ||||
| } | ||||
|  | ||||
| // 比较程序版本是否需要升级 | ||||
| func CompareVersions(v1, v2 string) int { | ||||
| 	normalize := func(s string) []int { | ||||
| 		s = strings.TrimPrefix(strings.ToLower(s), "v") | ||||
| 		parts := strings.Split(s, ".") | ||||
| 		result := make([]int, 3) | ||||
| 		for i := 0; i < 3 && i < len(parts); i++ { | ||||
| 			n, _ := strconv.Atoi(parts[i]) | ||||
| 			result[i] = n | ||||
| 		} | ||||
| 		return result | ||||
| 	} | ||||
| 	a := normalize(v1) | ||||
| 	b := normalize(v2) | ||||
| 	for i := 0; i < 3; i++ { | ||||
| 		if a[i] < b[i] { | ||||
| 			return -1 | ||||
| 		} else if a[i] > b[i] { | ||||
| 			return 1 | ||||
| 		} | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|   | ||||
| @@ -20,11 +20,11 @@ func TestBasicsAndSecurityCheck(t *testing.T) { | ||||
| 	timeout := 3 * time.Second | ||||
| 	result := CheckPublicAccess(timeout) | ||||
| 	if result.Connected { | ||||
| 		fmt.Print("✅ 本机有公网连接,类型: %s\n", result.StackType) | ||||
| 		fmt.Printf("✅ 本机有公网连接,类型: %s\n", result.StackType) | ||||
| 	} else { | ||||
| 		fmt.Println("❌ 本机未检测到公网连接") | ||||
| 	} | ||||
| 	basicInfo, securityInfo, nt3CheckType := BasicsAndSecurityCheck("zh", "ipv4", false) | ||||
| 	_, _, basicInfo, securityInfo, nt3CheckType := BasicsAndSecurityCheck("zh", "ipv4", false) | ||||
| 	fmt.Println(basicInfo) | ||||
| 	fmt.Println(securityInfo) | ||||
| 	fmt.Println(nt3CheckType) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user