mirror of
				https://github.com/oneclickvirt/ecs.git
				synced 2025-10-31 02:46:40 +08:00 
			
		
		
		
	Compare commits
	
		
			33 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 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 | 
							
								
								
									
										10
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								README.md
									
									
									
									
									
								
							| @@ -47,8 +47,8 @@ Shell 版本:[https://github.com/spiritLHLS/ecs](https://github.com/spiritLHLS | |||||||
| |----------------|---------------------------| | |----------------|---------------------------| | ||||||
| | Android(arm64) | 存在权限问题未修复,非安卓系统的ARM架构无问题      | | | Android(arm64) | 存在权限问题未修复,非安卓系统的ARM架构无问题      | | ||||||
| | OpenBSD/NetBSD | 部分Goalng的官方库未支持本系统(尤其是net相关项目)  | | | OpenBSD/NetBSD | 部分Goalng的官方库未支持本系统(尤其是net相关项目)  | | ||||||
| | Windows虚拟机   | 非物理机器不支持winsat测试硬件性能(硬盘和内存测试) | | | Windows虚拟机   | 无Admin权限的mbw测试性能不准确(内存测试) | | ||||||
| | Windows物理机(非Admin下)   | 无Admin权限不支持winsat测试硬件性能(硬盘和内存测试) | | | Windows物理机(非Admin下)   | 无Admin权限的mbw测试性能不准确(内存测试) | | ||||||
| --- | --- | ||||||
|  |  | ||||||
| ## **功能** | ## **功能** | ||||||
| @@ -61,7 +61,7 @@ Shell 版本:[https://github.com/spiritLHLS/ecs](https://github.com/spiritLHLS | |||||||
| - 常见流媒体测试并发查询:[UnlockTests](https://github.com/oneclickvirt/UnlockTests),逻辑借鉴 [RegionRestrictionCheck](https://github.com/lmc999/RegionRestrictionCheck) 等 | - 常见流媒体测试并发查询:[UnlockTests](https://github.com/oneclickvirt/UnlockTests),逻辑借鉴 [RegionRestrictionCheck](https://github.com/lmc999/RegionRestrictionCheck) 等 | ||||||
| - IP 质量/安全信息并发查询:二进制文件编译至 [securityCheck](https://github.com/oneclickvirt/securityCheck) | - IP 质量/安全信息并发查询:二进制文件编译至 [securityCheck](https://github.com/oneclickvirt/securityCheck) | ||||||
| - 邮件端口测试:[portchecker](https://github.com/oneclickvirt/portchecker) | - 邮件端口测试:[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) | - 三网路由测试:基于 [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) | - 网速测试:基于 [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) | - 三网 Ping 值测试:借鉴 [ecsspeed](https://github.com/spiritLHLS/ecsspeed),二次开发至 [pingtest](https://github.com/oneclickvirt/pingtest) | ||||||
| @@ -398,6 +398,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;"> |   <img src="https://console.zmto.com/templates/2019/dist/images/logo_dark.svg" alt="zmto" style="height: 50px;"> | ||||||
| </a> | </a> | ||||||
|  |  | ||||||
|  | ## History Usage | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ## Stargazers over time | ## Stargazers over time | ||||||
|  |  | ||||||
| [](https://www.spiritlhl.net) | [](https://www.spiritlhl.net) | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								README_EN.md
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								README_EN.md
									
									
									
									
									
								
							| @@ -1,7 +1,9 @@ | |||||||
| # ecs | # ECS | ||||||
|  |  | ||||||
| [](https://github.com/oneclickvirt/ecs/actions/workflows/build_binary.yaml) | [](https://github.com/oneclickvirt/ecs/actions/workflows/build_binary.yaml) | ||||||
|  |  | ||||||
|  | [](https://app.fossa.com/projects/git%2Bgithub.com%2Foneclickvirt%2Fecs?ref=badge_shield) | ||||||
|  |  | ||||||
| [](https://hits.spiritlhl.net) | [](https://hits.spiritlhl.net) | ||||||
|  |  | ||||||
| Fusion Monster Evaluation Project - GO Version | Fusion Monster Evaluation Project - GO Version | ||||||
| @@ -45,8 +47,8 @@ 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    | | | 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) | | | 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(Virtual Machines) | Inaccurate mbw test performance without Admin rights (memory tests) |  | ||||||
| | Windows(Physical Machines)(not under Admin) | No Admin privileges do not support winsat to test hardware performance (hard disk and memory tests) | | | Windows(Physical Machines)(not under Admin) | Inaccurate mbw test performance without Admin rights (memory tests) | | ||||||
|  |  | ||||||
| --- | --- | ||||||
|  |  | ||||||
| @@ -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 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 | | | 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 | | | 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. | Note that `goecs` allows you to specify CPU test method via parameters. The default is chosen for faster testing across more systems. | ||||||
|  |  | ||||||
| @@ -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;"> |   <img src="https://console.zmto.com/templates/2019/dist/images/logo_dark.svg" alt="zmto" style="height: 50px;"> | ||||||
| </a> | </a> | ||||||
|  |  | ||||||
|  | ## History Usage | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ## Stargazers over time | ## Stargazers over time | ||||||
|  |  | ||||||
| [](https://www.spiritlhl.net) | [](https://www.spiritlhl.net) | ||||||
|  |  | ||||||
|  | ## License | ||||||
|  | [](https://app.fossa.com/projects/git%2Bgithub.com%2Foneclickvirt%2Fecs?ref=badge_large) | ||||||
|   | |||||||
| @@ -15,7 +15,7 @@ | |||||||
| - [流媒体解锁](#流媒体解锁) | - [流媒体解锁](#流媒体解锁) | ||||||
| - [IP质量检测](#IP质量检测) | - [IP质量检测](#IP质量检测) | ||||||
| - [邮件端口检测](#邮件端口检测) | - [邮件端口检测](#邮件端口检测) | ||||||
| - [三网回城线路检测](#三网回城线路检测) | - [上游及回程线路检测](#上游及回程线路检测) | ||||||
| - [三网回程路由检测](#三网回程路由检测) | - [三网回程路由检测](#三网回程路由检测) | ||||||
| - [就近测速](#就近测速) | - [就近测速](#就近测速) | ||||||
|  |  | ||||||
| @@ -101,6 +101,7 @@ IPV6 子网掩码:根据宿主机信息查询的本机IPV6子网大小 | |||||||
| | 测试稳定性       | 核心测试组件10年以上未变 | 每个大版本更新测试项,分数不同版本间难以对比(每个版本对标当前最好的CPU) | | | 测试稳定性       | 核心测试组件10年以上未变 | 每个大版本更新测试项,分数不同版本间难以对比(每个版本对标当前最好的CPU) | | ||||||
| | 测试内容         | 仅测试计算性能,基于素数计算 | 覆盖多种性能测试,分数加权计算,但部分测试实际不常用 | | | 测试内容         | 仅测试计算性能,基于素数计算 | 覆盖多种性能测试,分数加权计算,但部分测试实际不常用 | | ||||||
| | 适用场景         | 适合快速测试,仅测试计算性能 | 适合综合全面的测试 | | | 适用场景         | 适合快速测试,仅测试计算性能 | 适合综合全面的测试 | | ||||||
|  | | 排行榜         | [sysbench.spiritlhl.net](https://sysbench.spiritlhl.net/) | [browser.geekbench.com](https://browser.geekbench.com/) | | ||||||
|  |  | ||||||
| 默认使用```Sysbench```进行测试,基准大致如下: | 默认使用```Sysbench```进行测试,基准大致如下: | ||||||
|  |  | ||||||
| @@ -186,11 +187,39 @@ AMD的7950x单核满血性能得分在6500左右,AMD的5950x单核满血性能 | |||||||
|  |  | ||||||
| 具体当前宿主机不做邮局或者不收电子邮件,那么该项目指标不用理会。 | 具体当前宿主机不做邮局或者不收电子邮件,那么该项目指标不用理会。 | ||||||
|  |  | ||||||
| ### **三网回程线路检测** | ### **上游及回程线路检测** | ||||||
|  |  | ||||||
| 检测当前的宿主机的IP地址 到 四个主要POP点城市的三个主要运营商的接入点的IP地址 的线路,具体来说 | #### 上游类型与运营商等级说明 | ||||||
|  |  | ||||||
| 电信163、联通4837、移动CMI 是常见的线路 | - **直接上游(Direct Upstream)**   | ||||||
|  |   当前运营商直接购买网络服务的上级运营商,通常是 BGP 邻居。 | ||||||
|  |  | ||||||
|  | - **间接上游(Indirect Upstream)**   | ||||||
|  |   直接上游的上级,形成层层向上的关系链。可通过 BGP 路由路径中的多跳信息识别。 | ||||||
|  |  | ||||||
|  | | 等级 | 描述 | | ||||||
|  | |------|------| | ||||||
|  | | **Tier 1 Global** | 全球顶级运营商(如 AT&T、Verizon、NTT、Telia 等),之间免费互联(Settlement-Free Peering),不依赖他人即可访问全球任意网络。 | | ||||||
|  | | **Tier 1 Regional** | 区域性顶级运营商,在特定区域具有一级能力,但在全球范围互联性稍弱。 | | ||||||
|  | | **Tier 1 Indirect** | 间接连接的 Tier 1(非直接购买),通过中间上游间接接入 Tier 1 网络。 | | ||||||
|  | | **Tier 2** | 需要向 Tier 1 付费购买上网能力的二级运营商,通常是各国主流电信商或 ISP。 | | ||||||
|  | | **CDN Provider** | 内容分发网络提供商,如 Cloudflare、Akamai、Fastly 等,主要用于内容加速而非传统上游。 | | ||||||
|  | | **Direct/Indirect Others** | 其他类型的直接或间接连接,如 IX(Internet Exchange)成员、私有对等互联等。 | | ||||||
|  |  | ||||||
|  | 上游质量判断:直接接入的高等级上游(特别是 Tier 1 Global)越多,通常网络连通性越好。但实际网络质量也受到以下因素影响: | ||||||
|  |  | ||||||
|  |   - 上下游之间的商业结算关系; | ||||||
|  |   - 购买的带宽套餐和服务质量; | ||||||
|  |   - 对等端口(Peering Ports)大小和负载; | ||||||
|  |   - 网络拥塞、路由策略、延迟路径等。 | ||||||
|  |  | ||||||
|  | 无法完全从 BGP 路由中判断。 | ||||||
|  |  | ||||||
|  | 一般来说,**接入高质量上游越多,网络连通性越优**。但由于存在诸多不可见的商业和技术因素,**无法仅凭上游等级准确判断网络质量**,上游检测约等于图一乐,实际得看对应的路由情况和长时间Ping的情况。 | ||||||
|  |  | ||||||
|  | 然后是检测当前的宿主机的IP地址 到 四个主要POP点城市的三个主要运营商的接入点的IP地址 的线路,具体来说 | ||||||
|  |  | ||||||
|  | 电信163、联通4837、移动CMI 是常见的线路,移动CMI对两广地区的移动运营商特供延迟低,也能算优质,仅限两广移动。 | ||||||
|  |  | ||||||
| 电信CN2GIA > 电信CN2GT 移动CMIN2 联通9929 算优质的线路 | 电信CN2GIA > 电信CN2GT 移动CMIN2 联通9929 算优质的线路 | ||||||
|  |  | ||||||
| @@ -198,9 +227,9 @@ AMD的7950x单核满血性能得分在6500左右,AMD的5950x单核满血性能 | |||||||
|  |  | ||||||
| ### **三网回程路由检测** | ### **三网回程路由检测** | ||||||
|  |  | ||||||
| 默认检测广州为目的地,实际可使用命令行参数指定目的地,见对应的说明。 | 默认检测广州为目的地,实际可使用命令行参数指定目的地,见对应的参数说明。 | ||||||
|  |  | ||||||
| 主要就是看是不是直连,是不是延迟低,是不是没有隐藏路由信息。如果路由全球跑,延迟起飞,那么线路自然不会好到哪里去。 | 主要就是看是不是直连,是不是延迟低,是不是没有隐藏路由信息。如果路由全球跑,延迟起飞,那么线路自然不会好到哪里去。有时候路由信息完全藏起来了,只知道实际使用的延迟低,实际可能也是优质线路只是查不到信息,这就没办法直接识别了。 | ||||||
|  |  | ||||||
| ### **就近测速** | ### **就近测速** | ||||||
|  |  | ||||||
| @@ -272,6 +301,7 @@ Supports selecting `GeekBench` and `Sysbench` for testing through command line p | |||||||
| | Test Stability | Core test components unchanged for over 10 years | Test items updated with each major version, scores difficult to compare between different versions (each version benchmarks against current best CPUs) | | | Test Stability | Core test components unchanged for over 10 years | Test items updated with each major version, scores difficult to compare between different versions (each version benchmarks against current best CPUs) | | ||||||
| | Test Content | Only tests computational performance, based on prime number calculation | Covers multiple performance tests, weighted score calculation, but some tests are not commonly used in practice | | | Test Content | Only tests computational performance, based on prime number calculation | Covers multiple performance tests, weighted score calculation, but some tests are not commonly used in practice | | ||||||
| | Applicable Scenarios | Suitable for quick testing, only tests computational performance | Suitable for comprehensive testing | | | Applicable Scenarios | Suitable for quick testing, only tests computational performance | Suitable for comprehensive testing | | ||||||
|  | | Ranking         | [sysbench.spiritlhl.net](https://sysbench.spiritlhl.net/) | [browser.geekbench.com](https://browser.geekbench.com/) | | ||||||
|  |  | ||||||
| By default, ```Sysbench``` is used for testing, with the baseline roughly as follows: | By default, ```Sysbench``` is used for testing, with the baseline roughly as follows: | ||||||
|  |  | ||||||
|   | |||||||
| @@ -8,36 +8,30 @@ import ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
| func DiskTest(language, testMethod, testPath string, isMultiCheck bool, autoChange bool) (realTestMethod, res string) { | func DiskTest(language, testMethod, testPath string, isMultiCheck bool, autoChange bool) (realTestMethod, res string) { | ||||||
| 	if runtime.GOOS == "windows" { | 	switch testMethod { | ||||||
| 		if testMethod != "winsat" && testMethod != "" { | 	case "fio": | ||||||
| 			// res = "Detected host is Windows, using Winsat for testing.\n" | 		res = disk.FioTest(language, isMultiCheck, testPath) | ||||||
| 			realTestMethod = "winsat" | 		if res == "" && autoChange { | ||||||
| 		} |  | ||||||
| 		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" |  | ||||||
| 			res += disk.DDTest(language, isMultiCheck, testPath) | 			res += disk.DDTest(language, isMultiCheck, testPath) | ||||||
| 			realTestMethod = "dd" | 			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 != "" { | 	if !strings.Contains(res, "\n") && res != "" { | ||||||
|   | |||||||
							
								
								
									
										18
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								go.mod
									
									
									
									
									
								
							| @@ -6,17 +6,17 @@ require ( | |||||||
| 	github.com/imroc/req/v3 v3.54.0 | 	github.com/imroc/req/v3 v3.54.0 | ||||||
| 	github.com/oneclickvirt/CommonMediaTests v0.0.4-20250329123841 | 	github.com/oneclickvirt/CommonMediaTests v0.0.4-20250329123841 | ||||||
| 	github.com/oneclickvirt/UnlockTests v0.0.28-20250727155204 | 	github.com/oneclickvirt/UnlockTests v0.0.28-20250727155204 | ||||||
| 	github.com/oneclickvirt/backtrace v0.0.5-20250727160732 | 	github.com/oneclickvirt/backtrace v0.0.7-20250811023541 | ||||||
| 	github.com/oneclickvirt/basics v0.0.15-20250728021329 | 	github.com/oneclickvirt/basics v0.0.15-20250805084236 | ||||||
| 	github.com/oneclickvirt/cputest v0.0.12-20250720122317 | 	github.com/oneclickvirt/cputest v0.0.12-20250720122317 | ||||||
| 	github.com/oneclickvirt/defaultset v0.0.2-20240624082446 | 	github.com/oneclickvirt/defaultset v0.0.2-20240624082446 | ||||||
| 	github.com/oneclickvirt/disktest v0.0.8-20250701092629 | 	github.com/oneclickvirt/disktest v0.0.10-20250808140407 | ||||||
| 	github.com/oneclickvirt/gostun v0.0.5-20250727155022 | 	github.com/oneclickvirt/gostun v0.0.5-20250727155022 | ||||||
| 	github.com/oneclickvirt/memorytest v0.0.9-20250720135728 | 	github.com/oneclickvirt/memorytest v0.0.9-20250808065154 | ||||||
| 	github.com/oneclickvirt/nt3 v0.0.6-20250726150925 | 	github.com/oneclickvirt/nt3 v0.0.8-20250810151538 | ||||||
| 	github.com/oneclickvirt/pingtest v0.0.8-20250728015259 | 	github.com/oneclickvirt/pingtest v0.0.8-20250728015259 | ||||||
| 	github.com/oneclickvirt/portchecker v0.0.3-20250728015900 | 	github.com/oneclickvirt/portchecker v0.0.3-20250728015900 | ||||||
| 	github.com/oneclickvirt/security v0.0.6-20250727160145 | 	github.com/oneclickvirt/security v0.0.6-20250805090112 | ||||||
| 	github.com/oneclickvirt/speedtest v0.0.10-20250728015734 | 	github.com/oneclickvirt/speedtest v0.0.10-20250728015734 | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -58,9 +58,9 @@ require ( | |||||||
| 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect | 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect | ||||||
| 	github.com/modern-go/reflect2 v1.0.2 // indirect | 	github.com/modern-go/reflect2 v1.0.2 // indirect | ||||||
| 	github.com/nxtrace/NTrace-core v1.4.2 // indirect | 	github.com/nxtrace/NTrace-core v1.4.2 // indirect | ||||||
| 	github.com/oneclickvirt/dd v0.0.2-20250701085922 // indirect | 	github.com/oneclickvirt/dd v0.0.2-20250808062818 // indirect | ||||||
| 	github.com/oneclickvirt/fio v0.0.2-20250701085933 // indirect | 	github.com/oneclickvirt/fio v0.0.2-20250808045755 // indirect | ||||||
| 	github.com/oneclickvirt/mbw v0.0.1-20250630140849 // indirect | 	github.com/oneclickvirt/mbw v0.0.1-20250808061222 // indirect | ||||||
| 	github.com/oschwald/maxminddb-golang v1.13.1 // indirect | 	github.com/oschwald/maxminddb-golang v1.13.1 // indirect | ||||||
| 	github.com/pelletier/go-toml/v2 v2.2.4 // indirect | 	github.com/pelletier/go-toml/v2 v2.2.4 // indirect | ||||||
| 	github.com/pion/dtls/v2 v2.2.7 // indirect | 	github.com/pion/dtls/v2 v2.2.7 // indirect | ||||||
|   | |||||||
							
								
								
									
										36
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								go.sum
									
									
									
									
									
								
							| @@ -98,34 +98,34 @@ github.com/oneclickvirt/CommonMediaTests v0.0.4-20250329123841 h1:Zef93z9UiZQwRA | |||||||
| github.com/oneclickvirt/CommonMediaTests v0.0.4-20250329123841/go.mod h1:DAmFPRjFV5p9fEzUUSml5jJGn2f1NZJQCzTxITHDjc4= | github.com/oneclickvirt/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 h1:apFaEbHGKflYMZzK17nXzEai4GG873mTd+d9hCO/KdY= | ||||||
| github.com/oneclickvirt/UnlockTests v0.0.28-20250727155204/go.mod h1:oOa6wj/qECtRMxwBO6D7o0L0F0Q/5sQ747OCnFQqoGE= | 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.7-20250811023541 h1:GzkzvUC6U9b6Dkz/Bl4JRPeQ7XBGoW7Qw1aWqzhF+MQ= | ||||||
| github.com/oneclickvirt/backtrace v0.0.5-20250727160732/go.mod h1:yxL1ixDmOmEt8NkHnMIetsTXJW8xMslUpEY2L8sYZ4Y= | github.com/oneclickvirt/backtrace v0.0.7-20250811023541/go.mod h1:/+KUtOWz48TyiTTbhVTsp3D6b5WY+4pCgvFBYtUGtns= | ||||||
| github.com/oneclickvirt/basics v0.0.15-20250728021329 h1:bXat5W1twZdOdzJ15BFZUYsjAEcTH9ly9oMDIg5+Rbo= | github.com/oneclickvirt/basics v0.0.15-20250805084236 h1:guYO6wGooSIOAIutuy/zfJ4sXj525nBITw8cjEPRaK8= | ||||||
| github.com/oneclickvirt/basics v0.0.15-20250728021329/go.mod h1:2PV+1ge01zb0Sqzj2V2I7P0wAdFSLF1XgAiumchJJbg= | github.com/oneclickvirt/basics v0.0.15-20250805084236/go.mod h1:2PV+1ge01zb0Sqzj2V2I7P0wAdFSLF1XgAiumchJJbg= | ||||||
| github.com/oneclickvirt/cputest v0.0.12-20250720122317 h1:toiwAK1hZE5b8klu2mOQ7J4sv5yV9lpPKwgPahfRYBQ= | 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/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-20250808062818 h1:0KHrKkdpL5oBE1OHsrRd2siRw4/2k6f9LBaP7T4JpOc= | ||||||
| github.com/oneclickvirt/dd v0.0.2-20250701085922/go.mod h1:tImu9sPTkLWo2tf1dEN1xQzrylWKauj9hbU8PHfyAeU= | 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 h1:5Pg3mK/u/vQvSz7anu0nxzrNdELi/AcDAU1mMsmPzyc= | ||||||
| github.com/oneclickvirt/defaultset v0.0.2-20240624082446/go.mod h1:e9Jt4tf2sbemCtc84/XgKcHy9EZ2jkc5x2sW1NiJS+E= | 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.10-20250808140407 h1:oUfi5zF3htUTB1ZJuClmK0o74ufP7icbu8LYCnxEOxE= | ||||||
| github.com/oneclickvirt/disktest v0.0.8-20250701092629/go.mod h1:6YCvGr+Z0tvcP4Ue8bezZqm/GqS/dSyEnSUhvS3Q03o= | github.com/oneclickvirt/disktest v0.0.10-20250808140407/go.mod h1:Vp3iMVBD4ccReDJz5n5SlzUdq0kDuVhpRklQk21KT+8= | ||||||
| github.com/oneclickvirt/fio v0.0.2-20250701085933 h1:4P7QcOTxbqyx5DhHdFvyeRSsdNajSo9l/H2XK0vICIc= | github.com/oneclickvirt/fio v0.0.2-20250808045755 h1:eWihCRWcalJjPIdrF8dMe68ZiPnMkSfHC8ENvElp/xE= | ||||||
| github.com/oneclickvirt/fio v0.0.2-20250701085933/go.mod h1:NIq+XYTey68KNERGIy/oRDlzpwLzBVoHOCiqX8didsE= | 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 h1:/e3gSUrOp1tg/1NTRx+P8B51OGcP26Q6//5EoSIjOvk= | ||||||
| github.com/oneclickvirt/gostun v0.0.5-20250727155022/go.mod h1:pfp7MFZJK9n/KTLAVqqFcCAns4xqMykmjI+1UeF/vdE= | 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-20250808061222 h1:WGXOe6QvHiDRhPVMI0VcctjzW08kGvJf50yq5YeZCtw= | ||||||
| github.com/oneclickvirt/mbw v0.0.1-20250630140849/go.mod h1:0Vq6NRpyLmGUdfHfL3uDcFsuZhi7KlG+OCs5ky2757Y= | github.com/oneclickvirt/mbw v0.0.1-20250808061222/go.mod h1:0Vq6NRpyLmGUdfHfL3uDcFsuZhi7KlG+OCs5ky2757Y= | ||||||
| github.com/oneclickvirt/memorytest v0.0.9-20250720135728 h1:RusZfaESDXK+k5YYfVXTCW5zLeQEd/dYY80a6xievE0= | github.com/oneclickvirt/memorytest v0.0.9-20250808065154 h1:mjYOvpFz2mpDU9MNjj66oIDcc2r6+zoW8veP616/+4Q= | ||||||
| github.com/oneclickvirt/memorytest v0.0.9-20250720135728/go.mod h1:7xMacjQobvFAtODht2hxTsB9hM2IFS7vZk3gxx+bsjo= | github.com/oneclickvirt/memorytest v0.0.9-20250808065154/go.mod h1:DBxiVZX7mWCe0Fy+qu57ENheLo00sLfjKzvxiICrUtU= | ||||||
| github.com/oneclickvirt/nt3 v0.0.6-20250726150925 h1:M+9kEpMp+O2a//yp9zJ11DleK7hxEmFd5jOWKNrSlmY= | github.com/oneclickvirt/nt3 v0.0.8-20250810151538 h1:pXxtvTwTFWAh/+Hz89wDat42CFjqNdlFyASPRxSdE5g= | ||||||
| github.com/oneclickvirt/nt3 v0.0.6-20250726150925/go.mod h1:O7YkaOMFihB8hwQiD74WTbDlyoTieDwTDBR6jbkZaP0= | github.com/oneclickvirt/nt3 v0.0.8-20250810151538/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 h1:egoxZRZBOWN3JqBwqEsULDyRo2/dpGMeWcmV3U87zig= | ||||||
| github.com/oneclickvirt/pingtest v0.0.8-20250728015259/go.mod h1:gxwsxxwitNQiGq2OI0ZogYoOLwc8DtuOdSRe6/EvRqs= | 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 h1:AomzdppSOFB70AJESQhlp0IPbsHTTJGimAWDk2TzCWM= | ||||||
| github.com/oneclickvirt/portchecker v0.0.3-20250728015900/go.mod h1:9sjMDPCd4Z40wkYB0S9gQPGH8YPtnNE1ZJthVIuHUzA= | 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-20250805090112 h1:lUNtsnpZ3JNLS4xxjFGGECaxA46yNyxbYjdust9W0M4= | ||||||
| github.com/oneclickvirt/security v0.0.6-20250727160145/go.mod h1:WpzPJsQFP0uOHmUUsqT9sjNhD5b+1LFd90HiM8cz4nM= | github.com/oneclickvirt/security v0.0.6-20250805090112/go.mod h1:JB6SJWm5pbrngCgSTYLd2m4Hj8mHO6mJua1WgHMZOcE= | ||||||
| github.com/oneclickvirt/speedtest v0.0.10-20250728015734 h1:HKO7/JQ74ueXA8Wo8NIvcK9DphbEG/YTfAAVz/akSiY= | 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/speedtest v0.0.10-20250728015734/go.mod h1:0W8vnMbA3iucXLXFdGfe9Ia6RPS0izRO7jvu/SnH1P8= | ||||||
| github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE= | github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE= | ||||||
|   | |||||||
							
								
								
									
										240
									
								
								goecs.go
									
									
									
									
									
								
							
							
						
						
									
										240
									
								
								goecs.go
									
									
									
									
									
								
							| @@ -7,6 +7,7 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"os" | 	"os" | ||||||
|  | 	"os/exec" | ||||||
| 	"os/signal" | 	"os/signal" | ||||||
| 	"regexp" | 	"regexp" | ||||||
| 	"runtime" | 	"runtime" | ||||||
| @@ -17,8 +18,6 @@ import ( | |||||||
|  |  | ||||||
| 	"github.com/oneclickvirt/CommonMediaTests/commediatests" | 	"github.com/oneclickvirt/CommonMediaTests/commediatests" | ||||||
| 	unlocktestmodel "github.com/oneclickvirt/UnlockTests/model" | 	unlocktestmodel "github.com/oneclickvirt/UnlockTests/model" | ||||||
| 	"github.com/oneclickvirt/UnlockTests/uts" |  | ||||||
| 	backtrace "github.com/oneclickvirt/backtrace/bk" |  | ||||||
| 	backtracemodel "github.com/oneclickvirt/backtrace/model" | 	backtracemodel "github.com/oneclickvirt/backtrace/model" | ||||||
| 	basicmodel "github.com/oneclickvirt/basics/model" | 	basicmodel "github.com/oneclickvirt/basics/model" | ||||||
| 	cputestmodel "github.com/oneclickvirt/cputest/model" | 	cputestmodel "github.com/oneclickvirt/cputest/model" | ||||||
| @@ -26,13 +25,14 @@ import ( | |||||||
| 	"github.com/oneclickvirt/ecs/cputest" | 	"github.com/oneclickvirt/ecs/cputest" | ||||||
| 	"github.com/oneclickvirt/ecs/disktest" | 	"github.com/oneclickvirt/ecs/disktest" | ||||||
| 	"github.com/oneclickvirt/ecs/memorytest" | 	"github.com/oneclickvirt/ecs/memorytest" | ||||||
|  | 	"github.com/oneclickvirt/ecs/nexttrace" | ||||||
| 	"github.com/oneclickvirt/ecs/speedtest" | 	"github.com/oneclickvirt/ecs/speedtest" | ||||||
| 	"github.com/oneclickvirt/ecs/unlocktest" | 	"github.com/oneclickvirt/ecs/unlocktest" | ||||||
|  | 	"github.com/oneclickvirt/ecs/upstreams" | ||||||
| 	"github.com/oneclickvirt/ecs/utils" | 	"github.com/oneclickvirt/ecs/utils" | ||||||
| 	gostunmodel "github.com/oneclickvirt/gostun/model" | 	gostunmodel "github.com/oneclickvirt/gostun/model" | ||||||
| 	memorytestmodel "github.com/oneclickvirt/memorytest/memory" | 	memorytestmodel "github.com/oneclickvirt/memorytest/memory" | ||||||
| 	nt3model "github.com/oneclickvirt/nt3/model" | 	nt3model "github.com/oneclickvirt/nt3/model" | ||||||
| 	"github.com/oneclickvirt/nt3/nt" |  | ||||||
| 	ptmodel "github.com/oneclickvirt/pingtest/model" | 	ptmodel "github.com/oneclickvirt/pingtest/model" | ||||||
| 	"github.com/oneclickvirt/pingtest/pt" | 	"github.com/oneclickvirt/pingtest/pt" | ||||||
| 	"github.com/oneclickvirt/portchecker/email" | 	"github.com/oneclickvirt/portchecker/email" | ||||||
| @@ -40,7 +40,7 @@ import ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
| 	ecsVersion                                                        = "v0.1.71" | 	ecsVersion                                                        = "v0.1.77" | ||||||
| 	menuMode                                                          bool | 	menuMode                                                          bool | ||||||
| 	onlyChinaTest                                                     bool | 	onlyChinaTest                                                     bool | ||||||
| 	input, choice                                                     string | 	input, choice                                                     string | ||||||
| @@ -60,7 +60,7 @@ var ( | |||||||
| 	autoChangeDiskTestMethod                                          = true | 	autoChangeDiskTestMethod                                          = true | ||||||
| 	filePath                                                          = "goecs.txt" | 	filePath                                                          = "goecs.txt" | ||||||
| 	enabelUpload                                                      = true | 	enabelUpload                                                      = true | ||||||
| 	help                                                              bool | 	onlyIpInfoCheckStatus, help                                       bool | ||||||
| 	goecsFlag                                                         = flag.NewFlagSet("goecs", flag.ContinueOnError) | 	goecsFlag                                                         = flag.NewFlagSet("goecs", flag.ContinueOnError) | ||||||
| 	finish                                                            bool | 	finish                                                            bool | ||||||
| ) | ) | ||||||
| @@ -144,7 +144,7 @@ func parseFlags() { | |||||||
| 	goecsFlag.StringVar(&diskTestMethod, "diskm", "fio", "Set disk test method (supported: fio, dd, winsat)") | 	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.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.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.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.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") | 	goecsFlag.BoolVar(&enableLogger, "log", false, "Enable/Disable logging in the current path") | ||||||
| @@ -186,11 +186,13 @@ func handleMenuMode(preCheck utils.NetCheckResult) { | |||||||
| 	commTestStatus, utTestStatus, securityTestStatus, emailTestStatus = false, false, false, false | 	commTestStatus, utTestStatus, securityTestStatus, emailTestStatus = false, false, false, false | ||||||
| 	backtraceStatus, nt3Status, speedTestStatus = false, false, false | 	backtraceStatus, nt3Status, speedTestStatus = false, false, false | ||||||
| 	autoChangeDiskTestMethod = true | 	autoChangeDiskTestMethod = true | ||||||
| 	printMenuOptions() | 	printMenuOptions(preCheck) | ||||||
| Loop: | Loop: | ||||||
| 	for { | 	for { | ||||||
| 		choice = getMenuChoice(language) | 		choice = getMenuChoice(language) | ||||||
| 		switch choice { | 		switch choice { | ||||||
|  | 		case "0": | ||||||
|  | 			os.Exit(0) | ||||||
| 		case "1": | 		case "1": | ||||||
| 			setFullTestStatus(preCheck) | 			setFullTestStatus(preCheck) | ||||||
| 			onlyChinaTest = utils.CheckChina(enableLogger) | 			onlyChinaTest = utils.CheckChina(enableLogger) | ||||||
| @@ -236,6 +238,7 @@ Loop: | |||||||
| 				fmt.Println("Can not test without network connection!") | 				fmt.Println("Can not test without network connection!") | ||||||
| 				return | 				return | ||||||
| 			} | 			} | ||||||
|  | 			nt3Location = "ALL" | ||||||
| 			setRouteTestStatus() | 			setRouteTestStatus() | ||||||
| 			break Loop | 			break Loop | ||||||
| 		default: | 		default: | ||||||
| @@ -244,23 +247,99 @@ Loop: | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func printMenuOptions() { | // 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() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func printMenuOptions(preCheck utils.NetCheckResult) { | ||||||
|  | 	clearScreen() // 清屏 | ||||||
|  | 	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 { | 	switch language { | ||||||
| 	case "zh": | 	case "zh": | ||||||
| 		fmt.Println("VPS融合怪版本: ", ecsVersion) | 		fmt.Printf("VPS融合怪版本: %s\n", ecsVersion) | ||||||
| 		fmt.Println("1. 融合怪完全体") | 		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("2. 极简版(系统信息+CPU+内存+磁盘+测速节点5个)") | ||||||
| 		fmt.Println("3. 精简版(系统信息+CPU+内存+磁盘+常用流媒体+路由+测速节点5个)") | 		fmt.Println("3. 精简版(系统信息+CPU+内存+磁盘+常用流媒体+路由+测速节点5个)") | ||||||
| 		fmt.Println("4. 精简网络版(系统信息+CPU+内存+磁盘+回程+路由+测速节点5个)") | 		fmt.Println("4. 精简网络版(系统信息+CPU+内存+磁盘+回程+路由+测速节点5个)") | ||||||
| 		fmt.Println("5. 精简解锁版(系统信息+CPU+内存+磁盘IO+御三家+常用流媒体+测速节点5个)") | 		fmt.Println("5. 精简解锁版(系统信息+CPU+内存+磁盘IO+御三家+常用流媒体+测速节点5个)") | ||||||
| 		fmt.Println("6. 网络单项(IP质量检测+三网回程+三网路由与延迟+测速节点11个)") | 		fmt.Println("6. 网络单项(IP质量检测+上游及三网回程+广州三网回程详细路由+全国延迟+测速节点11个)") | ||||||
| 		fmt.Println("7. 解锁单项(御三家解锁+常用流媒体解锁)") | 		fmt.Println("7. 解锁单项(御三家解锁+常用流媒体解锁)") | ||||||
| 		fmt.Println("8. 硬件单项(系统信息+CPU+内存+dd磁盘测试+fio磁盘测试)") | 		fmt.Println("8. 硬件单项(系统信息+CPU+dd磁盘测试+fio磁盘测试)") | ||||||
| 		fmt.Println("9. IP质量检测(15个数据库的IP检测+邮件端口检测)") | 		fmt.Println("9. IP质量检测(15个数据库的IP质量检测+邮件端口检测)") | ||||||
| 		fmt.Println("10. 三网回程线路+广州三网路由+全国三网延迟") | 		fmt.Println("10. 三网回程线路检测+三网回程详细路由(北京上海广州成都)+三网延迟测试(全国)") | ||||||
|  | 		fmt.Println("0. 退出程序") | ||||||
| 	case "en": | 	case "en": | ||||||
| 		fmt.Println("VPS Fusion Monster Test Version: ", ecsVersion) | 		fmt.Printf("VPS Fusion Monster Test Version: %s\n", ecsVersion) | ||||||
| 		fmt.Println("1. VPS Fusion Monster Test Comprehensive Test Suite") | 		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("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("3. Standard Test Suite (System Info + CPU + Memory + Disk + Basic Unlock Tests + 5 Speed Test Nodes)") | ||||||
| 		fmt.Println("4. Network-Focused Test Suite (System Info + CPU + Memory + Disk + 5 Speed Test Nodes)") | 		fmt.Println("4. Network-Focused Test Suite (System Info + CPU + Memory + Disk + 5 Speed Test Nodes)") | ||||||
| @@ -269,6 +348,7 @@ func printMenuOptions() { | |||||||
| 		fmt.Println("7. Unlock-Only Test (Basic Unlock Tests + Common Streaming Services Unlock)") | 		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("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("9. IP Quality Test (IP Test with 15 Databases + Email Port Test)") | ||||||
|  | 		fmt.Println("0. Exit Program") | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -335,16 +415,18 @@ func setUnlockFocusedTestStatus(preCheck utils.NetCheckResult) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func setNetworkOnlyTestStatus() { | func setNetworkOnlyTestStatus() { | ||||||
|  | 	onlyIpInfoCheckStatus = true | ||||||
| 	securityTestStatus = true | 	securityTestStatus = true | ||||||
| 	speedTestStatus = true | 	speedTestStatus = true | ||||||
| 	backtraceStatus = true | 	backtraceStatus = true | ||||||
| 	nt3Status = true | 	nt3Status = true | ||||||
|  | 	pingTestStatus = true | ||||||
| } | } | ||||||
|  |  | ||||||
| func setUnlockOnlyTestStatus() { | func setUnlockOnlyTestStatus() { | ||||||
|  | 	onlyIpInfoCheckStatus = true | ||||||
| 	commTestStatus = true | 	commTestStatus = true | ||||||
| 	utTestStatus = true | 	utTestStatus = true | ||||||
| 	enabelUpload = false |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func setHardwareOnlyTestStatus(preCheck utils.NetCheckResult) { | func setHardwareOnlyTestStatus(preCheck utils.NetCheckResult) { | ||||||
| @@ -358,15 +440,16 @@ func setHardwareOnlyTestStatus(preCheck utils.NetCheckResult) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func setIPQualityTestStatus() { | func setIPQualityTestStatus() { | ||||||
|  | 	onlyIpInfoCheckStatus = true | ||||||
| 	securityTestStatus = true | 	securityTestStatus = true | ||||||
| 	emailTestStatus = true | 	emailTestStatus = true | ||||||
| } | } | ||||||
|  |  | ||||||
| func setRouteTestStatus() { | func setRouteTestStatus() { | ||||||
|  | 	onlyIpInfoCheckStatus = true | ||||||
| 	backtraceStatus = true | 	backtraceStatus = true | ||||||
| 	nt3Status = true | 	nt3Status = true | ||||||
| 	pingTestStatus = true | 	pingTestStatus = true | ||||||
| 	enabelUpload = false |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func printInvalidChoice() { | func printInvalidChoice() { | ||||||
| @@ -387,7 +470,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 { | 	select { | ||||||
| 	case <-sig: | 	case <-sig: | ||||||
| 		if !finish { | 		if !finish { | ||||||
| @@ -463,16 +546,20 @@ func handleSignalInterrupt(sig chan os.Signal, startTime *time.Time, output *str | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func runChineseTests(preCheck utils.NetCheckResult, wg1, wg2, wg3 *sync.WaitGroup, basicInfo, securityInfo, emailInfo, mediaInfo, ptInfo *string, output *string, tempOutput string, startTime time.Time, outputMutex *sync.Mutex) { | func runChineseTests(preCheck utils.NetCheckResult, wg1, wg2, wg3, wg4, wg5 *sync.WaitGroup, basicInfo, securityInfo, emailInfo, mediaInfo, ptInfo *string, output *string, tempOutput string, startTime time.Time, outputMutex *sync.Mutex) { | ||||||
| 	*output = runBasicTests(preCheck, basicInfo, securityInfo, *output, tempOutput, outputMutex) | 	*output = runBasicTests(preCheck, basicInfo, securityInfo, *output, tempOutput, outputMutex) | ||||||
| 	*output = runCPUTest(*output, tempOutput, outputMutex) | 	*output = runCPUTest(*output, tempOutput, outputMutex) | ||||||
| 	*output = runMemoryTest(*output, tempOutput, outputMutex) | 	*output = runMemoryTest(*output, tempOutput, outputMutex) | ||||||
| 	*output = runDiskTest(*output, tempOutput, outputMutex) | 	*output = runDiskTest(*output, tempOutput, outputMutex) | ||||||
| 	if (onlyChinaTest || pingTestStatus) && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" { | 	if onlyIpInfoCheckStatus && !basicStatus && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" { | ||||||
| 		wg3.Add(1) | 		*output = runIpInfoCheck(*output, tempOutput, outputMutex) | ||||||
|  | 	} | ||||||
|  | 	var backtraceInfo, nt3Info string | ||||||
|  | 	if utTestStatus && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" && !onlyChinaTest { | ||||||
|  | 		wg1.Add(1) | ||||||
| 		go func() { | 		go func() { | ||||||
| 			defer wg3.Done() | 			defer wg1.Done() | ||||||
| 			*ptInfo = pt.PingTest() | 			*mediaInfo = unlocktest.MediaTest(language) | ||||||
| 		}() | 		}() | ||||||
| 	} | 	} | ||||||
| 	if emailTestStatus && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" { | 	if emailTestStatus && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" { | ||||||
| @@ -482,20 +569,42 @@ func runChineseTests(preCheck utils.NetCheckResult, wg1, wg2, wg3 *sync.WaitGrou | |||||||
| 			*emailInfo = email.EmailCheck() | 			*emailInfo = email.EmailCheck() | ||||||
| 		}() | 		}() | ||||||
| 	} | 	} | ||||||
| 	if utTestStatus && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" && !onlyChinaTest { | 	if (onlyChinaTest || pingTestStatus) && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" { | ||||||
| 		wg1.Add(1) | 		wg3.Add(1) | ||||||
| 		go func() { | 		go func() { | ||||||
| 			defer wg1.Done() | 			defer wg3.Done() | ||||||
| 			*mediaInfo = unlocktest.MediaTest(language) | 			*ptInfo = pt.PingTest() | ||||||
| 		}() | 		}() | ||||||
| 	} | 	} | ||||||
|  | 	if runtime.GOOS != "windows" && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" { | ||||||
|  | 		if backtraceStatus && !onlyChinaTest { | ||||||
|  | 			wg4.Add(1) | ||||||
|  | 			go func() { | ||||||
|  | 				defer wg4.Done() | ||||||
|  | 				backtraceInfo = utils.PrintAndCapture(func() { | ||||||
|  | 					utils.PrintCenteredTitle("上游及回程线路检测", width) | ||||||
|  | 					upstreams.UpstreamsCheck() | ||||||
|  | 				}, "", "") | ||||||
|  | 			}() | ||||||
|  | 		} | ||||||
|  | 		if nt3Status && !onlyChinaTest { | ||||||
|  | 			wg5.Add(1) | ||||||
|  | 			go func() { | ||||||
|  | 				defer wg5.Done() | ||||||
|  | 				nt3Info = utils.PrintAndCapture(func() { | ||||||
|  | 					utils.PrintCenteredTitle("三网回程路由检测", width) | ||||||
|  | 					nexttrace.NextTrace3Check(language, nt3Location, nt3CheckType) | ||||||
|  | 				}, "", "") | ||||||
|  | 			}() | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 	if preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" { | 	if preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" { | ||||||
| 		*output = runStreamingTests(wg1, mediaInfo, *output, tempOutput, outputMutex) | 		*output = runStreamingTests(wg1, mediaInfo, *output, tempOutput, outputMutex) | ||||||
| 		*output = runSecurityTests(*securityInfo, *output, tempOutput, outputMutex) | 		*output = runSecurityTests(*securityInfo, *output, tempOutput, outputMutex) | ||||||
| 		*output = runEmailTests(wg2, emailInfo, *output, tempOutput, outputMutex) | 		*output = runEmailTests(wg2, emailInfo, *output, tempOutput, outputMutex) | ||||||
| 	} | 	} | ||||||
| 	if runtime.GOOS != "windows" && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" { | 	if runtime.GOOS != "windows" && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" { | ||||||
| 		*output = runNetworkTests(wg3, ptInfo, *output, tempOutput, outputMutex) | 		*output = runNetworkTests(wg3, wg4, wg5, ptInfo, &backtraceInfo, &nt3Info, *output, tempOutput, outputMutex) | ||||||
| 	} | 	} | ||||||
| 	if preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" { | 	if preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" { | ||||||
| 		*output = runSpeedTests(*output, tempOutput, outputMutex) | 		*output = runSpeedTests(*output, tempOutput, outputMutex) | ||||||
| @@ -508,6 +617,9 @@ func runEnglishTests(preCheck utils.NetCheckResult, wg1, wg2 *sync.WaitGroup, ba | |||||||
| 	*output = runCPUTest(*output, tempOutput, outputMutex) | 	*output = runCPUTest(*output, tempOutput, outputMutex) | ||||||
| 	*output = runMemoryTest(*output, tempOutput, outputMutex) | 	*output = runMemoryTest(*output, tempOutput, outputMutex) | ||||||
| 	*output = runDiskTest(*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 preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" { | ||||||
| 		if utTestStatus { | 		if utTestStatus { | ||||||
| 			wg1.Add(1) | 			wg1.Add(1) | ||||||
| @@ -531,6 +643,24 @@ func runEnglishTests(preCheck utils.NetCheckResult, wg1, wg2 *sync.WaitGroup, ba | |||||||
| 	*output = appendTimeInfo(*output, tempOutput, startTime, outputMutex) | 	*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 { | func runBasicTests(preCheck utils.NetCheckResult, basicInfo, securityInfo *string, output, tempOutput string, outputMutex *sync.Mutex) string { | ||||||
| 	outputMutex.Lock() | 	outputMutex.Lock() | ||||||
| 	defer outputMutex.Unlock() | 	defer outputMutex.Unlock() | ||||||
| @@ -545,13 +675,13 @@ func runBasicTests(preCheck utils.NetCheckResult, basicInfo, securityInfo *strin | |||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			if preCheck.Connected && preCheck.StackType == "DualStack" { | 			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" { | 			} 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" { | 			} 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 { | 			} else { | ||||||
| 				*basicInfo, *securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, "", false) | 				upstreams.IPV4, upstreams.IPV6, *basicInfo, *securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, "", false) | ||||||
| 				securityTestStatus = false | 				securityTestStatus = false | ||||||
| 			} | 			} | ||||||
| 			if basicStatus { | 			if basicStatus { | ||||||
| @@ -686,26 +816,22 @@ func runEmailTests(wg2 *sync.WaitGroup, emailInfo *string, output, tempOutput st | |||||||
| 	}, tempOutput, output) | 	}, tempOutput, output) | ||||||
| } | } | ||||||
|  |  | ||||||
| func runNetworkTests(wg3 *sync.WaitGroup, ptInfo *string, output, tempOutput string, outputMutex *sync.Mutex) string { | func runNetworkTests(wg3, wg4, wg5 *sync.WaitGroup, ptInfo, backtraceInfo, nt3Info *string, output, tempOutput string, outputMutex *sync.Mutex) string { | ||||||
| 	outputMutex.Lock() | 	outputMutex.Lock() | ||||||
| 	defer outputMutex.Unlock() | 	defer outputMutex.Unlock() | ||||||
| 	output = utils.PrintAndCapture(func() { | 	if wg4 != nil { | ||||||
| 		if backtraceStatus && !onlyChinaTest { | 		wg4.Wait() | ||||||
| 			utils.PrintCenteredTitle("三网回程线路检测", width) | 	} | ||||||
| 			if uts.IPV6 { | 	if wg5 != nil { | ||||||
| 				backtrace.BackTrace(true) | 		wg5.Wait() | ||||||
| 			} else { | 	} | ||||||
| 				backtrace.BackTrace(false) |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	}, tempOutput, output) |  | ||||||
| 	output = utils.PrintAndCapture(func() { |  | ||||||
| 		if nt3Status && !onlyChinaTest { |  | ||||||
| 			utils.PrintCenteredTitle("三网回程路由检测", width) |  | ||||||
| 			nt.TraceRoute(language, nt3Location, nt3CheckType) |  | ||||||
| 		} |  | ||||||
| 	}, tempOutput, output) |  | ||||||
| 	return utils.PrintAndCapture(func() { | 	return utils.PrintAndCapture(func() { | ||||||
|  | 		if backtraceStatus && !onlyChinaTest && *backtraceInfo != "" { | ||||||
|  | 			fmt.Print(*backtraceInfo) | ||||||
|  | 		} | ||||||
|  | 		if nt3Status && !onlyChinaTest && *nt3Info != "" { | ||||||
|  | 			fmt.Print(*nt3Info) | ||||||
|  | 		} | ||||||
| 		if onlyChinaTest || pingTestStatus { | 		if onlyChinaTest || pingTestStatus { | ||||||
| 			wg3.Wait() | 			wg3.Wait() | ||||||
| 			utils.PrintCenteredTitle("三网ICMP的PING值检测", width) | 			utils.PrintCenteredTitle("三网ICMP的PING值检测", width) | ||||||
| @@ -787,19 +913,23 @@ func main() { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	initLogger() | 	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) | 	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 { | 	if menuMode { | ||||||
| 		handleMenuMode(preCheck) | 		handleMenuMode(preCheck) | ||||||
|  | 	} else { | ||||||
|  | 		onlyIpInfoCheckStatus = true | ||||||
| 	} | 	} | ||||||
| 	handleLanguageSpecificSettings() | 	handleLanguageSpecificSettings() | ||||||
| 	if !preCheck.Connected { | 	if !preCheck.Connected { | ||||||
| 		enabelUpload = false | 		enabelUpload = false | ||||||
| 	} | 	} | ||||||
| 	var ( | 	var ( | ||||||
| 		wg1, wg2, wg3                                         sync.WaitGroup | 		wg1, wg2, wg3, wg4, wg5                               sync.WaitGroup | ||||||
| 		basicInfo, securityInfo, emailInfo, mediaInfo, ptInfo string | 		basicInfo, securityInfo, emailInfo, mediaInfo, ptInfo string | ||||||
| 		output, tempOutput                                    string | 		output, tempOutput                                    string | ||||||
| 		outputMutex                                           sync.Mutex | 		outputMutex                                           sync.Mutex | ||||||
| @@ -811,7 +941,7 @@ func main() { | |||||||
| 	go handleSignalInterrupt(sig, &startTime, &output, tempOutput, uploadDone, &outputMutex) | 	go handleSignalInterrupt(sig, &startTime, &output, tempOutput, uploadDone, &outputMutex) | ||||||
| 	switch language { | 	switch language { | ||||||
| 	case "zh": | 	case "zh": | ||||||
| 		runChineseTests(preCheck, &wg1, &wg2, &wg3, &basicInfo, &securityInfo, &emailInfo, &mediaInfo, &ptInfo, &output, tempOutput, startTime, &outputMutex) | 		runChineseTests(preCheck, &wg1, &wg2, &wg3, &wg4, &wg5, &basicInfo, &securityInfo, &emailInfo, &mediaInfo, &ptInfo, &output, tempOutput, startTime, &outputMutex) | ||||||
| 	case "en": | 	case "en": | ||||||
| 		runEnglishTests(preCheck, &wg1, &wg2, &basicInfo, &securityInfo, &emailInfo, &mediaInfo, &output, tempOutput, startTime, &outputMutex) | 		runEnglishTests(preCheck, &wg1, &wg2, &basicInfo, &securityInfo, &emailInfo, &mediaInfo, &output, tempOutput, startTime, &outputMutex) | ||||||
| 	default: | 	default: | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								goecs.sh
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								goecs.sh
									
									
									
									
									
								
							| @@ -143,7 +143,7 @@ goecs_check() { | |||||||
|     os=$(uname -s 2>/dev/null || echo "Unknown") |     os=$(uname -s 2>/dev/null || echo "Unknown") | ||||||
|     arch=$(uname -m 2>/dev/null || echo "Unknown") |     arch=$(uname -m 2>/dev/null || echo "Unknown") | ||||||
|     check_china |     check_china | ||||||
|     ECS_VERSION="0.1.70" |     ECS_VERSION="0.1.76" | ||||||
|     for api in \ |     for api in \ | ||||||
|         "https://api.github.com/repos/oneclickvirt/ecs/releases/latest" \ |         "https://api.github.com/repos/oneclickvirt/ecs/releases/latest" \ | ||||||
|         "https://githubapi.spiritlhl.workers.dev/repos/oneclickvirt/ecs/releases/latest" \ |         "https://githubapi.spiritlhl.workers.dev/repos/oneclickvirt/ecs/releases/latest" \ | ||||||
| @@ -155,8 +155,8 @@ goecs_check() { | |||||||
|         sleep 1 |         sleep 1 | ||||||
|     done |     done | ||||||
|     if [ -z "$ECS_VERSION" ]; then |     if [ -z "$ECS_VERSION" ]; then | ||||||
|         _yellow "Unable to get version info, using default version 0.1.70" |         _yellow "Unable to get version info, using default version 0.1.76" | ||||||
|         ECS_VERSION="0.1.70" |         ECS_VERSION="0.1.76" | ||||||
|     fi |     fi | ||||||
|     version_output="" |     version_output="" | ||||||
|     for cmd_path in "goecs" "./goecs" "/usr/bin/goecs" "/usr/local/bin/goecs"; do |     for cmd_path in "goecs" "./goecs" "/usr/bin/goecs" "/usr/local/bin/goecs"; do | ||||||
|   | |||||||
| @@ -10,7 +10,6 @@ import ( | |||||||
| func MemoryTest(language, testMethod string) (realTestMethod, res string) { | func MemoryTest(language, testMethod string) (realTestMethod, res string) { | ||||||
| 	if runtime.GOOS == "windows" { | 	if runtime.GOOS == "windows" { | ||||||
| 		if testMethod != "winsat" && testMethod != "" { | 		if testMethod != "winsat" && testMethod != "" { | ||||||
| 			// res = "Detected host is Windows, using Winsat for testing.\n" |  | ||||||
| 			realTestMethod = "winsat" | 			realTestMethod = "winsat" | ||||||
| 		} | 		} | ||||||
| 		res += memory.WinsatTest(language) | 		res += memory.WinsatTest(language) | ||||||
| @@ -19,7 +18,6 @@ func MemoryTest(language, testMethod string) (realTestMethod, res string) { | |||||||
| 		case "sysbench": | 		case "sysbench": | ||||||
| 			res = memory.SysBenchTest(language) | 			res = memory.SysBenchTest(language) | ||||||
| 			if res == "" { | 			if res == "" { | ||||||
| 				// res = "sysbench test failed, switch to use dd test.\n" |  | ||||||
| 				res += memory.DDTest(language) | 				res += memory.DDTest(language) | ||||||
| 				realTestMethod = "dd" | 				realTestMethod = "dd" | ||||||
| 			} else { | 			} else { | ||||||
| @@ -29,7 +27,6 @@ func MemoryTest(language, testMethod string) (realTestMethod, res string) { | |||||||
| 			res = memory.DDTest(language) | 			res = memory.DDTest(language) | ||||||
| 			realTestMethod = "dd" | 			realTestMethod = "dd" | ||||||
| 		default: | 		default: | ||||||
| 			// res = "Unsupported test method, switch to use dd test.\n" |  | ||||||
| 			res += memory.DDTest(language) | 			res += memory.DDTest(language) | ||||||
| 			realTestMethod = "dd" | 			realTestMethod = "dd" | ||||||
| 		} | 		} | ||||||
|   | |||||||
							
								
								
									
										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) { | 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() | ||||||
|  | } | ||||||
							
								
								
									
										136
									
								
								utils/utils.go
									
									
									
									
									
								
							
							
						
						
									
										136
									
								
								utils/utils.go
									
									
									
									
									
								
							| @@ -11,6 +11,7 @@ import ( | |||||||
| 	"os" | 	"os" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
| 	"regexp" | 	"regexp" | ||||||
|  | 	"strconv" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"sync" | 	"sync" | ||||||
| 	"time" | 	"time" | ||||||
| @@ -18,12 +19,28 @@ import ( | |||||||
|  |  | ||||||
| 	"github.com/imroc/req/v3" | 	"github.com/imroc/req/v3" | ||||||
| 	"github.com/oneclickvirt/UnlockTests/uts" | 	"github.com/oneclickvirt/UnlockTests/uts" | ||||||
|  | 	bnetwork "github.com/oneclickvirt/basics/network" | ||||||
| 	"github.com/oneclickvirt/basics/system" | 	"github.com/oneclickvirt/basics/system" | ||||||
| 	butils "github.com/oneclickvirt/basics/utils" | 	butils "github.com/oneclickvirt/basics/utils" | ||||||
| 	. "github.com/oneclickvirt/defaultset" | 	. "github.com/oneclickvirt/defaultset" | ||||||
| 	"github.com/oneclickvirt/security/network" | 	"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 根据指定的宽度打印居中标题 | // PrintCenteredTitle 根据指定的宽度打印居中标题 | ||||||
| func PrintCenteredTitle(title string, width int) { | func PrintCenteredTitle(title string, width int) { | ||||||
| 	// 计算字符串的字符数 | 	// 计算字符串的字符数 | ||||||
| @@ -99,18 +116,38 @@ func CheckChina(enableLogger bool) bool { | |||||||
| 	return selectChina | 	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 执行安全检查 | // 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 wgt sync.WaitGroup | ||||||
| 	var ipInfo, securityInfo, systemInfo string | 	var ipv4, ipv6, ipInfo, securityInfo, systemInfo string | ||||||
| 	var err error |  | ||||||
| 	wgt.Add(1) | 	wgt.Add(1) | ||||||
| 	go func() { | 	go func() { | ||||||
| 		defer wgt.Done() | 		defer wgt.Done() | ||||||
| 		ipInfo, securityInfo, err = network.NetworkCheck("both", securityCheckStatus, language) | 		ipv4, ipv6, ipInfo, securityInfo, _ = network.NetworkCheck("both", securityCheckStatus, language) | ||||||
| 		if err != nil { | 		// if err != nil { | ||||||
| 			fmt.Println(err.Error()) | 		// 	fmt.Println(err.Error()) | ||||||
| 		} | 		// } | ||||||
| 	}() | 	}() | ||||||
| 	wgt.Add(1) | 	wgt.Add(1) | ||||||
| 	go func() { | 	go func() { | ||||||
| @@ -119,19 +156,19 @@ func BasicsAndSecurityCheck(language, nt3CheckType string, securityCheckStatus b | |||||||
| 	}() | 	}() | ||||||
| 	wgt.Wait() | 	wgt.Wait() | ||||||
| 	basicInfo := systemInfo + ipInfo | 	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.IPV4 = true | ||||||
| 		uts.IPV6 = true | 		uts.IPV6 = true | ||||||
| 		if nt3CheckType == "" { | 		if nt3CheckType == "" { | ||||||
| 			nt3CheckType = "ipv4" | 			nt3CheckType = "ipv4" | ||||||
| 		} | 		} | ||||||
| 	} else if strings.Contains(ipInfo, "IPV4") { | 	} else if strings.Contains(ipInfo, "IPV4") && ipv4 != "" { | ||||||
| 		uts.IPV4 = true | 		uts.IPV4 = true | ||||||
| 		uts.IPV6 = false | 		uts.IPV6 = false | ||||||
| 		if nt3CheckType == "" { | 		if nt3CheckType == "" { | ||||||
| 			nt3CheckType = "ipv4" | 			nt3CheckType = "ipv4" | ||||||
| 		} | 		} | ||||||
| 	} else if strings.Contains(ipInfo, "IPV6") { | 	} else if strings.Contains(ipInfo, "IPV6") && ipv6 != "" { | ||||||
| 		uts.IPV6 = true | 		uts.IPV6 = true | ||||||
| 		uts.IPV4 = false | 		uts.IPV4 = false | ||||||
| 		if nt3CheckType == "" { | 		if nt3CheckType == "" { | ||||||
| @@ -144,7 +181,7 @@ func BasicsAndSecurityCheck(language, nt3CheckType string, securityCheckStatus b | |||||||
| 		nt3CheckType = "ipv4" | 		nt3CheckType = "ipv4" | ||||||
| 	} | 	} | ||||||
| 	basicInfo = strings.ReplaceAll(basicInfo, "\n\n", "\n") | 	basicInfo = strings.ReplaceAll(basicInfo, "\n\n", "\n") | ||||||
| 	return basicInfo, securityInfo, nt3CheckType | 	return ipv4, ipv6, basicInfo, securityInfo, nt3CheckType | ||||||
| } | } | ||||||
|  |  | ||||||
| // CaptureOutput 捕获函数输出和错误输出,实时输出,并返回字符串 | // CaptureOutput 捕获函数输出和错误输出,实时输出,并返回字符串 | ||||||
| @@ -336,8 +373,6 @@ func ProcessAndUpload(output string, filePath string, enableUplaod bool) (string | |||||||
| 	return "", "" | 	return "", "" | ||||||
| } | } | ||||||
|  |  | ||||||
| // ============================= 前置联网能力检测 ============================= |  | ||||||
|  |  | ||||||
| var StackType string | var StackType string | ||||||
|  |  | ||||||
| type NetCheckResult struct { | type NetCheckResult struct { | ||||||
| @@ -359,6 +394,7 @@ func makeResolver(proto, dnsAddr string) *net.Resolver { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // 前置联网能力检测 | ||||||
| func CheckPublicAccess(timeout time.Duration) NetCheckResult { | func CheckPublicAccess(timeout time.Duration) NetCheckResult { | ||||||
| 	if timeout < 2*time.Second { | 	if timeout < 2*time.Second { | ||||||
| 		timeout = 2 * time.Second | 		timeout = 2 * time.Second | ||||||
| @@ -492,3 +528,77 @@ result: | |||||||
| 		StackType: stack, | 		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 | 	timeout := 3 * time.Second | ||||||
| 	result := CheckPublicAccess(timeout) | 	result := CheckPublicAccess(timeout) | ||||||
| 	if result.Connected { | 	if result.Connected { | ||||||
| 		fmt.Print("✅ 本机有公网连接,类型: %s\n", result.StackType) | 		fmt.Printf("✅ 本机有公网连接,类型: %s\n", result.StackType) | ||||||
| 	} else { | 	} else { | ||||||
| 		fmt.Println("❌ 本机未检测到公网连接") | 		fmt.Println("❌ 本机未检测到公网连接") | ||||||
| 	} | 	} | ||||||
| 	basicInfo, securityInfo, nt3CheckType := BasicsAndSecurityCheck("zh", "ipv4", false) | 	_, _, basicInfo, securityInfo, nt3CheckType := BasicsAndSecurityCheck("zh", "ipv4", false) | ||||||
| 	fmt.Println(basicInfo) | 	fmt.Println(basicInfo) | ||||||
| 	fmt.Println(securityInfo) | 	fmt.Println(securityInfo) | ||||||
| 	fmt.Println(nt3CheckType) | 	fmt.Println(nt3CheckType) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user