Compare commits

...

39 Commits

Author SHA1 Message Date
spiritlhl
04ce926582 fix: 更新主版本 2025-08-23 03:35:33 +00:00
spiritlhl
73eb38eed1 fix: 删除无效包导入 2025-08-23 03:34:51 +00:00
spiritlhl
9bc8a934b1 fix: 修复标识输出 2025-08-23 03:19:32 +00:00
spiritlhl
7b729e073b fix: 移动弃用的文件 2025-08-23 03:17:05 +00:00
spiritlhl
111126ae90 fix: 添加内存测试项基准说明,修复部分比较含糊的说明。 2025-08-23 03:15:54 +00:00
spiritlhl
9397f789be fix: 同步securitycheck上游更新,更新主程序版本号,去除默认的清屏操作 2025-08-23 03:02:13 +00:00
spiritlhl
5a1dda6483 fix: 添加额外的ASN获取方式,当查询失败时回落尝试修复查询(虽然出现问题的概率极小) 2025-08-23 02:56:02 +00:00
spiritlhl
e322c717c0 fix: 安装依赖去除sysbench编译尝试,主程序已自带sysbench回落机制,没必要强求依赖安装 2025-08-23 02:52:55 +00:00
spiritlhl
778b33142b fix: 自行编译的分支添加标识为非官方编译 2025-08-23 02:51:32 +00:00
spiritlhl
aa9f361380 feat: 添加Release的下载量统计 2025-08-19 13:00:05 +00:00
github-actions[bot]
3236c60359 chore: update ECS_VERSION to 0.1.83 in goecs.sh 2025-08-11 13:45:39 +00:00
spiritlhl
73b0f30ddc fix: 删除无效文件,去除无效重定向 2025-08-11 13:31:18 +00:00
spiritlhl
825da78bd5 fix: 外部重定向已捕捉无需重复捕捉 2025-08-11 13:16:46 +00:00
spiritlhl
5d2f3c7f96 fix: 更新版本 2025-08-11 13:14:33 +00:00
spiritlhl
61247a206e fix: 删除无效的并发 2025-08-11 13:08:20 +00:00
spiritlhl
f0daad1360 fix: 修复重定向冲突问题,由于nexttrace上层捕获了输出,无法再在融合怪中再次捕获进行重定向 2025-08-11 13:04:25 +00:00
github-actions[bot]
2d23fb55a0 chore: update ECS_VERSION to 0.1.79 in goecs.sh 2025-08-11 12:13:04 +00:00
spiritlhl
a73dbf2d0b fix: 修复部分单项测试说明错位 2025-08-11 12:08:51 +00:00
spiritlhl
b38dd713d9 fix: 修复退出选项被筛选逻辑拦截的问题 2025-08-11 20:02:20 +08:00
github-actions[bot]
e66ef1f106 chore: update ECS_VERSION to 0.1.77 in goecs.sh 2025-08-11 11:52:15 +00:00
spiritlhl
f6ee1e40ec fix: 添加退出程序的选项,添加开始执行前的清屏逻辑 2025-08-11 11:37:43 +00:00
spiritlhl
cb2bf0a7e5 fix: 主体逻辑将backtrace和三网路由详情检测加入整体的并发检测 2025-08-11 11:25:32 +00:00
spiritlhl
ad017db5a6 fix: 更新版本 2025-08-11 11:15:13 +00:00
spiritlhl
a99f58518a fix: 升级backtrace依赖,支持多重路由测试取平均结果,避免单次路由波动分析失败 2025-08-11 11:13:07 +00:00
spiritlhl
2e59bac322 fix: 提取三网详细路由的测试逻辑至于单独的包,添加单项测试 2025-08-11 10:59:17 +00:00
spiritlhl
4132b1daff feat: 详细三网路由测试支持并发测试,大幅缩短测试所需时间 2025-08-11 10:53:48 +00:00
github-actions[bot]
53296b745a chore: update ECS_VERSION to 0.1.76 in goecs.sh 2025-08-08 14:53:41 +00:00
spiritlhl
74630e9615 fix: 更新说明 2025-08-08 14:31:09 +00:00
spiritlhl
5ec7924214 fix: 更新版本(mbw已回落可用但未能测出真实性能) 2025-08-08 14:26:31 +00:00
spiritlhl
7a7fdc26a0 fix: memorytest更新依赖 2025-08-08 14:23:16 +00:00
spiritlhl
d4c855de92 fix: disktest去除无效的条件筛选 2025-08-08 14:16:50 +00:00
spiritlhl
7c22dee443 fix: 修复windows系统非Admin权限下的硬盘测试(FIO测试无误,DD测试缺少C依赖) 2025-08-08 14:15:59 +00:00
github-actions[bot]
797496b640 chore: update ECS_VERSION to 0.1.75 in goecs.sh 2025-08-06 09:12:25 +00:00
spiritlhl
5b686abdc8 fix: 规范输出 2025-08-06 09:06:48 +00:00
spiritlhl
f99a37edbe fix: 更新版本 2025-08-06 09:04:38 +00:00
spiritlhl
4ff49c8b90 fix: 离线模式下不检测程序版本,不统计使用次数 2025-08-06 09:02:57 +00:00
spiritlhl
1d9257beb3 fix: 合并缓存IP的存储位置 2025-08-06 08:51:50 +00:00
spiritlhl
fc6ccb9f92 fix: 修复无系统信息检测时无对应IP信息检测导致后续依赖IP信息查询的函数异常输出的问题 2025-08-06 08:45:00 +00:00
github-actions[bot]
88a2a7fdc9 chore: update ECS_VERSION to 0.1.74 in goecs.sh 2025-08-05 14:28:15 +00:00
24 changed files with 419 additions and 292 deletions

14
.back/OldFunction.go Normal file
View File

@@ -0,0 +1,14 @@
// clearScreen 清屏
func clearScreen() {
var cmd *exec.Cmd
switch runtime.GOOS {
case "windows":
cmd = exec.Command("cmd", "/c", "cls")
case "darwin":
cmd = exec.Command("clear")
default:
cmd = exec.Command("clear")
}
cmd.Stdout = os.Stdout
_ = cmd.Run()
}

View File

@@ -1,9 +0,0 @@
package backtrace
import (
"github.com/oneclickvirt/backtrace/bk"
)
func BackTrace(enableIpv6 bool) {
backtrace.BackTrace(enableIpv6)
}

View File

@@ -1,21 +0,0 @@
package backtrace
import (
"testing"
)
//func TestGeneratePrefixMap(t *testing.T) {
// prefix := "223.119.8.0/21"
// prefixList := GeneratePrefixList(prefix)
// if prefixList != nil {
// // 打印生成的IP地址前缀列表
// for _, ip := range prefixList {
// fmt.Println(ip)
// }
// }
//}
// 本包仅测试,无实际使用
func TestBackTrace(t *testing.T) {
BackTrace(false)
}

View File

@@ -1,9 +0,0 @@
package ntrace
import (
"github.com/oneclickvirt/nt3/nt"
)
func TraceRoute3(language, location, checkType string) {
nt.TraceRoute(language, location, checkType)
}

View File

@@ -1,9 +0,0 @@
package ntrace
import "testing"
// https://github.com/nxtrace/NTrace-core/blob/main/fast_trace/fast_trace.go
// 本包仅测试无实际使用
func TestTraceRoute(t *testing.T) {
TraceRoute3("en", "GZ", "ipv4")
}

View File

@@ -36,6 +36,8 @@ jobs:
sed -i '/^import/,/^)/{/^)/a\'$'\n''const token = "OvwKx5qgJtf7PZgCKbtyojSU.MTcwMTUxNzY1MTgwMw"'$'\n''}' utils/utils.go
sed -i '/github.com\/oneclickvirt\/security/d' go.mod
sed -i 's|var securityFlag = flag.Bool("security", true,|var securityFlag = flag.Bool("security", false,|g' goecs.go
sed -i 's|VPS融合怪测试|VPS融合怪测试(非官方编译)|g' utils/utils.go
sed -i 's|VPS Fusion Monster Test|VPS Fusion Monster Test (Unofficial)|g' utils/utils.go
go mod tidy
sed -i 's|但二进制文件编译至 \[securityCheck\].*)|但已开源|g' README.md
sed -i 's|but binary files compiled in \[securityCheck\].*)|but open sourced|g' README_EN.md
@@ -52,4 +54,4 @@ jobs:
run: |
git add .
git commit -m "Auto update public version (no security package)" || echo "No changes to commit"
git push -f origin public
git push -f origin public

View File

@@ -4,7 +4,7 @@
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Foneclickvirt%2Fecs.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Foneclickvirt%2Fecs?ref=badge_shield)
[![Hits](https://hits.spiritlhl.net/goecs.svg?action=hit&title=Hits&title_bg=%23555555&count_bg=%230eecf8&edge_flat=false)](https://hits.spiritlhl.net)
[![Hits](https://hits.spiritlhl.net/goecs.svg?action=hit&title=Hits&title_bg=%23555555&count_bg=%230eecf8&edge_flat=false)](https://hits.spiritlhl.net) [![Downloads](https://ghdownload.spiritlhl.net/oneclickvirt/ecs?color=36c600)](https://github.com/oneclickvirt/ecs/releases)
融合怪测评项目 - GO版本
@@ -47,8 +47,8 @@ Shell 版本:[https://github.com/spiritLHLS/ecs](https://github.com/spiritLHLS
|----------------|---------------------------|
| Android(arm64) | 存在权限问题未修复非安卓系统的ARM架构无问题 |
| OpenBSD/NetBSD | 部分Goalng的官方库未支持本系统(尤其是net相关项目) |
| Windows虚拟机 | 非物理机器不支持winsat测试硬件性能(硬盘和内存测试) |
| Windows物理机(非Admin下) | 无Admin权限不支持winsat测试硬件性能(硬盘和内存测试) |
| Windows虚拟机 | 无Admin权限的mbw测试性能不准确(内存测试) |
| Windows物理机(非Admin下) | 无Admin权限的mbw测试性能不准确(内存测试) |
---
## **功能**

View File

@@ -4,7 +4,7 @@
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Foneclickvirt%2Fecs.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Foneclickvirt%2Fecs?ref=badge_shield)
[![Hits](https://hits.spiritlhl.net/goecs.svg?action=hit&title=Hits&title_bg=%23555555&count_bg=%230eecf8&edge_flat=false)](https://hits.spiritlhl.net)
[![Hits](https://hits.spiritlhl.net/goecs.svg?action=hit&title=Hits&title_bg=%23555555&count_bg=%230eecf8&edge_flat=false)](https://hits.spiritlhl.net) [![Downloads](https://ghdownload.spiritlhl.net/oneclickvirt/ecs?color=36c600)](https://github.com/oneclickvirt/ecs/releases)
Fusion Monster Evaluation Project - GO Version
@@ -47,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 |
| OpenBSD/NetBSD | Some of Goalng's official libraries do not support this system (especially net-related items) |
| Windows(Virtual Machines) | Non-Physical Machines do not support winsat to test hardware performance (hard disk and memory tests) |
| Windows(Physical Machines)(not under Admin) | No Admin privileges do not support winsat to test hardware performance (hard disk and memory tests) |
| Windows(Virtual Machines) | Inaccurate mbw test performance without Admin rights (memory tests) |
| Windows(Physical Machines)(not under Admin) | Inaccurate mbw test performance without Admin rights (memory tests) |
---

View File

@@ -1,6 +1,6 @@
## 目录 / Table of Contents / 目次
[![Hits](https://hits.spiritlhl.net/goecs.svg?action=hit&title=Hits&title_bg=%23555555&count_bg=%230eecf8&edge_flat=false)](https://hits.spiritlhl.net)
[![Hits](https://hits.spiritlhl.net/goecs.svg?action=hit&title=Hits&title_bg=%23555555&count_bg=%230eecf8&edge_flat=false)](https://hits.spiritlhl.net) [![Downloads](https://ghdownload.spiritlhl.net/oneclickvirt/ecs?color=36c600)](https://github.com/oneclickvirt/ecs/releases)
## 语言 / Languages / 言語
- [中文](#中文)
@@ -77,7 +77,7 @@ VM-x/AMD-V/Hyper-V: 是当前测试宿主机是否支持嵌套虚拟化的指标
虚拟化架构: 显示宿主机来自什么虚拟化架构,一般来说推荐```Dedicated > KVM > Xen```虚拟化,其他虚拟化都会存在性能损耗,导致使用的时候存在性能共享/损耗,但这个也说不准,独立服务器才拥有完全独立的资源占用,其他虚拟化基本都会有资源共享,取决于宿主机的售卖者是否有良心,具体性能优劣还是得看后面的专项测试。
NAT类型: 显示NAT类型具体推荐```Full Cone > Restricted Cone > Port Restricted Cone > Symmetric```,测不出来会显示```Inconclusive```,一般来说不拿来做特殊用途(有关于特殊的代理实时通讯需求的)都不用关注本指标。
NAT类型: 显示NAT类型具体推荐```Full Cone > Restricted Cone > Port Restricted Cone > Symmetric```,测不出来或者非正规协议的类型会显示```Inconclusive```,一般来说只有特殊用途,比如有特殊的代理实时通讯、做FRP内穿端口等需求才需要特别关注其他一般情况下都不用关注本指标。
TCP加速方式一般是```cubic/bbr```拥塞控制协议一般来说做代理服务器用bbr可以改善网速普通用途不必关注此指标。
@@ -117,13 +117,33 @@ AMD的7950x单核满血性能得分在6500左右AMD的5950x单核满血性能
多说一句,```GeekBench```测的很多内容,实际在服务器使用过程中根本用不到,测试仅供参考。当然```Sysbench```非常不全面但它基于最基础的计算性能可以大致比较CPU的性能。
实际上CPU性能测试够用就行除非是科学计算以及视频转码一般不需要特别追求高性能CPU。
实际上CPU性能测试够用就行除非是科学计算以及视频转码一般不需要特别追求高性能CPU。如果有性能需求,那么需要关注程序本身吃的是多核还是单核,对应看多核还是单核得分。
### **内存测试**
一般来说只需要判断IO速度是否低于```10240MB/s```,如果低于这个值那么证明内存性能不佳,极大概率存在超售超卖问题。
一般来说,只需要判断 IO 速度是否低于 `10240 MB/s (≈10 GB/s)`
如果低于这个值,那么证明内存性能不佳,极大概率存在超售超卖问题。
至于超开的原因可能是开了虚拟内存(硬盘当内存用)、可能是开了ZRAM(牺牲CPU性能)、可能是开了气球驱动、可能是开了KSM内存融合原因多种多样。
至于超开的原因可能是
* 开了虚拟内存 (硬盘当内存用)
* 开了 ZRAM (牺牲 CPU 性能)
* 开了气球驱动 (Balloon Driver)
* 开了 KSM 内存融合
原因多种多样。
| 内存类型 | 典型频率 (MHz) | 单通道带宽 | 双通道带宽 |
| ---- | ------------ | ------------------------------------- | --------------------------------------- |
| DDR3 | 1333 \~ 2133 | 10 \~ 17 GB/s (≈ 10240 \~ 17408 MB/s) | 20 \~ 34 GB/s (≈ 20480 \~ 34816 MB/s) |
| DDR4 | 2133 \~ 3200 | 17 \~ 25 GB/s (≈ 17408 \~ 25600 MB/s) | 34 \~ 50 GB/s (≈ 34816 \~ 51200 MB/s) |
| DDR5 | 4800 \~ 7200 | 38 \~ 57 GB/s (≈ 38912 \~ 58368 MB/s) | 76 \~ 114 GB/s (≈ 77824 \~ 116736 MB/s) |
根据上表内容,本项目测试的粗略判断方法:
* **< 20 GB/s (20480 MB/s)** → 可能是 DDR3或 DDR4 单通道 / 低频)
* **20 \~ 40 GB/s (20480 \~ 40960 MB/s)** → 大概率 DDR4
* **≈ 50 GB/s (≈ 51200 MB/s)** → 基本就是 DDR5
### **硬盘测试**
@@ -279,7 +299,7 @@ Load: Displays system load.
Virtualization Architecture: Shows what virtualization architecture the host machine uses. Generally speaking, the recommended order is `Dedicated > KVM > Xen` virtualization. Other virtualization will have performance losses, leading to shared/degraded performance during use. However, this is not definitive. Only dedicated servers have completely independent resource usage; other virtualization methods basically all have resource sharing, depending on whether the host machine seller has a conscience. The specific performance merits still depend on the specialized tests that follow.
NAT Type: Displays NAT type. Specifically recommended in order: ```Full Cone > Restricted Cone > Port Restricted Cone > Symmetric```. When not detectable, it will show ```Inconclusive```. Generally speaking, if you're not using it for special purposes (related to special proxy and real-time communication needs), you don't need to pay attention to this metric.
NAT Type: Displays the NAT type, with the following specific recommendations: ```Full Cone > Restricted Cone > Port Restricted Cone > Symmetric``` . If the type cannot be determined or is an irregular protocol, it will display ```Inconclusive``` . Generally, this metric only requires special attention for specific purposes, such as using special proxies, real-time communication, or FRP port forwarding. In most other cases, this metric does not need to be monitored.
TCP Acceleration Method: Generally this is the ```cubic/bbr``` congestion control protocol. Generally speaking, using bbr for proxy servers can improve network speed; for ordinary purposes, you don't need to pay attention to this indicator.
@@ -317,13 +337,33 @@ For ```GeekBench``` baselines, see the [official website](https://browser.geekbe
As an additional note, many things tested by `GeekBench` are not actually used in server usage processes, so the test is for reference only. Of course, `Sysbench` is very incomplete, but it can roughly compare CPU performance based on the most basic computational performance.
In practice, CPU performance just needs to be sufficient. Unless you're doing scientific computing or video transcoding, you generally don't need to pursue high-performance CPUs.
In fact, CPU performance testing is sufficient as long as it meets basic requirements. Unless you are engaged in scientific computing or video transcoding, there is generally no need to pursue high-performance CPUs. If performance is a requirement, then you need to pay attention to whether the program itself is multi-core or single-core, and correspondingly look at the multi-core or single-core scores.
### **Memory Testing**
### **Memory Test**
Generally speaking, you only need to determine whether the IO speed is below `10240MB/s`. If it's below this value, it proves that memory performance is poor, with an extremely high probability of overselling issues.
Generally speaking, you only need to determine whether the IO speed is lower than `10240 MB/s (≈10 GB/s)`.
If it is lower than this value, then it proves that the memory performance is poor, and there is a high probability of overselling.
As for the reasons for oversubscription, it could be that virtual memory is enabled (using disk as memory), ZRAM might be enabled (sacrificing CPU performance), balloon drivers might be enabled, or KSM memory fusion might be enabled - there are various possible reasons.
The reasons for overselling may be:
* Virtual memory is enabled (using the hard drive as memory)
* ZRAM enabled (sacrificing CPU performance)
* Balloon Driver enabled
* KSM memory fusion enabled
There are various possible causes.
| Memory Type | Typical Frequency (MHz) | Single-Channel Bandwidth | Dual-Channel Bandwidth |
| ---- | ----------- - | ------------------------------------- | -------------------------------------- - |
| DDR3 | 1333 \~ 2133 | 10 \~ 17 GB/s (≈ 10240 \~ 17408 MB/s) | 20 \~ 34 GB/s (≈ 20480 \~ 34816 MB/s) |
| DDR4 | 21333200 | 1725 GB/s (≈ 1740825600 MB/s) | 3450 GB/s (≈ 3481651200 MB/s) |
| DDR5 | 48007200 | 3857 GB/s (≈ 3891258368 MB/s) | 76114 GB/s (≈ 77824116736 MB/s) |
Based on the content of the above table, the rough judgment method for this project's testing is as follows:
* **< 20 GB/s (20480 MB/s)** → May be DDR3 (or DDR4 single-channel / low-frequency)
* **2040 GB/s (2048040960 MB/s)** → Likely DDR4
* **≈ 50 GB/s (≈ 51200 MB/s)** → Essentially DDR5
### **Disk Testing**
@@ -427,7 +467,7 @@ OS: システム名とアーキテクチャを表示します
仮想化アーキテクチャ: ホストマシンがどの仮想化アーキテクチャから来ているかを表示します。一般的に ```Dedicated > KVM > Xen``` 仮想化が推奨されます。他の仮想化はパフォーマンス低下を引き起こし、使用時にパフォーマンス共有/損失が発生しますが、これも確実ではありません。専用サーバーのみが完全に独立したリソース占有を持ち、他の仮想化はほとんどリソース共有があります。これはホストマシンの販売者が良心的かどうかによって異なります。具体的なパフォーマンスの優劣は、後の専門テストを見る必要があります。
NAT種類: NAT種類を表示します。具体的には ```Full Cone > Restricted Cone > Port Restricted Cone > Symmetric``` が推奨されます。検出できない場合は ```Inconclusive``` と表示されます。一般的に特別な用途(特殊なプロキシリアルタイム通信の要件に関連する)に使用しない限り、この指標を気にする必要はありません。
NATタイプ: NATタイプを表示します。具体的な推奨順序は```Full Cone > Restricted Cone > Port Restricted Cone > Symmetric```です。測定不能または非標準プロトコルのタイプの場合は```Inconclusive```と表示されます。通常は特別な用途、例えば特別なプロキシの使用、リアルタイム通信、FRPによるポート転送などが必要な場合を除き、この指標は特に注目する必要はありません。
TCP加速方式一般的に ```cubic/bbr``` 輻輳制御プロトコルです。一般的にプロキシサーバーとして使用する場合、bbrを使用するとネットワーク速度が改善されますが、通常の用途ではこの指標に注目する必要はありません。
@@ -464,13 +504,33 @@ Sysbenchのベンチマークは[CPU Performance Ladder For Sysbench](https://sy
補足ですが、```GeekBench```がテストする多くの内容は、サーバー使用過程で実際には必要ないことが多いです。テストは参考程度にしてください。もちろん```Sysbench```は非常に包括的ではありませんが、基本的な計算性能に基づいてCPUのパフォーマンスを大まかに比較できます。
実際にはCPUパフォーマンスは十分であれば良く、科学計算やビデオエンコード以外では、特に高性能CPUを追求する必要はありません。
実際にはCPUの性能テストは十分な性能があれば十分です。科学計算や動画変換のような特殊な用途を除けば、一般的に高性能CPUを特別に追求する必要はありません。もし性能要件がある場合、プログラム自体がマルチコアかシングルコアのどちらを主に利用しているかを確認し、それに応じてマルチコアかシングルコアのスコアを比較する必要があります。
### **メモリテスト**
一般的に、IO速度が```10240MB/s```未満かどうかを判断するだけで十分です。この値を下回る場合、メモリパフォーマンスが良くなく、オーバーセリング/オーバーコミットの問題がある可能性が非常に高いです。
一般的に、IO速度が`10240 MB/s (≈10 GB/s)`未満かどうかを判断するだけで十分です。
この値を下回る場合、メモリ性能が不十分であり、ほぼ確実にオーバープロビジョニングの問題が存在します。
オーバーコミットの原因は、仮想メモリの使用ディスクをメモリとして使用、ZRAMCPUパフォーマンスを犠牲、バルーンドライバの使用、KSMメモリマージの使用など、様々な可能性があります
オーバープロビジョニングの原因としては、以下の可能性が考えられます
* 仮想メモリを有効にしている(ハードディスクをメモリとして使用)
* ZRAMを有効にしているCPU性能を犠牲にしている
* バルーンドライバーBalloon Driverを有効にしている
* KSMメモリ融合を有効にしている
原因は多岐にわたります。
| メモリタイプ | 典型的な周波数 (MHz) | シングルチャネル帯域幅 | ダブルチャネル帯域幅 |
| ---- | ----------- - | ------------------------------------- | -------------------------------------- - |
| DDR3 | 1333 \~ 2133 | 10 \~ 17 GB/s (≈ 10240 \~ 17408 MB/s) | 20 \~ 34 GB/s (≈ 20480 \~ 34816 MB/s) |
| DDR4 | 2133 3200 | 17 25 GB/s (≈ 17408 25600 MB/s) | 34 50 GB/s (≈ 34816 51200 MB/s) |
| DDR5 | 4800 7200 | 38 57 GB/s (≈ 38912 58368 MB/s) | 76 114 GB/s (≈ 77824 116736 MB/s) |
上記の表の内容に基づき、本プロジェクトのテストにおける粗略な判断方法:
* **< 20 GB/s (20480 MB/s)** → 可能是 DDR3または DDR4 シングルチャネル / 低周波数)
* **20 40 GB/s (20480 40960 MB/s)** → ほぼ確実にDDR4
* **≈ 50 GB/s (≈ 51200 MB/s)** → ほぼ確実にDDR5
### **ディスクテスト**

View File

@@ -8,36 +8,30 @@ import (
)
func DiskTest(language, testMethod, testPath string, isMultiCheck bool, autoChange bool) (realTestMethod, res string) {
if runtime.GOOS == "windows" {
if testMethod != "winsat" && testMethod != "" {
// res = "Detected host is Windows, using Winsat for testing.\n"
realTestMethod = "winsat"
}
res = disk.WinsatTest(language, isMultiCheck, testPath)
} else {
switch testMethod {
case "fio":
res = disk.FioTest(language, isMultiCheck, testPath)
if res == "" && autoChange {
// res = "Fio test failed, switching to DD for testing.\n"
res += disk.DDTest(language, isMultiCheck, testPath)
realTestMethod = "dd"
} else {
realTestMethod = "fio"
}
case "dd":
res = disk.DDTest(language, isMultiCheck, testPath)
if res == "" && autoChange {
// res = "DD test failed, switching to Fio for testing.\n"
res += disk.FioTest(language, isMultiCheck, testPath)
realTestMethod = "fio"
} else {
realTestMethod = "dd"
}
default:
// res = "Unsupported test method specified, switching to DD for testing.\n"
switch testMethod {
case "fio":
res = disk.FioTest(language, isMultiCheck, testPath)
if res == "" && autoChange {
res += disk.DDTest(language, isMultiCheck, testPath)
realTestMethod = "dd"
} else {
realTestMethod = "fio"
}
case "dd":
res = disk.DDTest(language, isMultiCheck, testPath)
if res == "" && autoChange {
res += disk.FioTest(language, isMultiCheck, testPath)
realTestMethod = "fio"
} else {
realTestMethod = "dd"
}
default:
if runtime.GOOS == "windows" {
realTestMethod = "winsat"
res = disk.WinsatTest(language, isMultiCheck, testPath)
} else {
res = disk.DDTest(language, isMultiCheck, testPath)
realTestMethod = "dd"
}
}
if !strings.Contains(res, "\n") && res != "" {

18
go.mod
View File

@@ -6,17 +6,17 @@ require (
github.com/imroc/req/v3 v3.54.0
github.com/oneclickvirt/CommonMediaTests v0.0.4-20250329123841
github.com/oneclickvirt/UnlockTests v0.0.28-20250727155204
github.com/oneclickvirt/backtrace v0.0.6-20250805091811
github.com/oneclickvirt/basics v0.0.15-20250805084236
github.com/oneclickvirt/backtrace v0.0.7-20250811023541
github.com/oneclickvirt/basics v0.0.15-20250812130523
github.com/oneclickvirt/cputest v0.0.12-20250720122317
github.com/oneclickvirt/defaultset v0.0.2-20240624082446
github.com/oneclickvirt/disktest v0.0.9-20250801101625
github.com/oneclickvirt/disktest v0.0.10-20250808140407
github.com/oneclickvirt/gostun v0.0.5-20250727155022
github.com/oneclickvirt/memorytest v0.0.9-20250720135728
github.com/oneclickvirt/nt3 v0.0.7-20250805133514
github.com/oneclickvirt/memorytest v0.0.9-20250808065154
github.com/oneclickvirt/nt3 v0.0.8-20250811123903
github.com/oneclickvirt/pingtest v0.0.8-20250728015259
github.com/oneclickvirt/portchecker v0.0.3-20250728015900
github.com/oneclickvirt/security v0.0.6-20250805090112
github.com/oneclickvirt/security v0.0.6-20250823030124
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/reflect2 v1.0.2 // indirect
github.com/nxtrace/NTrace-core v1.4.2 // indirect
github.com/oneclickvirt/dd v0.0.2-20250701085922 // indirect
github.com/oneclickvirt/fio v0.0.2-20250701085933 // indirect
github.com/oneclickvirt/mbw v0.0.1-20250630140849 // indirect
github.com/oneclickvirt/dd v0.0.2-20250808062818 // indirect
github.com/oneclickvirt/fio v0.0.2-20250808045755 // indirect
github.com/oneclickvirt/mbw v0.0.1-20250808061222 // indirect
github.com/oschwald/maxminddb-golang v1.13.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/pion/dtls/v2 v2.2.7 // indirect

36
go.sum
View File

@@ -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/UnlockTests v0.0.28-20250727155204 h1:apFaEbHGKflYMZzK17nXzEai4GG873mTd+d9hCO/KdY=
github.com/oneclickvirt/UnlockTests v0.0.28-20250727155204/go.mod h1:oOa6wj/qECtRMxwBO6D7o0L0F0Q/5sQ747OCnFQqoGE=
github.com/oneclickvirt/backtrace v0.0.6-20250805091811 h1:mKXh/SB+8Aud1TdgmekIXiRR1ZTduIwoCpvrwa5gyyo=
github.com/oneclickvirt/backtrace v0.0.6-20250805091811/go.mod h1:/+KUtOWz48TyiTTbhVTsp3D6b5WY+4pCgvFBYtUGtns=
github.com/oneclickvirt/basics v0.0.15-20250805084236 h1:guYO6wGooSIOAIutuy/zfJ4sXj525nBITw8cjEPRaK8=
github.com/oneclickvirt/basics v0.0.15-20250805084236/go.mod h1:2PV+1ge01zb0Sqzj2V2I7P0wAdFSLF1XgAiumchJJbg=
github.com/oneclickvirt/backtrace v0.0.7-20250811023541 h1:GzkzvUC6U9b6Dkz/Bl4JRPeQ7XBGoW7Qw1aWqzhF+MQ=
github.com/oneclickvirt/backtrace v0.0.7-20250811023541/go.mod h1:/+KUtOWz48TyiTTbhVTsp3D6b5WY+4pCgvFBYtUGtns=
github.com/oneclickvirt/basics v0.0.15-20250812130523 h1:nPNTVq8d9N1rdshkMAbnhZxTb7L2Yt7NlIg6rY10YRQ=
github.com/oneclickvirt/basics v0.0.15-20250812130523/go.mod h1:2PV+1ge01zb0Sqzj2V2I7P0wAdFSLF1XgAiumchJJbg=
github.com/oneclickvirt/cputest v0.0.12-20250720122317 h1:toiwAK1hZE5b8klu2mOQ7J4sv5yV9lpPKwgPahfRYBQ=
github.com/oneclickvirt/cputest v0.0.12-20250720122317/go.mod h1:vjlH8tkPFft1tlLOpeNskXVvurxkHaJ3+dgFxQGLXY4=
github.com/oneclickvirt/dd v0.0.2-20250701085922 h1:WiWZwcnCPhRc8hLZdvkjD2kOEpnqn1S31z1j0x3V4l0=
github.com/oneclickvirt/dd v0.0.2-20250701085922/go.mod h1:tImu9sPTkLWo2tf1dEN1xQzrylWKauj9hbU8PHfyAeU=
github.com/oneclickvirt/dd v0.0.2-20250808062818 h1:0KHrKkdpL5oBE1OHsrRd2siRw4/2k6f9LBaP7T4JpOc=
github.com/oneclickvirt/dd v0.0.2-20250808062818/go.mod h1:tImu9sPTkLWo2tf1dEN1xQzrylWKauj9hbU8PHfyAeU=
github.com/oneclickvirt/defaultset v0.0.2-20240624082446 h1:5Pg3mK/u/vQvSz7anu0nxzrNdELi/AcDAU1mMsmPzyc=
github.com/oneclickvirt/defaultset v0.0.2-20240624082446/go.mod h1:e9Jt4tf2sbemCtc84/XgKcHy9EZ2jkc5x2sW1NiJS+E=
github.com/oneclickvirt/disktest v0.0.9-20250801101625 h1:N8sAZrziexT/4qqVwK1hIvXrIKjAinsGdQ9ceumBxNo=
github.com/oneclickvirt/disktest v0.0.9-20250801101625/go.mod h1:6YCvGr+Z0tvcP4Ue8bezZqm/GqS/dSyEnSUhvS3Q03o=
github.com/oneclickvirt/fio v0.0.2-20250701085933 h1:4P7QcOTxbqyx5DhHdFvyeRSsdNajSo9l/H2XK0vICIc=
github.com/oneclickvirt/fio v0.0.2-20250701085933/go.mod h1:NIq+XYTey68KNERGIy/oRDlzpwLzBVoHOCiqX8didsE=
github.com/oneclickvirt/disktest v0.0.10-20250808140407 h1:oUfi5zF3htUTB1ZJuClmK0o74ufP7icbu8LYCnxEOxE=
github.com/oneclickvirt/disktest v0.0.10-20250808140407/go.mod h1:Vp3iMVBD4ccReDJz5n5SlzUdq0kDuVhpRklQk21KT+8=
github.com/oneclickvirt/fio v0.0.2-20250808045755 h1:eWihCRWcalJjPIdrF8dMe68ZiPnMkSfHC8ENvElp/xE=
github.com/oneclickvirt/fio v0.0.2-20250808045755/go.mod h1:NIq+XYTey68KNERGIy/oRDlzpwLzBVoHOCiqX8didsE=
github.com/oneclickvirt/gostun v0.0.5-20250727155022 h1:/e3gSUrOp1tg/1NTRx+P8B51OGcP26Q6//5EoSIjOvk=
github.com/oneclickvirt/gostun v0.0.5-20250727155022/go.mod h1:pfp7MFZJK9n/KTLAVqqFcCAns4xqMykmjI+1UeF/vdE=
github.com/oneclickvirt/mbw v0.0.1-20250630140849 h1:p6RMhOPBnQKAm9+VEQ2axAFsidrdSdrhXMyheIyv2a8=
github.com/oneclickvirt/mbw v0.0.1-20250630140849/go.mod h1:0Vq6NRpyLmGUdfHfL3uDcFsuZhi7KlG+OCs5ky2757Y=
github.com/oneclickvirt/memorytest v0.0.9-20250720135728 h1:RusZfaESDXK+k5YYfVXTCW5zLeQEd/dYY80a6xievE0=
github.com/oneclickvirt/memorytest v0.0.9-20250720135728/go.mod h1:7xMacjQobvFAtODht2hxTsB9hM2IFS7vZk3gxx+bsjo=
github.com/oneclickvirt/nt3 v0.0.7-20250805133514 h1:PeDFYMaqO3nH8dVNHek1HtjxBYVli1R5Rtd/5uFOSN0=
github.com/oneclickvirt/nt3 v0.0.7-20250805133514/go.mod h1:O7YkaOMFihB8hwQiD74WTbDlyoTieDwTDBR6jbkZaP0=
github.com/oneclickvirt/mbw v0.0.1-20250808061222 h1:WGXOe6QvHiDRhPVMI0VcctjzW08kGvJf50yq5YeZCtw=
github.com/oneclickvirt/mbw v0.0.1-20250808061222/go.mod h1:0Vq6NRpyLmGUdfHfL3uDcFsuZhi7KlG+OCs5ky2757Y=
github.com/oneclickvirt/memorytest v0.0.9-20250808065154 h1:mjYOvpFz2mpDU9MNjj66oIDcc2r6+zoW8veP616/+4Q=
github.com/oneclickvirt/memorytest v0.0.9-20250808065154/go.mod h1:DBxiVZX7mWCe0Fy+qu57ENheLo00sLfjKzvxiICrUtU=
github.com/oneclickvirt/nt3 v0.0.8-20250811123903 h1:ubSPLh/DSrXj+tOgmRABgi2vrVmbmjjSne+NrVFNmNc=
github.com/oneclickvirt/nt3 v0.0.8-20250811123903/go.mod h1:F1v+6xInBKnbUa8gV1M40R1HOzxg+obtduNhx3CTnmA=
github.com/oneclickvirt/pingtest v0.0.8-20250728015259 h1:egoxZRZBOWN3JqBwqEsULDyRo2/dpGMeWcmV3U87zig=
github.com/oneclickvirt/pingtest v0.0.8-20250728015259/go.mod h1:gxwsxxwitNQiGq2OI0ZogYoOLwc8DtuOdSRe6/EvRqs=
github.com/oneclickvirt/portchecker v0.0.3-20250728015900 h1:AomzdppSOFB70AJESQhlp0IPbsHTTJGimAWDk2TzCWM=
github.com/oneclickvirt/portchecker v0.0.3-20250728015900/go.mod h1:9sjMDPCd4Z40wkYB0S9gQPGH8YPtnNE1ZJthVIuHUzA=
github.com/oneclickvirt/security v0.0.6-20250805090112 h1:lUNtsnpZ3JNLS4xxjFGGECaxA46yNyxbYjdust9W0M4=
github.com/oneclickvirt/security v0.0.6-20250805090112/go.mod h1:JB6SJWm5pbrngCgSTYLd2m4Hj8mHO6mJua1WgHMZOcE=
github.com/oneclickvirt/security v0.0.6-20250823030124 h1:3RjpJNfKV7anN6GJs0ky2BfXFHPUVrDxUomEqoB0x7I=
github.com/oneclickvirt/security v0.0.6-20250823030124/go.mod h1:RSMooIlb4H/kLrGWNvUyOgdzQKgYKVv+LzWGlsPsLW4=
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/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE=

179
goecs.go
View File

@@ -24,6 +24,7 @@ import (
"github.com/oneclickvirt/ecs/cputest"
"github.com/oneclickvirt/ecs/disktest"
"github.com/oneclickvirt/ecs/memorytest"
"github.com/oneclickvirt/ecs/nexttrace"
"github.com/oneclickvirt/ecs/speedtest"
"github.com/oneclickvirt/ecs/unlocktest"
"github.com/oneclickvirt/ecs/upstreams"
@@ -31,7 +32,6 @@ import (
gostunmodel "github.com/oneclickvirt/gostun/model"
memorytestmodel "github.com/oneclickvirt/memorytest/memory"
nt3model "github.com/oneclickvirt/nt3/model"
"github.com/oneclickvirt/nt3/nt"
ptmodel "github.com/oneclickvirt/pingtest/model"
"github.com/oneclickvirt/pingtest/pt"
"github.com/oneclickvirt/portchecker/email"
@@ -39,7 +39,7 @@ import (
)
var (
ecsVersion = "v0.1.74"
ecsVersion = "v0.1.85"
menuMode bool
onlyChinaTest bool
input, choice string
@@ -59,10 +59,9 @@ var (
autoChangeDiskTestMethod = true
filePath = "goecs.txt"
enabelUpload = true
help bool
onlyIpInfoCheckStatus, help bool
goecsFlag = flag.NewFlagSet("goecs", flag.ContinueOnError)
finish bool
IPV4, IPV6 string
)
func getMenuChoice(language string) string {
@@ -100,7 +99,7 @@ func getMenuChoice(language string) string {
if re.MatchString(input) {
inChoice := input
switch inChoice {
case "1", "2", "3", "4", "5", "6", "7", "8", "9", "10":
case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10":
return inChoice
default:
if language == "zh" {
@@ -186,11 +185,13 @@ func handleMenuMode(preCheck utils.NetCheckResult) {
commTestStatus, utTestStatus, securityTestStatus, emailTestStatus = false, false, false, false
backtraceStatus, nt3Status, speedTestStatus = false, false, false
autoChangeDiskTestMethod = true
printMenuOptions()
printMenuOptions(preCheck)
Loop:
for {
choice = getMenuChoice(language)
switch choice {
case "0":
os.Exit(0)
case "1":
setFullTestStatus(preCheck)
onlyChinaTest = utils.CheckChina(enableLogger)
@@ -245,44 +246,62 @@ Loop:
}
}
func printMenuOptions() {
func printMenuOptions(preCheck utils.NetCheckResult) {
var stats *utils.StatsResponse
var statsErr error
var githubInfo *utils.GitHubRelease
var githubErr error
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()
var statsInfo string
if statsErr != nil {
statsInfo = "NULL"
// 只有在网络连接正常时才获取统计信息和版本信息
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 {
statsInfo = fmt.Sprintf("总使用量: %s | 今日使用: %s",
utils.FormatGoecsNumber(stats.Total),
utils.FormatGoecsNumber(stats.Daily))
statsErr = fmt.Errorf("network not connected")
githubErr = fmt.Errorf("network not connected")
}
var statsInfo string
var cmp int
if githubErr == nil {
cmp = utils.CompareVersions(ecsVersion, githubInfo.TagName)
} else {
cmp = 0
if preCheck.Connected {
// 网络连接正常时处理统计信息和版本比较
if statsErr != nil {
statsInfo = "NULL"
} else {
switch language {
case "zh":
statsInfo = fmt.Sprintf("总使用量: %s | 今日使用: %s",
utils.FormatGoecsNumber(stats.Total),
utils.FormatGoecsNumber(stats.Daily))
case "en":
statsInfo = fmt.Sprintf("Total Usage: %s | Daily Usage: %s",
utils.FormatGoecsNumber(stats.Total),
utils.FormatGoecsNumber(stats.Daily))
}
}
if githubErr == nil {
cmp = utils.CompareVersions(ecsVersion, githubInfo.TagName)
} else {
cmp = 0
}
}
switch language {
case "zh":
fmt.Printf("VPS融合怪版本: %s\n", ecsVersion)
switch cmp {
case -1:
fmt.Printf("检测到新版本 %s 如有必要请更新!\n", githubInfo.TagName)
if preCheck.Connected {
switch cmp {
case -1:
fmt.Printf("检测到新版本 %s 如有必要请更新!\n", githubInfo.TagName)
}
fmt.Printf("使用统计: %s\n", statsInfo)
}
fmt.Printf("使用统计: %s\n", statsInfo)
fmt.Println("1. 融合怪完全体(能测全测)")
fmt.Println("2. 极简版(系统信息+CPU+内存+磁盘+测速节点5个)")
fmt.Println("3. 精简版(系统信息+CPU+内存+磁盘+常用流媒体+路由+测速节点5个)")
@@ -291,18 +310,19 @@ func printMenuOptions() {
fmt.Println("6. 网络单项(IP质量检测+上游及三网回程+广州三网回程详细路由+全国延迟+测速节点11个)")
fmt.Println("7. 解锁单项(御三家解锁+常用流媒体解锁)")
fmt.Println("8. 硬件单项(系统信息+CPU+dd磁盘测试+fio磁盘测试)")
fmt.Println("9. IP质量检测(15个数据库的IP检测+邮件端口检测)")
fmt.Println("9. IP质量检测(15个数据库的IP质量检测+邮件端口检测)")
fmt.Println("10. 三网回程线路检测+三网回程详细路由(北京上海广州成都)+三网延迟测试(全国)")
fmt.Println("0. 退出程序")
case "en":
fmt.Printf("VPS Fusion Monster Test Version: %s\n", ecsVersion)
switch cmp {
case -1:
fmt.Printf("New version detected %s update if necessary!\n", githubInfo.TagName)
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.Printf("Total Usage: %s | Daily Usage: %s\n",
utils.FormatGoecsNumber(stats.Total),
utils.FormatGoecsNumber(stats.Daily))
fmt.Println("1. VPS Fusion Monster Test Comprehensive Test Suite")
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)")
@@ -311,6 +331,7 @@ func printMenuOptions() {
fmt.Println("7. Unlock-Only Test (Basic Unlock Tests + Common Streaming Services Unlock)")
fmt.Println("8. Hardware-Only Test (System Info + CPU + Memory + dd Disk Test + fio Disk Test)")
fmt.Println("9. IP Quality Test (IP Test with 15 Databases + Email Port Test)")
fmt.Println("0. Exit Program")
}
}
@@ -377,6 +398,7 @@ func setUnlockFocusedTestStatus(preCheck utils.NetCheckResult) {
}
func setNetworkOnlyTestStatus() {
onlyIpInfoCheckStatus = true
securityTestStatus = true
speedTestStatus = true
backtraceStatus = true
@@ -385,9 +407,9 @@ func setNetworkOnlyTestStatus() {
}
func setUnlockOnlyTestStatus() {
onlyIpInfoCheckStatus = true
commTestStatus = true
utTestStatus = true
enabelUpload = false
}
func setHardwareOnlyTestStatus(preCheck utils.NetCheckResult) {
@@ -401,15 +423,16 @@ func setHardwareOnlyTestStatus(preCheck utils.NetCheckResult) {
}
func setIPQualityTestStatus() {
onlyIpInfoCheckStatus = true
securityTestStatus = true
emailTestStatus = true
}
func setRouteTestStatus() {
onlyIpInfoCheckStatus = true
backtraceStatus = true
nt3Status = true
pingTestStatus = true
enabelUpload = false
}
func printInvalidChoice() {
@@ -430,7 +453,7 @@ func handleLanguageSpecificSettings() {
}
}
func handleSignalInterrupt(sig chan os.Signal, startTime *time.Time, output *string, tempOutput string, uploadDone chan bool, outputMutex *sync.Mutex) {
func handleSignalInterrupt(sig chan os.Signal, startTime *time.Time, output *string, _ string, uploadDone chan bool, outputMutex *sync.Mutex) {
select {
case <-sig:
if !finish {
@@ -511,11 +534,14 @@ func runChineseTests(preCheck utils.NetCheckResult, wg1, wg2, wg3 *sync.WaitGrou
*output = runCPUTest(*output, tempOutput, outputMutex)
*output = runMemoryTest(*output, tempOutput, outputMutex)
*output = runDiskTest(*output, tempOutput, outputMutex)
if (onlyChinaTest || pingTestStatus) && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" {
wg3.Add(1)
if onlyIpInfoCheckStatus && !basicStatus && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" {
*output = runIpInfoCheck(*output, tempOutput, outputMutex)
}
if utTestStatus && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" && !onlyChinaTest {
wg1.Add(1)
go func() {
defer wg3.Done()
*ptInfo = pt.PingTest()
defer wg1.Done()
*mediaInfo = unlocktest.MediaTest(language)
}()
}
if emailTestStatus && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" {
@@ -525,11 +551,11 @@ func runChineseTests(preCheck utils.NetCheckResult, wg1, wg2, wg3 *sync.WaitGrou
*emailInfo = email.EmailCheck()
}()
}
if utTestStatus && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" && !onlyChinaTest {
wg1.Add(1)
if (onlyChinaTest || pingTestStatus) && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" {
wg3.Add(1)
go func() {
defer wg1.Done()
*mediaInfo = unlocktest.MediaTest(language)
defer wg3.Done()
*ptInfo = pt.PingTest()
}()
}
if preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" {
@@ -551,6 +577,9 @@ func runEnglishTests(preCheck utils.NetCheckResult, wg1, wg2 *sync.WaitGroup, ba
*output = runCPUTest(*output, tempOutput, outputMutex)
*output = runMemoryTest(*output, tempOutput, outputMutex)
*output = runDiskTest(*output, tempOutput, outputMutex)
if onlyIpInfoCheckStatus && !basicStatus && preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" {
*output = runIpInfoCheck(*output, tempOutput, outputMutex)
}
if preCheck.Connected && preCheck.StackType != "" && preCheck.StackType != "None" {
if utTestStatus {
wg1.Add(1)
@@ -574,6 +603,24 @@ func runEnglishTests(preCheck utils.NetCheckResult, wg1, wg2 *sync.WaitGroup, ba
*output = appendTimeInfo(*output, tempOutput, startTime, outputMutex)
}
// runIpInfoCheck 系统和网络基础信息检测不进行测试的时候该函数检测取得本机IP信息并显示(单项测试中输出)
func runIpInfoCheck(output, tempOutput string, outputMutex *sync.Mutex) string {
outputMutex.Lock()
defer outputMutex.Unlock()
return utils.PrintAndCapture(func() {
var ipinfo string
upstreams.IPV4, upstreams.IPV6, ipinfo = utils.OnlyBasicsIpInfo(language)
if ipinfo != "" {
if language == "zh" {
utils.PrintCenteredTitle("IP信息", width)
} else {
utils.PrintCenteredTitle("IP-Information", width)
}
fmt.Printf("%s", ipinfo)
}
}, tempOutput, output)
}
func runBasicTests(preCheck utils.NetCheckResult, basicInfo, securityInfo *string, output, tempOutput string, outputMutex *sync.Mutex) string {
outputMutex.Lock()
defer outputMutex.Unlock()
@@ -588,13 +635,13 @@ func runBasicTests(preCheck utils.NetCheckResult, basicInfo, securityInfo *strin
}
}
if preCheck.Connected && preCheck.StackType == "DualStack" {
IPV4, IPV6, *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" {
IPV4, IPV6, *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" {
IPV4, IPV6, *basicInfo, *securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, "ipv6", securityTestStatus)
upstreams.IPV4, upstreams.IPV6, *basicInfo, *securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, "ipv6", securityTestStatus)
} else {
IPV4, IPV6, *basicInfo, *securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, "", false)
upstreams.IPV4, upstreams.IPV6, *basicInfo, *securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, "", false)
securityTestStatus = false
}
if basicStatus {
@@ -732,20 +779,16 @@ func runEmailTests(wg2 *sync.WaitGroup, emailInfo *string, output, tempOutput st
func runNetworkTests(wg3 *sync.WaitGroup, ptInfo *string, output, tempOutput string, outputMutex *sync.Mutex) string {
outputMutex.Lock()
defer outputMutex.Unlock()
output = utils.PrintAndCapture(func() {
return utils.PrintAndCapture(func() {
if backtraceStatus && !onlyChinaTest {
utils.PrintCenteredTitle("上游及回程线路检测", width)
upstreams.UpstreamsCheck(IPV4)
upstreams.UpstreamsCheck() // 不能在重定向的同时外部并发,此处仅可以顺序执行
}
}, tempOutput, output)
output = utils.PrintAndCapture(func() {
if nt3Status && !onlyChinaTest {
utils.PrintCenteredTitle("三网回程路由检测", width)
nt.TraceRoute(language, nt3Location, nt3CheckType)
nexttrace.NextTrace3Check(language, nt3Location, nt3CheckType) // 不能在重定向的同时外部并发,此处仅可以顺序执行
}
}, tempOutput, output)
return utils.PrintAndCapture(func() {
if onlyChinaTest || pingTestStatus {
if (onlyChinaTest || pingTestStatus) && *ptInfo != "" {
wg3.Wait()
utils.PrintCenteredTitle("三网ICMP的PING值检测", width)
fmt.Println(*ptInfo)
@@ -826,12 +869,16 @@ func main() {
return
}
initLogger()
go func() {
http.Get("https://hits.spiritlhl.net/goecs.svg?action=hit&title=Hits&title_bg=%23555555&count_bg=%230eecf8&edge_flat=false")
}()
preCheck := utils.CheckPublicAccess(3 * time.Second)
go func() {
if preCheck.Connected {
http.Get("https://hits.spiritlhl.net/goecs.svg?action=hit&title=Hits&title_bg=%23555555&count_bg=%230eecf8&edge_flat=false")
}
}()
if menuMode {
handleMenuMode(preCheck)
} else {
onlyIpInfoCheckStatus = true
}
handleLanguageSpecificSettings()
if !preCheck.Connected {

102
goecs.sh
View File

@@ -1,21 +1,24 @@
#!/bin/bash
# From https://github.com/oneclickvirt/ecs
# 2025.06.29
# 2025.08.23
# curl -L https://raw.githubusercontent.com/oneclickvirt/ecs/master/goecs.sh -o goecs.sh && chmod +x goecs.sh
# 或
# curl -L https://cnb.cool/oneclickvirt/ecs/-/git/raw/main/goecs.sh -o goecs.sh && chmod +x goecs.sh
CYAN='\033[96m'
BOLD='\033[1m'
RESET='\033[0m'
echo -e "${CYAN}${BOLD}"
cat <<"EOF"
,ad8888ba, ,ad8888ba, 88888888888 ,ad8888ba, ad88888ba
d8"' `"8b d8"' `"8b 88 d8"' `"8b d8" "8b
d8' d8' `8b 88 d8' Y8a
88 88 88 88aaaaa 88 `"Y8aaaaa,
88 88888 88 88 88""""" 88 `"""""8b,
Y8, 88 Y8, ,8P 88 Y8, `8b
Y8a. .a88 Y8a. .a8P 88 Y8a. .a8P Y8a a8P
`"Y88888P" `"Y8888Y"' 88888888888 `"Y8888Y"' "Y88888P"
██████╗ ██████╗ ███████╗ ██████╗███████╗
██╔════╝ ██╔═══██╗██╔════╝██╔════╝██╔════╝
██║ ███╗██║ ██║█████╗ ██║ ███████╗
██║ ██║██║ ██║██╔══╝ ██║ ██║
╚██████╔╝╚██████╔╝███████╗╚██████╗███████║
╚═════╝ ╚═════╝ ╚══════╝ ╚═════╝╚══════╝
EOF
echo -e "${RESET}"
cd /root >/dev/null 2>&1
if [ ! -d "/usr/bin/" ]; then
mkdir -p "/usr/bin/"
@@ -63,7 +66,6 @@ download_file() {
check_china() {
_yellow "正在检测IP所在区域......"
if [[ -z "${CN}" ]]; then
# 首先尝试通过 ipapi.co 检测
if curl -m 6 -s https://ipapi.co/json | grep -q 'China'; then
_yellow "根据ipapi.co提供的信息当前IP可能在中国"
if [ "$noninteractive" != "true" ]; then
@@ -143,7 +145,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.73"
ECS_VERSION="0.1.83"
for api in \
"https://api.github.com/repos/oneclickvirt/ecs/releases/latest" \
"https://githubapi.spiritlhl.workers.dev/repos/oneclickvirt/ecs/releases/latest" \
@@ -155,8 +157,8 @@ goecs_check() {
sleep 1
done
if [ -z "$ECS_VERSION" ]; then
_yellow "Unable to get version info, using default version 0.1.73"
ECS_VERSION="0.1.73"
_yellow "Unable to get version info, using default version 0.1.83"
ECS_VERSION="0.1.83"
fi
version_output=""
for cmd_path in "goecs" "./goecs" "/usr/bin/goecs" "/usr/local/bin/goecs"; do
@@ -367,68 +369,6 @@ InstallSysbench() {
fi
}
Check_SysBench() {
if [ ! -f "/usr/bin/sysbench" ] && [ ! -f "/usr/local/bin/sysbench" ]; then
InstallSysbench
fi
# 尝试编译安装
if [ ! -f "/usr/bin/sysbench" ] && [ ! -f "/usr/local/bin/sysbench" ]; then
echo -e "${Msg_Warning}Sysbench Module install Failure, trying compile modules ..."
Check_Sysbench_InstantBuild
fi
source ~/.bashrc
# 最终检测
if [ "$(command -v sysbench)" ] || [ -f "/usr/bin/sysbench" ] || [ -f "/usr/local/bin/sysbench" ]; then
_yellow "Install sysbench successfully!"
else
_red "SysBench Moudle install Failure! Try Restart Bench or Manually install it! (/usr/bin/sysbench)"
_blue "Will try to test with geekbench5 instead later."
fi
sleep 3
}
Check_Sysbench_InstantBuild() {
if [ "${Var_OSRelease}" = "centos" ] || [ "${Var_OSRelease}" = "rhel" ] || [ "${Var_OSRelease}" = "almalinux" ] || [ "${Var_OSRelease}" = "ubuntu" ] || [ "${Var_OSRelease}" = "debian" ] || [ "${Var_OSRelease}" = "fedora" ] || [ "${Var_OSRelease}" = "arch" ] || [ "${Var_OSRelease}" = "astra" ]; then
local os_sysbench=${Var_OSRelease}
if [ "$os_sysbench" = "astra" ]; then
os_sysbench="debian"
fi
if [ "$os_sysbench" = "opencloudos" ]; then
os_sysbench="centos"
fi
echo -e "${Msg_Info}Release Detected: ${os_sysbench}"
echo -e "${Msg_Info}Preparing compile enviorment ..."
prepare_compile_env "${os_sysbench}"
echo -e "${Msg_Info}Downloading Source code (Version 1.0.20)..."
mkdir -p /tmp/sysbench_install/src/
mv /tmp/sysbench-1.0.20 /tmp/sysbench_install/src/
echo -e "${Msg_Info}Compiling Sysbench Module ..."
cd /tmp/sysbench_install/src/sysbench-1.0.20
./autogen.sh && ./configure --without-mysql && make -j8 && make install
echo -e "${Msg_Info}Cleaning up ..."
cd /tmp && rm -rf /tmp/sysbench_install/src/sysbench*
else
echo -e "${Msg_Warning}Unsupported operating system: ${Var_OSRelease}"
fi
}
prepare_compile_env() {
local system="$1"
if [ "${system}" = "centos" ] || [ "${system}" = "rhel" ] || [ "${system}" = "almalinux" ]; then
yum install -y epel-release
yum install -y wget curl make gcc gcc-c++ make automake libtool pkgconfig libaio-devel
elif [ "${system}" = "ubuntu" ] || [ "${system}" = "debian" ]; then
! apt-get update && apt-get --fix-broken install -y && apt-get update
! apt-get -y install --no-install-recommends curl wget make automake libtool pkg-config libaio-dev unzip && apt-get --fix-broken install -y && apt-get -y install --no-install-recommends curl wget make automake libtool pkg-config libaio-dev unzip
elif [ "${system}" = "fedora" ]; then
dnf install -y wget curl gcc gcc-c++ make automake libtool pkgconfig libaio-devel
elif [ "${system}" = "arch" ]; then
pacman -S --needed --noconfirm wget curl gcc gcc make automake libtool pkgconfig libaio lib32-libaio
else
echo -e "${Msg_Warning}Unsupported operating system: ${system}"
fi
}
env_check() {
REGEX=("debian|astra" "ubuntu" "centos|red hat|kernel|oracle linux|alma|rocky" "'amazon linux'" "fedora" "arch" "freebsd" "alpine" "openbsd" "opencloudos")
RELEASE=("Debian" "Ubuntu" "CentOS" "CentOS" "Fedora" "Arch" "FreeBSD" "Alpine" "OpenBSD" "OpenCloudOS")
@@ -540,14 +480,8 @@ env_check() {
_green "Installing sysbench"
${INSTALL_CMD} sysbench
if [ $? -ne 0 ]; then
echo "Unable to download sysbench through package manager, attempting compilation..."
wget -O /tmp/sysbench.zip "${cdn_success_url}https://github.com/akopytov/sysbench/archive/1.0.20.zip" || curl -Lk -o /tmp/sysbench.zip "${cdn_success_url}https://github.com/akopytov/sysbench/archive/1.0.20.zip"
if [ ! -f /tmp/sysbench.zip ]; then
wget -q -O /tmp/sysbench.zip "https://hub.fgit.cf/akopytov/sysbench/archive/1.0.20.zip"
fi
chmod +x /tmp/sysbench.zip
unzip /tmp/sysbench.zip -d /tmp
Check_SysBench
_red "Unable to install sysbench through package manager"
_yellow "Sysbench installation skipped"
fi
fi
if ! command -v geekbench >/dev/null 2>&1; then
@@ -663,4 +597,4 @@ case "$1" in
echo
show_help
;;
esac
esac

View File

@@ -10,7 +10,6 @@ import (
func MemoryTest(language, testMethod string) (realTestMethod, res string) {
if runtime.GOOS == "windows" {
if testMethod != "winsat" && testMethod != "" {
// res = "Detected host is Windows, using Winsat for testing.\n"
realTestMethod = "winsat"
}
res += memory.WinsatTest(language)
@@ -19,7 +18,6 @@ func MemoryTest(language, testMethod string) (realTestMethod, res string) {
case "sysbench":
res = memory.SysBenchTest(language)
if res == "" {
// res = "sysbench test failed, switch to use dd test.\n"
res += memory.DDTest(language)
realTestMethod = "dd"
} else {
@@ -29,7 +27,6 @@ func MemoryTest(language, testMethod string) (realTestMethod, res string) {
res = memory.DDTest(language)
realTestMethod = "dd"
default:
// res = "Unsupported test method, switch to use dd test.\n"
res += memory.DDTest(language)
realTestMethod = "dd"
}

44
nexttrace/nexttrace.go Normal file
View 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)
}
}
}
}

View 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)
}

View File

@@ -6,5 +6,5 @@ import (
)
func Test(t *testing.T) {
fmt.Print("%s", MediaTest("zh"))
fmt.Printf("%s", MediaTest("zh"))
}

View File

@@ -2,17 +2,65 @@ 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"
)
func UpstreamsCheck(ip string) {
if ip != "" {
if result, err := bgptools.GetPoPInfo(ip); err == nil {
fmt.Print(result.Result)
}
}
backtrace.BackTrace(uts.IPV6)
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("同一目标地址多个线路时,检测可能已越过汇聚层,除第一个线路外,后续信息可能无效"))
}

View File

@@ -3,5 +3,6 @@ package upstreams
import "testing"
func TestUpstreamsCheck(t *testing.T) {
UpstreamsCheck("148.100.85.25")
IPV4 = "148.100.85.25"
UpstreamsCheck()
}

View File

@@ -19,6 +19,7 @@ import (
"github.com/imroc/req/v3"
"github.com/oneclickvirt/UnlockTests/uts"
bnetwork "github.com/oneclickvirt/basics/network"
"github.com/oneclickvirt/basics/system"
butils "github.com/oneclickvirt/basics/utils"
. "github.com/oneclickvirt/defaultset"
@@ -115,18 +116,38 @@ func CheckChina(enableLogger bool) bool {
return selectChina
}
// OnlyBasicsIpInfo 仅检查和输出IP信息
func OnlyBasicsIpInfo(language string) (string, string, string) {
ipv4, ipv6, ipInfo, _, err := bnetwork.NetworkCheck("both", false, language)
if err != nil {
return "", "", ""
}
basicInfo := ipInfo
if strings.Contains(ipInfo, "IPV4") && strings.Contains(ipInfo, "IPV6") && ipv4 != "" && ipv6 != "" {
uts.IPV4 = true
uts.IPV6 = true
} else if strings.Contains(ipInfo, "IPV4") && ipv4 != "" {
uts.IPV4 = true
uts.IPV6 = false
} else if strings.Contains(ipInfo, "IPV6") && ipv6 != "" {
uts.IPV6 = true
uts.IPV4 = false
}
basicInfo = strings.ReplaceAll(basicInfo, "\n\n", "\n")
return ipv4, ipv6, basicInfo
}
// BasicsAndSecurityCheck 执行安全检查
func BasicsAndSecurityCheck(language, nt3CheckType string, securityCheckStatus bool) (string, string, string, string, string) {
var wgt sync.WaitGroup
var ipv4, ipv6, ipInfo, securityInfo, systemInfo string
var err error
wgt.Add(1)
go func() {
defer wgt.Done()
ipv4, ipv6, ipInfo, securityInfo, err = network.NetworkCheck("both", securityCheckStatus, language)
if err != nil {
fmt.Println(err.Error())
}
ipv4, ipv6, ipInfo, securityInfo, _ = network.NetworkCheck("both", securityCheckStatus, language)
// if err != nil {
// fmt.Println(err.Error())
// }
}()
wgt.Add(1)
go func() {

View File

@@ -20,7 +20,7 @@ func TestBasicsAndSecurityCheck(t *testing.T) {
timeout := 3 * time.Second
result := CheckPublicAccess(timeout)
if result.Connected {
fmt.Print("✅ 本机有公网连接,类型: %s\n", result.StackType)
fmt.Printf("✅ 本机有公网连接,类型: %s\n", result.StackType)
} else {
fmt.Println("❌ 本机未检测到公网连接")
}