Compare commits

...

25 Commits

Author SHA1 Message Date
spiritlhl
39c2607b42 fix:修复nexttrace权限不足时导致整个程序退出的问题 2025-11-11 10:12:27 +00:00
spiritlhl
519c0f3e86 fix:更新外部依赖库,去除可能的数据竞争 2025-11-11 10:00:19 +00:00
spiritlhl
3b5b8a348e fix:修复恶性BUG添加单项recover机制,优化整体执行的稳定性 2025-11-11 09:42:44 +00:00
spiritlhl
858585b4ff fix:处理IPV6解析不存在和不可用的两种情况,修复潜在的可能导致数组越界整个程序崩溃的问题 2025-11-11 09:04:37 +00:00
github-actions[bot]
b891416147 chore: update ECS_VERSION to 0.1.102 in goecs.sh 2025-11-09 09:21:01 +00:00
spiritlhl
8e79568895 fix:更新版本 2025-11-09 09:06:49 +00:00
spiritlhl
01aa051c96 fix:更新backtrace的IPV6检测支持更多IP段 2025-11-09 09:05:51 +00:00
spiritlhl
628a380122 fix:更新IP质量检测依赖 2025-11-09 09:03:44 +00:00
spiritlhl
2b94d289f3 fix: 更新youtube的地区识别 2025-11-09 09:02:59 +00:00
github-actions[bot]
e3676760da chore: update ECS_VERSION to 0.1.101 in goecs.sh 2025-11-09 05:15:53 +00:00
spiritsoul
55fbe111ac fix:更新版本 2025-11-09 04:58:39 +00:00
spiritsoul
a37e6b1021 fix:删除无效的说明 2025-11-09 04:51:50 +00:00
spiritsoul
06b68ce205 fix:对应调整检测用语,不再使用流媒体而是平台术语 2025-11-09 04:31:15 +00:00
spiritsoul
9a839de71c fix:删除御三家流媒体检测,后面的UnlockTest已经包含且更准确,老的方法都失效了 2025-11-09 04:13:40 +00:00
spiritsoul
09afd48ad5 fix:修复netflix检测失效的问题 2025-11-09 04:03:59 +00:00
spiritlhl
cbc5bed3d4 fix:优化格式 2025-11-07 22:02:23 +08:00
spiritlhl
834ff78bd9 fix:修复表格格式错误 2025-11-07 21:59:36 +08:00
spiritlhl
351a4b552f fix:更新路由线路表格,方便比对 2025-11-07 13:51:35 +00:00
github-actions[bot]
d619991f9c chore: update ECS_VERSION to 0.1.100 in goecs.sh 2025-11-06 06:32:58 +00:00
spiritlhl
b065af63d6 fix:更新依赖版本,避免查询超额报错 2025-11-06 06:18:05 +00:00
github-actions[bot]
4d49222094 chore: update ECS_VERSION to 0.1.99 in goecs.sh 2025-11-04 12:16:26 +00:00
spiritlhl
78b5634306 fix:升级版本 2025-11-04 12:01:54 +00:00
spiritlhl
a0bc2de61a fix:修复在权限不足测试时,icmp报错导致的整个程序退出的问题 2025-11-04 11:55:49 +00:00
spiritlhl
3c45667c55 fix: 更新依赖,ping值检测设置3次测试取平均值 2025-11-04 11:51:10 +00:00
github-actions[bot]
6111554225 chore: update ECS_VERSION to 0.1.98 in goecs.sh 2025-11-03 02:55:13 +00:00
18 changed files with 439 additions and 223 deletions

View File

@@ -55,8 +55,7 @@ Shell 版本:[https://github.com/spiritLHLS/ecs](https://github.com/spiritLHLS
- CPU 测试:[cputest](https://github.com/oneclickvirt/cputest),支持 sysbench(lua/golang版本)、geekbench、winsat
- 内存测试:[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) 等
- 流媒体平台解锁测试并发查询:[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)
@@ -185,8 +184,8 @@ Usage: goecs [options]
Enable/Disable backtrace test (in 'en' language or on windows it always false) (default true)
-basic
Enable/Disable basic test (default true)
-comm
Enable/Disable common media test (default true)
-ut
Enable/Disable unlock media test (default true)
-cpu
Enable/Disable CPU test (default true)
-cpum string
@@ -252,6 +251,7 @@ Usage: goecs [options]
2. 解压后,右键以管理员模式运行。
PS如果是虚拟机环境不以管理员模式运行也行因为虚拟机无原生的测试工具将自动启用替代方法测试。
PPS: 暂时不要下载带GUI标签的exe文件未完整适配CI版本的压缩包是没问题的。
---

View File

@@ -55,8 +55,7 @@ Shell version: [https://github.com/spiritLHLS/ecs/blob/main/README_EN.md](https:
- 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, 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
- Streaming platform unlock tests concurrent query: Self-developed to [UnlockTests](https://github.com/oneclickvirt/UnlockTests), logic modified from [RegionRestrictionCheck](https://github.com/lmc999/RegionRestrictionCheck) and others
- IP quality/security information concurrent query: Self-developed, binary files compiled in [securityCheck](https://github.com/oneclickvirt/securityCheck)
- Email port test: Self-developed [portchecker](https://github.com/oneclickvirt/portchecker)
- Three-network return path test: Modified from [zhanghanyun/backtrace](https://github.com/zhanghanyun/backtrace) to [oneclickvirt/backtrace](https://github.com/oneclickvirt/backtrace)
@@ -184,8 +183,8 @@ Usage: goecs [options]
Enable/Disable backtrace test (in 'en' language or on windows it always false) (default true)
-basic
Enable/Disable basic test (default true)
-comm
Enable/Disable common media test (default true)
-ut
Enable/Disable unlock media test (default true)
-cpu
Enable/Disable CPU test (default true)
-cpum string
@@ -251,6 +250,7 @@ Usage: goecs [options]
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.
PPS: Please refrain from downloading executable files labelled with a GUI for the time being, as they have not been fully adapted. The compressed packages for the CI version are unaffected.
---

View File

@@ -12,7 +12,7 @@
- [CPU测试](#CPU测试)
- [内存测试](#内存测试)
- [硬盘测试](#硬盘测试)
- [流媒体解锁](#流媒体解锁)
- [平台解锁检测](#平台解锁检测)
- [IP质量检测](#IP质量检测)
- [邮件端口检测](#邮件端口检测)
- [上游及回程线路检测](#上游及回程线路检测)
@@ -25,7 +25,7 @@
- [CPU Testing](#CPU-Testing)
- [Memory Testing](#Memory-Testing)
- [Disk Testing](#Disk-Testing)
- [Streaming Media Unlocking](#Streaming-Media-Unlocking)
- [Platform Unlock Testing](#Platform-Unlock-Testing)
- [IP Quality Detection](#IP-Quality-Detection)
- [Email Port Detection](#Email-Port-Detection)
- [PING Testing](#PING-Testing)
@@ -36,7 +36,7 @@
- [CPUテスト](#CPUテスト)
- [メモリテスト](#メモリテスト)
- [ディスクテスト](#ディスクテスト)
- [ストリーミングメディアロック解除](#ストリーミングメディアロック解除)
- [プラットフォームロック解除検出](#プラットフォームロック解除検出)
- [IP品質検出](#IP品質検出)
- [メールポート検出](#メールポート検出)
- [PING検出](#PING検出)
@@ -218,24 +218,24 @@ AMD的7950x单核满血性能得分在6500左右AMD的5950x单核满血性能
注意这里测试的是真实的IO仅限本项目非本项目测试的IO不保证基准通用因为他们测试的时候可能用的不是同样的参数可能未设置IO直接读写可能设置IO引擎不一致可能设置测试时间不一致都会导致基准有偏差。
### **流媒体解锁**
### **平台解锁检测**
依赖项目:[https://github.com/oneclickvirt/CommonMediaTests](https://github.com/oneclickvirt/CommonMediaTests) [https://github.com/oneclickvirt/UnlockTests](https://github.com/oneclickvirt/UnlockTests)
依赖项目:[https://github.com/oneclickvirt/UnlockTests](https://github.com/oneclickvirt/UnlockTests)
默认只检测跨国流媒体解锁。
默认只检测跨国平台解锁。
一般来说正常的情况下一个IP多个流媒体的解锁地区都是一致的不会到处乱飘如果发现多家平台解锁地区不一致那么IP大概率来自IPXO等平台租赁或者是刚刚宣告和被使用未被流媒体普通的数据库所识别修正地域。
一般来说正常的情况下一个IP多个平台的解锁地区都是一致的不会到处乱飘如果发现多家平台解锁地区不一致那么IP大概率来自IPXO等平台租赁或者是刚刚宣告和被使用未被平台普通的数据库所识别修正地域。
由于各平台的IP数据库识别速度不一致所以有时候有的平台解锁区域正常有的飘到路由上的某个位置有的飘到IP未被你使用前所在的位置。
| DNS 类型 | 解锁方式判断是否必要 | DNS 对解锁影响 | 说明 |
| ------------ | ---------- | --------- | --------------------------------------- |
| 官方主流 DNS | 否 | 小 | 流媒体解锁主要依赖测试节点的 IPDNS 解析基本不会干扰解锁。 |
| 非主流 / 自建 DNS | 是 | 大 | 流媒体解锁结果受 DNS 解析影响较大,需要判断是原生解锁还是 DNS 解锁。|
| 官方主流 DNS | 否 | 小 | 平台解锁主要依赖测试节点的 IPDNS 解析基本不会干扰解锁。 |
| 非主流 / 自建 DNS | 是 | 大 | 平台解锁结果受 DNS 解析影响较大,需要判断是原生解锁还是 DNS 解锁。|
所以测试过程中如果宿主机当前使用的是官方主流的DNS不会进行是否为原生解锁的判断解锁类型大部分受后面查询的IP质量的使用类型和公司类型的影响。
对于IP质量解锁比较敏感的实际上是各大AI平台和本地流媒体以及reddit和spotify其他的跨国平台一般不易受IP质量影响解锁。
对于IP质量解锁比较敏感的实际上是各大AI平台和本地平台解锁以及reddit和spotify其他的跨国平台一般不易受IP质量影响解锁。
### **IP质量检测**
@@ -276,20 +276,19 @@ AMD的7950x单核满血性能得分在6500左右AMD的5950x单核满血性能
| ----------- | ---------- |
| hosting | 数据中心网络(IDC) |
| residential | 家庭/住宅网络(家宽) |
| FixedLineISPISP | 固定线路互联网服务提供商(家宽) |
| isp | 固定线路互联网服务提供商(家宽) |
| business | 企业办公网络(商宽) |
| cellular | 移动运营商网络(家宽) |
| education | 教育机构网络(教育网) |
| government | 政府机构网络(政府网) |
| military | 军事网络(政府网) |
| DataCenter/WebHosting/Transit | 数据中心网络(IDC) |
| CDN | 内容分发网络(IDC) |
| 公司类型 | 说明 |
| ------------ | ------------ |
| business | 企业公司(商宽) |
| hosting | 主机/数据中心公司(IDC) |
| FixedLineISPISP | 固定线路互联网服务提供商(家宽) |
| business | 企业公司(商宽) |
| isp | 固定线路互联网服务提供商(家宽) |
| education | 教育机构(教育网) |
| government | 政府机构(政府网) |
@@ -322,11 +321,11 @@ Abuser 或 Abuse 的滥用得分会直接影响机器的正常使用(中国境
- 发起大规模洪流攻击
- 进行端口扫描或全网扫描
这类历史记录会被举报并录入 Abuse 数据库。如果你接手的 IP 刚被他人滥用过,可能仍会有延迟的 Abuse 警告邮件发送至服务商。服务商可能会误判为你本人从事恶意行为,进而清退机器,且大多数情况下无法退款。对跨国流媒体服务而言Abuse 滥用得分还可能影响平台对该 IP 的信誉评分。
这类历史记录会被举报并录入 Abuse 数据库。如果你接手的 IP 刚被他人滥用过,可能仍会有延迟的 Abuse 警告邮件发送至服务商。服务商可能会误判为你本人从事恶意行为,进而清退机器,且大多数情况下无法退款。对跨国平台服务而言Abuse 滥用得分还可能影响平台对该 IP 的信誉评分。
对于需要家宽进行流媒体解锁需求的用户(如电商需求),应关注「使用类型」与「公司类型」是否同时识别为 ISP。如果仅为单 ISP 或识别为非 ISP则后续数据库更新后IP 类型很可能被更正为 Hosting从而影响解锁效果。
对于需要家宽进行平台解锁需求的用户(如电商需求),应关注「使用类型」与「公司类型」是否同时识别为 ISP。如果仅为单 ISP 或识别为非 ISP则后续数据库更新后IP 类型很可能被更正为 Hosting从而影响解锁效果。
大部分 IP 识别数据库按月更新。更新后IP 属性可能被修改,出现由 ISP → Hosting 的情况。对于一些敏感的平台,比如某些特定国家的流媒体(如 NetflixSpotify),某些区别对待不同国家的流媒体(如 TikTok),非家宽解锁的可能性较低但不是没有,如果你需要稳定解锁且追求其特殊功能解锁,才需要追求家宽流媒体解锁。如果仅仅是浏览观看,很多时候没必要追求家宽,
大部分 IP 识别数据库按月更新。更新后IP 属性可能被修改,出现由 ISP → Hosting 的情况。对于一些敏感的平台,比如某些特定国家的平台(如 NetflixSpotify),某些区别对待不同国家的平台(如 TikTok),非家宽解锁的可能性较低但不是没有,如果你需要稳定解锁且追求其特殊功能解锁,才需要追求家宽平台解锁。如果仅仅是浏览观看,很多时候没必要追求家宽,
对于 IP 类型分类有必要仔细说说
@@ -394,9 +393,15 @@ Abuser 或 Abuse 的滥用得分会直接影响机器的正常使用(中国境
然后是检测当前的宿主机的IP地址 到 四个主要POP点城市的三个主要运营商的接入点的IP地址 的线路,具体来说
电信163、联通4837、移动CMI 是常见的线路移动CMI对两广地区的移动运营商特供延迟低也能算优质仅限两广移动。
电信CN2GIA > 电信CN2GT 移动CMIN2 联通9929 算优质的线路
| 运营商 | 线路代号 | 全称 | 特点 | 线路质量 |
| --- | -------------- | --------------------------------- | -------------- | --- |
| 中国电信 | 163 | ChinaNet (原163骨干网) | 普通国际出口,延迟高易绕路 | 一般 |
| 中国电信 | CN2 GT | ChinaNet Next Carrying Network (GT) | 较优于163偶有拥堵 | 良好 |
| 中国电信 | CN2 GIA | Global Internet Access(GT) | 直连国际POP低延迟低丢包 | 优质(最好) |
| 中国联通 | 4837 | Unicom International (AS4837) | 常见国际出口,覆盖广 | 一般到良好 |
| 中国联通 | 9929 | Unicom Premium / CU-IX | 精品网直连主要IXP延迟低 | 优质 |
| 中国移动 | CMI (AS58453) | China Mobile International | 节点多,对两广(广东广西)优化好 | 两广良好,其他一般 |
| 中国移动 | CMIN2 (AS58807) | China Mobile International N2 | 高质量专线低延迟低丢包对标CN2 | 优质 |
用什么运营商连宿主机的IP就看哪个运营商的线路就行了具体线路的路由情况看在下一个检测项看到对应的ICMP检测路由信息。
@@ -412,7 +417,44 @@ Abuser 或 Abuse 的滥用得分会直接影响机器的正常使用(中国境
有时候路由信息完全藏起来了,只知道实际使用的延迟低,实际可能也是优质线路只是查不到信息,这就没办法直接识别了。
所有测不出来失败的地址以及延迟大于等于999ms的延迟都设为了999延迟超过这个也证明目标延迟过大影响使用此时认为目标不可用就行。
这块能看到更多线路的信息了,一般能看到以下线路
| 运营商 | 线路代号 | 全称来源 | 特点 | 线路质量 |
| --- | --- | --- | --- | --- |
| 中国电信 | 163 | ChinaNet (原163骨干网) | 普通国际出口,延迟高易绕路 | 一般 |
| 中国电信 | CN2 GT | ChinaNet Next Carrying Network (GT) | 较优于163偶有拥堵 | 良好 |
| 中国电信 | CN2 GIA | Global Internet Access (GIA) | 直连国际POP低延迟低丢包 | 优质 |
| 中国电信 | CN2 BGP | CN2混合BGP(GIA+GT) | 混合路由性能略低于纯GIA | 良好至优质 |
| 中国电信 | CUII | ChinaNet United International Internet | 面向直连美国的专线 | 优质 |
| 中国电信 | 163+CUII混线 | 163国内段+国际专线出口 | 价格低,性能一般 | 一般 |
| 中国联通 | 169 | China169骨干网 | 老主干网一般对接4837 | 一般(少部分优质) |
| 中国联通 | 4837 | Unicom International (AS4837) | 常见国际出口,覆盖广 | 良好 |
| 中国联通 | 9929 | Unicom Premium / CU-IX | 精品网直连IXP低延迟 | 优质 |
| 中国联通 | 9929+4837混BGP | 混合出口(IDC常见优化) | 性能平衡 | 良好 |
| 中国联通 | CUVIP / CU-IX | 联通精品直连IX (港/新/日) | 企业高端专线 | 优质 |
| 中国联通 | CUA (AS17621) | 联通亚洲专线 | 东南亚方向优化 | 良好 |
| 中国移动 | CMI (AS58453) | China Mobile International | 对接节点多 | 两广良好,其他一般 |
| 中国移动 | CMIN | China Mobile International Network (旧版) | 老出口已被CMI替代 | 一般 |
| 中国移动 | CMIN2 (AS58807) | China Mobile International N2 | 低延迟低丢包 | 优质 |
| 中国移动 | CMIN2+CMI混线 | 混合出口 | 依地区表现不同 | 良好 |
| 中国移动 | CMI-HKIX | 香港IX专线 | 香港延迟极低 | 优质(香港) |
上面是中国出境入境的线路段的线路,下面是出境后与国际互联常见的线路
| 运营商 | 线路代号 | 来源 | 特点 | 线路质量 |
| --- | --- | --- | --- | --- |
| 其他 | 国际BGP | HE、NTT、Telia等Tier1 Global | 稳定性取决地区 | 国际互联良好 |
| 其他 | 地区IX | HKIX、SGIX、JPIX、Equinix IX | 地区IX低延迟限区域 | 区域优质 |
| 其他 | SoftBankAS17676 | 日本软银骨干 | 日本方向优化,沿海延迟低 | 沿海优质 |
| 其他 | NTTAS2914 | 日本/全球NTT Communications | 亚洲优化,但有时候不稳定 | 亚洲优质(时不时炸) |
| 其他 | PCCWAS3491 | 香港电讯盈科(Pacnet) | 港区机房常用,对南部优 | 良好至优质(南方) |
| 其他 | SingtelAS7473 | 新加坡电信 | 东南亚方向极优CN2常中转此线 | 良好至优质(东南亚) |
| 其他 | KTAS4766 | 韩国电信 | 韩国至中国延迟低(但有时候也炸) | 良好(北方) |
| 其他 | HGCAS9304 | 香港和记环球通信 | 香港区域BGP主力 | 一般至良好(香港) |
| 其他 | TataAS6453 | 印度塔塔通信 | 亚洲跨区骨干部分IDC混线使用 | 一般(南亚) |
| 其他 | Level3AS3356 | 美国Lumen/Level3 | 北美主干对CN2转接良好 | 良好(国际) |
| 其他 | GTTAS3257 | 欧洲骨干 | 稳定性高,延迟略高 | 一般(国际) |
| 其他 | TelstraAS1221 | 澳洲电信 | 澳大利亚及东南亚方向优 | 良好(南亚) |
### **PING值测试**
@@ -426,6 +468,8 @@ Abuser 或 Abuse 的滥用得分会直接影响机器的正常使用(中国境
对于参数指定的状态,优先级会高于选项中默认的参数设置。
所有测不出来失败的地址以及延迟大于等于9999ms的延迟都设为了9999延迟超过这个也证明目标延迟过大影响使用此时认为目标不可用就行。
### **就近测速**
依赖项目:[https://github.com/oneclickvirt/speedtest](https://github.com/oneclickvirt/speedtest)
@@ -612,24 +656,24 @@ If NVMe SSD's 1M (IOPS) value < 1GB/s indicates serious resource overselling.
Note: This tests real IO, limited to this project. IO tests from other projects don't guarantee universal benchmarks because they may use different parameters, may not set direct IO read/write, may have inconsistent IO engines, or inconsistent test times, all causing benchmark deviations.
### Streaming Media Unlocking
### Platform Unlock Testing
Dependency project: [https://github.com/oneclickvirt/CommonMediaTests](https://github.com/oneclickvirt/CommonMediaTests) [https://github.com/oneclickvirt/UnlockTests](https://github.com/oneclickvirt/UnlockTests)
Dependency project: [https://github.com/oneclickvirt/UnlockTests](https://github.com/oneclickvirt/UnlockTests)
Default only checks cross-border streaming media unlocking.
Default only checks cross-border platform unlocking.
Generally speaking, under normal circumstances, multiple streaming services for one IP should have consistent unlock regions without scattered locations. If multiple platforms show inconsistent unlock regions, the IP likely comes from platforms like IPXO rentals or has been recently announced and used, not yet recognized and corrected by streaming media common databases.
Generally speaking, under normal circumstances, multiple platform services for one IP should have consistent unlock regions without scattered locations. If multiple platforms show inconsistent unlock regions, the IP likely comes from platforms like IPXO rentals or has been recently announced and used, not yet recognized and corrected by platform common databases.
Due to inconsistent IP database recognition speeds across platforms, sometimes some platforms unlock regions normally, some drift to certain router locations, and some drift to where the IP was before you used it.
| DNS Type | Unlock Method Judgment Necessary | DNS Impact on Unlocking | Description |
| -------- | ------------------------------- | ----------------------- | ----------- |
| Official Mainstream DNS | No | Small | Streaming unlock mainly relies on node IP, DNS resolution basically doesn't interfere with unlocking |
| Non-mainstream / Self-built DNS | Yes | Large | Streaming unlock results greatly affected by DNS resolution, need to judge if it's native unlock or DNS unlock |
| Official Mainstream DNS | No | Small | Platform unlock mainly relies on node IP, DNS resolution basically doesn't interfere with unlocking |
| Non-mainstream / Self-built DNS | Yes | Large | Platform unlock results greatly affected by DNS resolution, need to judge if it's native unlock or DNS unlock |
So during testing, if the host currently uses official mainstream DNS, no judgment of whether it's native unlocking will be performed.
Platforms that are particularly sensitive to IP quality for unlocking include major AI platforms, local streaming services, Reddit, and Spotify. Other multinational platforms are generally less affected by IP quality when it comes to unlocking.
Platforms that are particularly sensitive to IP quality for unlocking include major AI platforms, local platform unlocking, Reddit, and Spotify. Other multinational platforms are generally less affected by IP quality when it comes to unlocking.
### IP Quality Detection
@@ -670,20 +714,19 @@ Generally speaking, checking the usage type, company type, and security informat
| ----------- | ---------- |
| hosting | Data center network (IDC) |
| residential | Home/Residential network (Home broadband) |
| FixedLineISP, ISP | Fixed-line Internet Service Provider (Home broadband) |
| isp | Fixed-line Internet Service Provider (Home broadband) |
| business | Enterprise office network (Business broadband) |
| cellular | Mobile carrier network (Home broadband) |
| education | Educational institution network (Education network) |
| government | Government institution network (Government network) |
| military | Military network (Government network) |
| DataCenter/WebHosting/Transit | Data center network (IDC) |
| CDN | Content Delivery Network (IDC) |
| Company Type | Description |
| ------------ | ------------ |
| business | Business company (Business broadband) |
| hosting | Hosting/Data center company (IDC) |
| FixedLineISP, ISP | Fixed-line Internet Service Provider (Home broadband) |
| business | Business company (Business broadband) |
| isp | Fixed-line Internet Service Provider (Home broadband) |
| education | Educational institution (Education network) |
| government | Government institution (Government network) |
@@ -716,11 +759,11 @@ If Abuse records exist and the score is high, it indicates that the IP may have
- Launched large-scale flood attacks
- Conducted port scanning or network-wide scanning
Such historical records will be reported and entered into the Abuse database. If the IP you take over has just been abused by others, delayed Abuse warning emails may still be sent to the service provider. The service provider may misjudge you as the person engaging in malicious behavior, and then terminate the machine, and in most cases, no refund will be given. For cross-border streaming services, Abuse scores may also affect the platform's reputation rating for that IP.
Such historical records will be reported and entered into the Abuse database. If the IP you take over has just been abused by others, delayed Abuse warning emails may still be sent to the service provider. The service provider may misjudge you as the person engaging in malicious behavior, and then terminate the machine, and in most cases, no refund will be given. For cross-border platform services, Abuse scores may also affect the platform's reputation rating for that IP.
For users who need residential broadband for streaming unlock requirements (such as e-commerce needs), attention should be paid to whether "Usage Type" and "Company Type" are both identified as ISP. If it is only single ISP or identified as non-ISP, after subsequent database updates, the IP type is likely to be corrected to Hosting, thereby affecting unlock effectiveness.
For users who need residential broadband for platform unlock requirements (such as e-commerce needs), attention should be paid to whether "Usage Type" and "Company Type" are both identified as ISP. If it is only single ISP or identified as non-ISP, after subsequent database updates, the IP type is likely to be corrected to Hosting, thereby affecting unlock effectiveness.
Most IP identification databases are updated monthly. After updates, IP attributes may be modified, resulting in situations where ISP → Hosting occurs. For some sensitive platforms, such as streaming services in certain specific countries (like Netflix, Spotify), or streaming services that treat different countries differently (like TikTok), the possibility of non-residential unlock is low but not impossible. If you need stable unlock and pursue its special function unlock, you only need to pursue residential broadband streaming unlock. If you're just browsing and watching, there's often no need to pursue residential broadband.
Most IP identification databases are updated monthly. After updates, IP attributes may be modified, resulting in situations where ISP → Hosting occurs. For some sensitive platforms, such as platform services in certain specific countries (like Netflix, Spotify), or platform services that treat different countries differently (like TikTok), the possibility of non-residential unlock is low but not impossible. If you need stable unlock and pursue its special function unlock, you only need to pursue residential broadband platform unlock. If you're just browsing and watching, there's often no need to pursue residential broadband.
It is necessary to elaborate on IP type classification
@@ -760,7 +803,7 @@ Dependency project: [https://github.com/oneclickvirt/pingtest](https://github.co
Measure the latency from the current IP address to each TG data center and major websites.
All addresses that cannot be tested for failure, as well as those with latency greater than or equal to 999ms, have their latency set to 999. Latency exceeding this threshold also indicates excessive target latency that impairs usability. At this point, the target should be considered unavailable.
All addresses that cannot be tested for failure, as well as those with latency greater than or equal to 9999ms, have their latency set to 9999. Latency exceeding this threshold also indicates excessive target latency that impairs usability. At this point, the target should be considered unavailable.
### Nearby Speed Testing
@@ -946,24 +989,24 @@ NVMe SSDの1M (IOPS)値 < 1GB/s の場合、深刻なリソースオーバーセ
注意ここでテストするのは真のIOで、本プロジェクト限定です。本プロジェクト以外でテストしたIOは基準の汎用性を保証しません。彼らがテスト時に同じパラメータを使用していない可能性、IO直接読み書きを設定していない可能性、IOエンジン設定が一致しない可能性、テスト時間設定が一致しない可能性があり、すべて基準の偏差を引き起こします。
### ストリーミングメディアロック解除
### プラットフォームロック解除検出
依存プロジェクト:[https://github.com/oneclickvirt/CommonMediaTests](https://github.com/oneclickvirt/CommonMediaTests) [https://github.com/lmc999/RegionRestrictionCheck](https://github.com/lmc999/RegionRestrictionCheck)
依存プロジェクト:[https://github.com/oneclickvirt/UnlockTests](https://github.com/oneclickvirt/UnlockTests)
デフォルトでは国境を越えるストリーミングメディアのロック解除のみをチェックします。
デフォルトでは国境を越えるプラットフォームのロック解除のみをチェックします。
一般的に、正常な状況下では、一つのIPの複数のストリーミングメディアのロック解除地域はすべて一致し、あちこち飛び回ることはありません。複数のプラットフォームでロック解除地域が一致しない場合、IPはIPXOなどのプラットフォームからのレンタルか、最近宣告され使用されたもので、ストリーミングメディアの一般的なデータベースに認識修正されていない可能性が高いです。
一般的に、正常な状況下では、一つのIPの複数のプラットフォームのロック解除地域はすべて一致し、あちこち飛び回ることはありません。複数のプラットフォームでロック解除地域が一致しない場合、IPはIPXOなどのプラットフォームからのレンタルか、最近宣告され使用されたもので、プラットフォームの一般的なデータベースに認識修正されていない可能性が高いです。
各プラットフォームのIPデータベース認識速度が一致しないため、時々あるプラットフォームではロック解除地域が正常、あるプラットフォームではルート上のある位置に飛ぶ、あるプラットフォームではIPがあなたによって使用される前にいた位置に飛ぶことがあります。
| DNS タイプ | ロック解除方式判断の必要性 | DNSのロック解除への影響 | 説明 |
| --------- | ------------------------- | ---------------------- | ---- |
| 公式主流DNS | 不要 | 小 | ストリーミングメディアのロック解除は主にードIPに依存し、DNS解析は基本的にロック解除を干渉しない |
| 非主流/自建DNS | 必要 | 大 | ストリーミングメディアのロック解除結果はDNS解析の影響を大きく受け、ネイティブロック解除かDNSロック解除かを判断する必要がある |
| 公式主流DNS | 不要 | 小 | プラットフォームロック解除は主にードIPに依存し、DNS解析は基本的にロック解除を干渉しない |
| 非主流/自建DNS | 必要 | 大 | プラットフォームロック解除結果はDNS解析の影響を大きく受け、ネイティブロック解除かDNSロック解除かを判断する必要がある |
そのため、テスト過程で、ホストが現在使用しているのが公式主流のDNSの場合、ネイティブロック解除かどうかの判断は行われません。
IP品質によるアクセス制限に敏感なのは、実際には主要なAIプラットフォームやローカルストリーミングサービス、redditやspotifyなどであり、その他の多国籍プラットフォームは一般的にIP品質の影響を受けにくい。
IP品質によるアクセス制限に敏感なのは、実際には主要なAIプラットフォームやローカルプラットフォームロック解除、redditやspotifyなどであり、その他の多国籍プラットフォームは一般的にIP品質の影響を受けにくい。
### IP品質検出
@@ -1004,20 +1047,19 @@ IP品質によるアクセス制限に敏感なのは、実際には主要なAI
| ----------- | ---------- |
| hosting | データセンターネットワーク(IDC) |
| residential | 家庭/住宅ネットワーク(家庭用回線) |
| FixedLineISP、ISP | 固定回線インターネットサービスプロバイダー(家庭用回線) |
| isp | 固定回線インターネットサービスプロバイダー(家庭用回線) |
| business | 企業オフィスネットワーク(ビジネス回線) |
| cellular | モバイル通信事業者ネットワーク(家庭用回線) |
| education | 教育機関ネットワーク(教育ネットワーク) |
| government | 政府機関ネットワーク(政府ネットワーク) |
| military | 軍事ネットワーク(政府ネットワーク) |
| DataCenter/WebHosting/Transit | データセンターネットワーク(IDC) |
| CDN | コンテンツ配信ネットワーク(IDC) |
| 会社タイプ | 説明 |
| ------------ | ------------ |
| business | 企業会社(ビジネス回線) |
| hosting | ホスト/データセンター会社(IDC) |
| FixedLineISP、ISP | 固定回線インターネットサービスプロバイダー(家庭用回線) |
| business | 企業会社(ビジネス回線) |
| isp | 固定回線インターネットサービスプロバイダー(家庭用回線) |
| education | 教育機関(教育ネットワーク) |
| government | 政府機関(政府ネットワーク) |
@@ -1050,11 +1092,11 @@ Abuse記録が存在し、スコアが高い場合、そのIPが過去に以下
- 大規模なフラッド攻撃を開始した
- ポートスキャンまたはネットワーク全体のスキャンを実施した
このような履歴記録は報告され、Abuseデータベースに登録される。引き継いだIPが他人によって悪用されたばかりの場合、遅延したAbuse警告メールがサービスプロバイダに送信される可能性がある。サービスプロバイダは、あなた本人が悪意のある行為を行っていると誤判定し、マシンを解約する可能性があり、ほとんどの場合、返金は行われない。国境を越えたストリーミングサービスの場合、AbuseスコアはそのIPに対するプラットフォームの信頼評価にも影響を与える可能性がある。
このような履歴記録は報告され、Abuseデータベースに登録される。引き継いだIPが他人によって悪用されたばかりの場合、遅延したAbuse警告メールがサービスプロバイダに送信される可能性がある。サービスプロバイダは、あなた本人が悪意のある行為を行っていると誤判定し、マシンを解約する可能性があり、ほとんどの場合、返金は行われない。国境を越えたプラットフォームサービスの場合、AbuseスコアはそのIPに対するプラットフォームの信頼評価にも影響を与える可能性がある。
ストリーミング解除要件のために住宅ブロードバンドが必要なユーザー(Eコマース需要など)は、「使用タイプ」と「会社タイプ」の両方がISPとして識別されているかどうかに注意を払う必要がある。単一ISPのみ、または非ISPとして識別されている場合、その後のデータベース更新後、IPタイプがHostingに修正される可能性が高く、解除効果に影響を与える。
プラットフォームロック解除要件のために住宅ブロードバンドが必要なユーザー(Eコマース需要など)は、「使用タイプ」と「会社タイプ」の両方がISPとして識別されているかどうかに注意を払う必要がある。単一ISPのみ、または非ISPとして識別されている場合、その後のデータベース更新後、IPタイプがHostingに修正される可能性が高く、解除効果に影響を与える。
ほとんどのIP識別データベースは月次で更新される。更新後、IP属性が変更され、ISP → Hostingという状況が発生する可能性がある。特定の国のストリーミングサービス(NetflixやSpotifyなど)や、異なる国を区別して扱うストリーミングサービス(TikTokなど)など、一部の敏感なプラットフォームでは、非住宅での解除の可能性は低いが、不可能ではない。安定した解除が必要で、その特別な機能解除を追求する場合にのみ、住宅ブロードバンドストリーミング解除を追求する必要がある。単にブラウジングや視聴するだけであれば、多くの場合、住宅ブロードバンドを追求する必要はない。
ほとんどのIP識別データベースは月次で更新される。更新後、IP属性が変更され、ISP → Hostingという状況が発生する可能性がある。特定の国のプラットフォームサービス(NetflixやSpotifyなど)や、異なる国を区別して扱うプラットフォームサービス(TikTokなど)など、一部の敏感なプラットフォームでは、非住宅での解除の可能性は低いが、不可能ではない。安定した解除が必要で、その特別な機能解除を追求する場合にのみ、住宅ブロードバンドプラットフォームロック解除を追求する必要がある。単にブラウジングや視聴するだけであれば、多くの場合、住宅ブロードバンドを追求する必要はない。
IPタイプの分類について詳しく説明する必要がある
@@ -1094,7 +1136,7 @@ IPタイプの分類について詳しく説明する必要がある
現在のIPアドレスからTGの各データセンターおよび主要ウェブサイトまでの遅延を測定します。
検出不能な失敗アドレスおよび遅延が999ms以上のものは、遅延を999に設定する。この値を超える遅延は対象の遅延が過大で利用に影響することを示すため、この時点で対象は利用不可と判断すればよい。
検出不能な失敗アドレスおよび遅延が9999ms以上のものは、遅延を9999に設定する。この値を超える遅延は対象の遅延が過大で利用に影響することを示すため、この時点で対象は利用不可と判断すればよい。
### 近隣スピードテスト

13
go.mod
View File

@@ -4,19 +4,18 @@ go 1.25.3
require (
github.com/imroc/req/v3 v3.54.0
github.com/oneclickvirt/CommonMediaTests v0.0.4-20250329123841
github.com/oneclickvirt/UnlockTests v0.0.30-20251030112700
github.com/oneclickvirt/backtrace v0.0.8-20251102140847
github.com/oneclickvirt/UnlockTests v0.0.31-20251111095646
github.com/oneclickvirt/backtrace v0.0.8-20251109090457
github.com/oneclickvirt/basics v0.0.16-20251030093657
github.com/oneclickvirt/cputest v0.0.12-20250720122317
github.com/oneclickvirt/cputest v0.0.12-20251111095842
github.com/oneclickvirt/defaultset v0.0.2-20240624082446
github.com/oneclickvirt/disktest v0.0.10-20250924030424
github.com/oneclickvirt/gostun v0.0.5-20250727155022
github.com/oneclickvirt/memorytest v0.0.10-20250924154648
github.com/oneclickvirt/nt3 v0.0.10-20251103023436
github.com/oneclickvirt/pingtest v0.0.9-20251102150730
github.com/oneclickvirt/nt3 v0.0.10-20251111095706
github.com/oneclickvirt/pingtest v0.0.9-20251104112920
github.com/oneclickvirt/portchecker v0.0.3-20250728015900
github.com/oneclickvirt/security v0.0.7-20251030094114
github.com/oneclickvirt/security v0.0.7-20251109090041
github.com/oneclickvirt/speedtest v0.0.11-20251102151740
)

26
go.sum
View File

@@ -94,16 +94,14 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/nxtrace/NTrace-core v1.4.3-rc.1 h1:V19tkw3kKAMQOOh7Ibb/jZFBk4kMUfQYmpxxtsOfYWo=
github.com/nxtrace/NTrace-core v1.4.3-rc.1/go.mod h1:lGhfZ916pEUJh+VzWZTYu7bKBo06pAn+/gXb0A/7gGg=
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.30-20251030112700 h1:dtHHyWZdshox8StzrjgImj3Rvqwup5OZJ8FAZZQjPIA=
github.com/oneclickvirt/UnlockTests v0.0.30-20251030112700/go.mod h1:oOa6wj/qECtRMxwBO6D7o0L0F0Q/5sQ747OCnFQqoGE=
github.com/oneclickvirt/backtrace v0.0.8-20251102140847 h1:OiwD06+Mql3pYP8jJFFdP3OUlCrx/qJT7y2YCd/OMiI=
github.com/oneclickvirt/backtrace v0.0.8-20251102140847/go.mod h1:mj9TSow7FNszBb3bQj2Hhm41LwBo7HQP6sgaPtovKdM=
github.com/oneclickvirt/UnlockTests v0.0.31-20251111095646 h1:GXwimPara6aY88GNYnTkFQfr/aLPsFATT4aDTRDdVsU=
github.com/oneclickvirt/UnlockTests v0.0.31-20251111095646/go.mod h1:oOa6wj/qECtRMxwBO6D7o0L0F0Q/5sQ747OCnFQqoGE=
github.com/oneclickvirt/backtrace v0.0.8-20251109090457 h1:599/R/qMAtfPCPG1bPoi6KbjNJzVkKtxm8dvVIdtn5o=
github.com/oneclickvirt/backtrace v0.0.8-20251109090457/go.mod h1:mj9TSow7FNszBb3bQj2Hhm41LwBo7HQP6sgaPtovKdM=
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/cputest v0.0.12-20251111095842 h1:ixZUvIkSlsIZfsg+dNDKq/FTofEtUjfA2LtpTrNr/6s=
github.com/oneclickvirt/cputest v0.0.12-20251111095842/go.mod h1:vjlH8tkPFft1tlLOpeNskXVvurxkHaJ3+dgFxQGLXY4=
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=
@@ -118,14 +116,14 @@ github.com/oneclickvirt/mbw v0.0.1-20250808061222 h1:WGXOe6QvHiDRhPVMI0VcctjzW08
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.10-20251103023436 h1:vXqiU/HE0EXGf17LHyIQx8xYJz3+MOCHtlbfKyvt3cQ=
github.com/oneclickvirt/nt3 v0.0.10-20251103023436/go.mod h1:yo1ufkduFt9QjqG7nqSUf1D3YlQOmFpdlTYniJfclQI=
github.com/oneclickvirt/pingtest v0.0.9-20251102150730 h1:pipqyJUaUI0K5waFvDNNfqbIikMp+9Kg8Dw/kLEUYF8=
github.com/oneclickvirt/pingtest v0.0.9-20251102150730/go.mod h1:gxwsxxwitNQiGq2OI0ZogYoOLwc8DtuOdSRe6/EvRqs=
github.com/oneclickvirt/nt3 v0.0.10-20251111095706 h1:GEdgL6oAWXY80NIq23mLjcTR3gvLGh9iusFzJK6SoDo=
github.com/oneclickvirt/nt3 v0.0.10-20251111095706/go.mod h1:yo1ufkduFt9QjqG7nqSUf1D3YlQOmFpdlTYniJfclQI=
github.com/oneclickvirt/pingtest v0.0.9-20251104112920 h1:j3Fjhy0YHT/VF7iuAVVELaRXkquvRd64tWWfFLJs01o=
github.com/oneclickvirt/pingtest v0.0.9-20251104112920/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.7-20251030094114 h1:Ax8J1TYqprXyiWNAIJJ3xhoyGhvBlKw4m9j6va5Q2nM=
github.com/oneclickvirt/security v0.0.7-20251030094114/go.mod h1:YfDilPFW22szjdUNgv4VOuSwHnZzsFsdPOfRYiMoc3I=
github.com/oneclickvirt/security v0.0.7-20251109090041 h1:H5Brkx2pKNRZAnvk1wABFcg+krXAygHgWV9R3+LU7xE=
github.com/oneclickvirt/security v0.0.7-20251109090041/go.mod h1:YfDilPFW22szjdUNgv4VOuSwHnZzsFsdPOfRYiMoc3I=
github.com/oneclickvirt/speedtest v0.0.11-20251102151740 h1:1NUrNt5ay6/xVNC5x62UrQjPqK8jgbKtyjBml/3boZg=
github.com/oneclickvirt/speedtest v0.0.11-20251102151740/go.mod h1:fy0II2Wo7kDWVBKTwcHdodZwyfmJo0g8N9V02EwQDZE=
github.com/oneclickvirt/stream v0.0.2-20250924154001 h1:GuJWdiPkoK84+y/+oHKr2Ghl3c/MzS9Z5m1nM+lMmy4=

View File

@@ -10,7 +10,6 @@ import (
"syscall"
"time"
"github.com/oneclickvirt/CommonMediaTests/commediatests"
unlocktestmodel "github.com/oneclickvirt/UnlockTests/model"
backtracemodel "github.com/oneclickvirt/backtrace/model"
basicmodel "github.com/oneclickvirt/basics/model"
@@ -28,7 +27,7 @@ import (
)
var (
ecsVersion = "v0.1.98" // 融合怪版本号
ecsVersion = "v0.1.103" // 融合怪版本号
configs = params.NewConfig(ecsVersion) // 全局配置实例
userSetFlags = make(map[string]bool) // 用于跟踪哪些参数是用户显式设置的
)
@@ -40,7 +39,6 @@ func initLogger() {
cputestmodel.EnableLoger = true
memorytestmodel.EnableLoger = true
disktestmodel.EnableLoger = true
commediatests.EnableLoger = true
unlocktestmodel.EnableLoger = true
ptmodel.EnableLoger = true
backtracemodel.EnableLoger = true
@@ -85,6 +83,7 @@ func main() {
basicInfo, securityInfo, emailInfo, mediaInfo, ptInfo string
output, tempOutput string
outputMutex sync.Mutex
infoMutex sync.Mutex // 保护并发字符串写入
)
startTime := time.Now()
uploadDone := make(chan bool, 1)
@@ -93,9 +92,9 @@ func main() {
go runner.HandleSignalInterrupt(sig, configs, &startTime, &output, tempOutput, uploadDone, &outputMutex)
switch configs.Language {
case "zh":
runner.RunChineseTests(preCheck, configs, &wg1, &wg2, &wg3, &basicInfo, &securityInfo, &emailInfo, &mediaInfo, &ptInfo, &output, tempOutput, startTime, &outputMutex)
runner.RunChineseTests(preCheck, configs, &wg1, &wg2, &wg3, &basicInfo, &securityInfo, &emailInfo, &mediaInfo, &ptInfo, &output, tempOutput, startTime, &outputMutex, &infoMutex)
case "en":
runner.RunEnglishTests(preCheck, configs, &wg1, &wg2, &wg3, &basicInfo, &securityInfo, &emailInfo, &mediaInfo, &ptInfo, &output, tempOutput, startTime, &outputMutex)
runner.RunEnglishTests(preCheck, configs, &wg1, &wg2, &wg3, &basicInfo, &securityInfo, &emailInfo, &mediaInfo, &ptInfo, &output, tempOutput, startTime, &outputMutex, &infoMutex)
default:
fmt.Println("Unsupported language")
}

View File

@@ -152,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.97"
ECS_VERSION="0.1.102"
for api in \
"https://api.github.com/repos/oneclickvirt/ecs/releases/latest" \
"https://githubapi.spiritlhl.workers.dev/repos/oneclickvirt/ecs/releases/latest" \
@@ -164,8 +164,8 @@ goecs_check() {
sleep 1
done
if [ -z "$ECS_VERSION" ]; then
_yellow "Unable to get version info, using default version 0.1.97"
ECS_VERSION="0.1.97"
_yellow "Unable to get version info, using default version 0.1.102"
ECS_VERSION="0.1.102"
fi
version_output=""
for cmd_path in "goecs" "./goecs" "/usr/bin/goecs" "/usr/local/bin/goecs"; do

View File

@@ -21,7 +21,7 @@ func GetMenuChoice(language string) string {
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
defer signal.Stop(sigChan)
inputChan := make(chan string, 1)
go func() {
select {
case <-sigChan:
@@ -31,43 +31,33 @@ func GetMenuChoice(language string) string {
return
}
}()
for {
go func() {
var input string
fmt.Print("请输入选项 / Please enter your choice: ")
fmt.Scanln(&input)
input = strings.TrimSpace(input)
input = strings.TrimRight(input, "\n")
select {
case inputChan <- input:
case <-ctx.Done():
return
}
}()
select {
case input := <-inputChan:
re := regexp.MustCompile(`^\d+$`)
if re.MatchString(input) {
inChoice := input
switch inChoice {
case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10":
return inChoice
default:
if language == "zh" {
fmt.Println("无效的选项")
} else {
fmt.Println("Invalid choice")
}
}
} else {
var input string
fmt.Print("请输入选项 / Please enter your choice: ")
fmt.Scanln(&input)
input = strings.TrimSpace(input)
input = strings.TrimRight(input, "\n")
re := regexp.MustCompile(`^\d+$`)
if re.MatchString(input) {
inChoice := input
switch inChoice {
case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10":
return inChoice
default:
if language == "zh" {
fmt.Println("输入错误,请输入一个纯数字")
fmt.Println("无效的选项")
} else {
fmt.Println("Invalid input, please enter a number")
fmt.Println("Invalid choice")
}
}
case <-ctx.Done():
return ""
} else {
if language == "zh" {
fmt.Println("输入错误,请输入一个纯数字")
} else {
fmt.Println("Invalid input, please enter a number")
}
}
}
}
@@ -127,13 +117,13 @@ func PrintMenuOptions(preCheck utils.NetCheckResult, config *params.Config) {
}
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质量检测+上游及三网回程+广州三网回程详细路由+全国延迟+TGDC+网站延迟+测速节点11个)")
fmt.Println("7. 解锁单项(御三家解锁+常用流媒体解锁)")
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质量检测+上游及三网回程+广州三网回程详细路由+全国延迟+TGDC+网站延迟+测速节点11个)")
fmt.Println("7. 解锁单项(跨国平台解锁)")
fmt.Println("8. 硬件单项(系统信息+CPU+dd磁盘测试+fio磁盘测试)")
fmt.Println("9. IP质量检测(15个数据库的IP质量检测+邮件端口检测)")
fmt.Println("10. 三网回程线路检测+三网回程详细路由(北京上海广州成都)+全国延迟+TGDC+网站延迟")
@@ -147,16 +137,16 @@ func PrintMenuOptions(preCheck utils.NetCheckResult, config *params.Config) {
}
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)")
fmt.Println("5. Unlock-Focused Test Suite (System Info + CPU + Memory + Disk IO + Basic Unlock Tests + Common Streaming Services + 5 Speed Test Nodes)")
fmt.Println("6. Network-Only Test (IP Quality Test + TGDC + Websites + 11 Speed Test Nodes)")
fmt.Println("7. Unlock-Only Test (Basic Unlock Tests + Common Streaming Services Unlock)")
fmt.Println("8. Hardware-Only Test (System Info + CPU + Memory + dd Disk Test + fio Disk Test)")
fmt.Println("9. IP Quality Test (IP Test with 15 Databases + Email Port Test)")
fmt.Println("0. Exit Program")
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 + International Platform Unlock + Routing + 5 Speed Test Nodes)")
fmt.Println("4. Network-Focused Test Suite (System Info + CPU + Memory + Disk + Backtrace + Routing + 5 Speed Test Nodes)")
fmt.Println("5. Unlock-Focused Test Suite (System Info + CPU + Memory + Disk IO + International Platform Unlock + 5 Speed Test Nodes)")
fmt.Println("6. Network-Only Test (IP Quality Test + Upstream & 3-Network Backtrace + Guangzhou 3-Network Detailed Routing + National Latency + TGDC + Websites + 11 Speed Test Nodes)")
fmt.Println("7. Unlock-Only Test (International Platform 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")
}
}
@@ -167,7 +157,6 @@ func HandleMenuMode(preCheck utils.NetCheckResult, config *params.Config) {
config.CpuTestStatus = false
config.MemoryTestStatus = false
config.DiskTestStatus = false
config.CommTestStatus = false
config.UtTestStatus = false
config.SecurityTestStatus = false
config.EmailTestStatus = false
@@ -246,7 +235,6 @@ func SetFullTestStatus(preCheck utils.NetCheckResult, config *params.Config) {
config.MemoryTestStatus = true
config.DiskTestStatus = true
if preCheck.Connected {
config.CommTestStatus = true
config.UtTestStatus = true
config.SecurityTestStatus = true
config.EmailTestStatus = true
@@ -302,7 +290,6 @@ func SetUnlockFocusedTestStatus(preCheck utils.NetCheckResult, config *params.Co
config.MemoryTestStatus = true
config.DiskTestStatus = true
if preCheck.Connected {
config.CommTestStatus = true
config.UtTestStatus = true
config.SpeedTestStatus = true
}
@@ -323,7 +310,6 @@ func SetNetworkOnlyTestStatus(config *params.Config) {
// SetUnlockOnlyTestStatus sets unlock-only test configuration
func SetUnlockOnlyTestStatus(config *params.Config) {
config.OnlyIpInfoCheck = true
config.CommTestStatus = true
config.UtTestStatus = true
}

View File

@@ -29,7 +29,6 @@ type Config struct {
CpuTestStatus bool
MemoryTestStatus bool
DiskTestStatus bool
CommTestStatus bool
UtTestStatus bool
SecurityTestStatus bool
EmailTestStatus bool
@@ -65,7 +64,6 @@ func NewConfig(version string) *Config {
CpuTestStatus: true,
MemoryTestStatus: true,
DiskTestStatus: true,
CommTestStatus: true,
UtTestStatus: true,
SecurityTestStatus: true,
EmailTestStatus: true,
@@ -94,7 +92,6 @@ func (c *Config) ParseFlags(args []string) {
c.GoecsFlag.BoolVar(&c.CpuTestStatus, "cpu", true, "Enable/Disable CPU test")
c.GoecsFlag.BoolVar(&c.MemoryTestStatus, "memory", true, "Enable/Disable memory test")
c.GoecsFlag.BoolVar(&c.DiskTestStatus, "disk", true, "Enable/Disable disk test")
c.GoecsFlag.BoolVar(&c.CommTestStatus, "comm", true, "Enable/Disable common media test")
c.GoecsFlag.BoolVar(&c.UtTestStatus, "ut", true, "Enable/Disable unlock media test")
c.GoecsFlag.BoolVar(&c.SecurityTestStatus, "security", true, "Enable/Disable security test")
c.GoecsFlag.BoolVar(&c.EmailTestStatus, "email", true, "Enable/Disable email port test")
@@ -152,9 +149,6 @@ func (c *Config) SaveUserSetParams() map[string]interface{} {
if c.UserSetFlags["disk"] {
saved["disk"] = c.DiskTestStatus
}
if c.UserSetFlags["comm"] {
saved["comm"] = c.CommTestStatus
}
if c.UserSetFlags["ut"] {
saved["ut"] = c.UtTestStatus
}
@@ -216,75 +210,116 @@ func (c *Config) SaveUserSetParams() map[string]interface{} {
// RestoreUserSetParams restores user-set parameters
func (c *Config) RestoreUserSetParams(saved map[string]interface{}) {
if val, ok := saved["basic"]; ok {
c.BasicStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.BasicStatus = boolVal
}
}
if val, ok := saved["cpu"]; ok {
c.CpuTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.CpuTestStatus = boolVal
}
}
if val, ok := saved["memory"]; ok {
c.MemoryTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.MemoryTestStatus = boolVal
}
}
if val, ok := saved["disk"]; ok {
c.DiskTestStatus = val.(bool)
}
if val, ok := saved["comm"]; ok {
c.CommTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.DiskTestStatus = boolVal
}
}
if val, ok := saved["ut"]; ok {
c.UtTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.UtTestStatus = boolVal
}
}
if val, ok := saved["security"]; ok {
c.SecurityTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.SecurityTestStatus = boolVal
}
}
if val, ok := saved["email"]; ok {
c.EmailTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.EmailTestStatus = boolVal
}
}
if val, ok := saved["backtrace"]; ok {
c.BacktraceStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.BacktraceStatus = boolVal
}
}
if val, ok := saved["nt3"]; ok {
c.Nt3Status = val.(bool)
if boolVal, ok := val.(bool); ok {
c.Nt3Status = boolVal
}
}
if val, ok := saved["speed"]; ok {
c.SpeedTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.SpeedTestStatus = boolVal
}
}
if val, ok := saved["ping"]; ok {
c.PingTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.PingTestStatus = boolVal
}
}
if val, ok := saved["tgdc"]; ok {
c.TgdcTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.TgdcTestStatus = boolVal
}
}
if val, ok := saved["web"]; ok {
c.WebTestStatus = val.(bool)
if boolVal, ok := val.(bool); ok {
c.WebTestStatus = boolVal
}
}
if val, ok := saved["cpum"]; ok {
c.CpuTestMethod = val.(string)
if strVal, ok := val.(string); ok {
c.CpuTestMethod = strVal
}
}
if val, ok := saved["cput"]; ok {
c.CpuTestThreadMode = val.(string)
if strVal, ok := val.(string); ok {
c.CpuTestThreadMode = strVal
}
}
if val, ok := saved["memorym"]; ok {
c.MemoryTestMethod = val.(string)
if strVal, ok := val.(string); ok {
c.MemoryTestMethod = strVal
}
}
if val, ok := saved["diskm"]; ok {
c.DiskTestMethod = val.(string)
if strVal, ok := val.(string); ok {
c.DiskTestMethod = strVal
}
}
if val, ok := saved["diskp"]; ok {
c.DiskTestPath = val.(string)
if strVal, ok := val.(string); ok {
c.DiskTestPath = strVal
}
}
if val, ok := saved["diskmc"]; ok {
c.DiskMultiCheck = val.(bool)
if boolVal, ok := val.(bool); ok {
c.DiskMultiCheck = boolVal
}
}
if val, ok := saved["nt3loc"]; ok {
if c.Choice != "10" {
c.Nt3Location = val.(string)
if strVal, ok := val.(string); ok {
c.Nt3Location = strVal
}
}
}
if val, ok := saved["nt3t"]; ok {
c.Nt3CheckType = val.(string)
if strVal, ok := val.(string); ok {
c.Nt3CheckType = strVal
}
}
if val, ok := saved["spnum"]; ok {
c.SpNum = val.(int)
if intVal, ok := val.(int); ok {
c.SpNum = intVal
}
}
c.ValidateParams()

View File

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

View File

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

View File

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

View File

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

View File

@@ -2,14 +2,55 @@ package tests
import (
"fmt"
"net"
"os"
"strings"
"github.com/oneclickvirt/nt3/nt"
)
func NextTrace3Check(language, nt3Location, nt3CheckType string) {
// 先检查 ICMP 权限
conn, err := net.ListenPacket("ip4:icmp", "0.0.0.0")
if err != nil {
// 没有权限,显示友好提示并跳过
if language == "zh" {
fmt.Println("路由追踪测试需要 root 权限或 CAP_NET_RAW 能力,已跳过")
fmt.Fprintf(os.Stderr, "[WARN] ICMP权限不足: %v\n", err)
} else {
fmt.Println("Route tracing test requires root privileges or CAP_NET_RAW capability, skipped")
fmt.Fprintf(os.Stderr, "[WARN] Insufficient ICMP permission: %v\n", err)
}
return
}
conn.Close()
defer func() {
if r := recover(); r != nil {
if language == "zh" {
fmt.Println("路由追踪测试出现错误,已跳过")
fmt.Fprintf(os.Stderr, "[WARN] 路由追踪panic: %v\n", r)
} else {
fmt.Println("Route tracing test failed, skipped")
fmt.Fprintf(os.Stderr, "[WARN] Route tracing panic: %v\n", r)
}
}
}()
resultChan := make(chan nt.TraceResult, 100)
go nt.TraceRoute(language, nt3Location, nt3CheckType, resultChan)
errorOccurred := false
go func() {
defer func() {
if r := recover(); r != nil {
errorOccurred = true
resultChan <- nt.TraceResult{
Index: -1,
ISPName: "Error",
Output: []string{fmt.Sprintf("Route tracing error: %v", r)},
}
close(resultChan)
}
}()
nt.TraceRoute(language, nt3Location, nt3CheckType, resultChan)
}()
for result := range resultChan {
if result.Index == -1 {
for index, res := range result.Output {
@@ -21,13 +62,19 @@ func NextTrace3Check(language, nt3Location, nt3CheckType string) {
continue
}
if result.ISPName == "Error" {
if language == "zh" {
fmt.Println("路由追踪测试失败(可能因为权限不足),已跳过")
} else {
fmt.Println("Route tracing test failed (possibly due to insufficient permissions), skipped")
}
for _, res := range result.Output {
res = strings.TrimSpace(res)
if res != "" {
fmt.Println(res)
fmt.Fprintf(os.Stderr, "[WARN] %s\n", res)
}
}
return
errorOccurred = true
continue
}
for _, res := range result.Output {
res = strings.TrimSpace(res)
@@ -41,4 +88,11 @@ func NextTrace3Check(language, nt3Location, nt3CheckType string) {
}
}
}
if errorOccurred {
if language == "zh" {
fmt.Println("提示: 路由追踪需要 root 权限或 CAP_NET_RAW 能力")
} else {
fmt.Println("Hint: Route tracing requires root privileges or CAP_NET_RAW capability")
}
}
}

View File

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

View File

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

View File

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

View File

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