mirror of
https://github.com/oneclickvirt/ecs.git
synced 2025-09-27 11:42:23 +08:00
Compare commits
297 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c3aa62753b | ||
![]() |
83b8efd7ee | ||
![]() |
2fa0270e4e | ||
![]() |
3bd1136683 | ||
![]() |
d5837ed535 | ||
![]() |
080c62cd93 | ||
![]() |
ce690aab2d | ||
![]() |
05ec4d75b8 | ||
![]() |
553e0ddef6 | ||
![]() |
819d155fd5 | ||
![]() |
d7519801b0 | ||
![]() |
d6302be4ae | ||
![]() |
a8366005dc | ||
![]() |
4e3249b590 | ||
![]() |
8a52f6df76 | ||
![]() |
ebe85216bb | ||
![]() |
7909d4ba78 | ||
![]() |
4939d155d8 | ||
![]() |
d69f85d0db | ||
![]() |
f4dea6ce6e | ||
![]() |
bc596e8e48 | ||
![]() |
116ae33505 | ||
![]() |
a32846638b | ||
![]() |
d84fb21f82 | ||
![]() |
f199336cf0 | ||
![]() |
a1196ab8d2 | ||
![]() |
9431fe3944 | ||
![]() |
5dcef9f4c3 | ||
![]() |
865ca62f06 | ||
![]() |
eea78a7c30 | ||
![]() |
2f5feace7b | ||
![]() |
615ffca90f | ||
![]() |
685fe735f6 | ||
![]() |
5545990854 | ||
![]() |
91d1aa4461 | ||
![]() |
94f9576383 | ||
![]() |
ef91a61d22 | ||
![]() |
bafd77e2f5 | ||
![]() |
eb03d50cd2 | ||
![]() |
dbd921d8ca | ||
![]() |
8b9df2c385 | ||
![]() |
ce57c141a0 | ||
![]() |
da3dc7e11e | ||
![]() |
d4cbd0772a | ||
![]() |
2ff558ae7b | ||
![]() |
f5d9752e89 | ||
![]() |
1f563c823a | ||
![]() |
807141751a | ||
![]() |
e55a18b3de | ||
![]() |
920054c844 | ||
![]() |
3c5405dd07 | ||
![]() |
a33702f164 | ||
![]() |
daf07945dc | ||
![]() |
88b39c0ae3 | ||
![]() |
65ddb32d74 | ||
![]() |
acf2f0e98c | ||
![]() |
e63dc4d3f4 | ||
![]() |
7fb4e358e8 | ||
![]() |
15ba7fb00f | ||
![]() |
916f21a72f | ||
![]() |
f00d5db69c | ||
![]() |
6dbb171d3b | ||
![]() |
0921aef041 | ||
![]() |
dd4a4e317b | ||
![]() |
d80f3451ff | ||
![]() |
ebce9e493d | ||
![]() |
176899d3e9 | ||
![]() |
e58da9e921 | ||
![]() |
651bbb94d0 | ||
![]() |
91ffbfa417 | ||
![]() |
84b0303468 | ||
![]() |
f3e10a999b | ||
![]() |
76a6e09d97 | ||
![]() |
9c9dbc6200 | ||
![]() |
20c8063e5e | ||
![]() |
fbe5eb8e58 | ||
![]() |
290f0d8d8c | ||
![]() |
140347c2a6 | ||
![]() |
aeda7a6e88 | ||
![]() |
a205ca38be | ||
![]() |
43bf9c81ed | ||
![]() |
d47f8987a7 | ||
![]() |
ffbe5a539a | ||
![]() |
4b8ae06df8 | ||
![]() |
859e783241 | ||
![]() |
3cd912219e | ||
![]() |
a85a06b440 | ||
![]() |
681da08f01 | ||
![]() |
bdd00d46f8 | ||
![]() |
1f213bb788 | ||
![]() |
1dec7c323b | ||
![]() |
391cc351c4 | ||
![]() |
282a947156 | ||
![]() |
73916d324a | ||
![]() |
6cce2a7e8e | ||
![]() |
2a653930a8 | ||
![]() |
2295035706 | ||
![]() |
3e8c7112a0 | ||
![]() |
a8175219d5 | ||
![]() |
a827583b76 | ||
![]() |
82a1d19c6c | ||
![]() |
4ef0ac8d5a | ||
![]() |
3bb70191e7 | ||
![]() |
1bca0052c5 | ||
![]() |
7c06d278e0 | ||
![]() |
5cec395f3c | ||
![]() |
4994994d4f | ||
![]() |
91ad962b13 | ||
![]() |
8356d95566 | ||
![]() |
1428087818 | ||
![]() |
7b1e78fb7e | ||
![]() |
0a62c62dd8 | ||
![]() |
34b4f66289 | ||
![]() |
eca268048f | ||
![]() |
c3ffe741ad | ||
![]() |
9de837ef71 | ||
![]() |
2c3da79871 | ||
![]() |
e7ad87ecbd | ||
![]() |
a89a79c11c | ||
![]() |
ee38b65a5a | ||
![]() |
0a756f04ca | ||
![]() |
f040ffb1d4 | ||
![]() |
efb870a9de | ||
![]() |
9151cd3b70 | ||
![]() |
ef8e2789e2 | ||
![]() |
2dad691bd6 | ||
![]() |
a9c5ed359a | ||
![]() |
e3c88308c9 | ||
![]() |
617c6c2f98 | ||
![]() |
d42d6999a2 | ||
![]() |
4c0f54181c | ||
![]() |
f2828970f5 | ||
![]() |
7d84d55823 | ||
![]() |
daad5158d4 | ||
![]() |
859eea7b69 | ||
![]() |
50b172d274 | ||
![]() |
1534cc19b0 | ||
![]() |
f0e5af9dcd | ||
![]() |
900083ad25 | ||
![]() |
5784e9b76f | ||
![]() |
a79e908f40 | ||
![]() |
53c25a6230 | ||
![]() |
aa76fe134c | ||
![]() |
a1491585d6 | ||
![]() |
b5fce2e16b | ||
![]() |
ac1da2af0a | ||
![]() |
6ff440a9e9 | ||
![]() |
1a3049e49d | ||
![]() |
b463cd3085 | ||
![]() |
bf16dfa387 | ||
![]() |
e00415960f | ||
![]() |
f0ed7c5b1c | ||
![]() |
e6500a23ee | ||
![]() |
b1d0611f6b | ||
![]() |
b78cf8a1ac | ||
![]() |
34065b0161 | ||
![]() |
f2e4ca6a0b | ||
![]() |
a8c76a2ee2 | ||
![]() |
d6319e5a02 | ||
![]() |
2213e52335 | ||
![]() |
0f5b11cc5f | ||
![]() |
36fda2e287 | ||
![]() |
7dfece6e29 | ||
![]() |
ffb9bfdf7f | ||
![]() |
17e96a94fe | ||
![]() |
b16b22c117 | ||
![]() |
9a6879207f | ||
![]() |
8e66e5c801 | ||
![]() |
47d84ac3dd | ||
![]() |
073a894e26 | ||
![]() |
7a92e6688e | ||
![]() |
971a2c66c7 | ||
![]() |
b4e9e17925 | ||
![]() |
5de0e9734e | ||
![]() |
465c6031f8 | ||
![]() |
a421e12435 | ||
![]() |
766f978e3e | ||
![]() |
ae9d74c17c | ||
![]() |
958c0c4153 | ||
![]() |
9924bb1e72 | ||
![]() |
a6d28bd72a | ||
![]() |
955b887039 | ||
![]() |
ac3839a8eb | ||
![]() |
4d2c89dc96 | ||
![]() |
e773e4d0fd | ||
![]() |
d0814ee1da | ||
![]() |
c31c978fc8 | ||
![]() |
040a3db6e2 | ||
![]() |
cd68643df8 | ||
![]() |
5ad59dcd36 | ||
![]() |
476ae5d25f | ||
![]() |
369ae42139 | ||
![]() |
676973d946 | ||
![]() |
3ce8b69065 | ||
![]() |
d752a2fb7f | ||
![]() |
95fba10d0f | ||
![]() |
acebe04732 | ||
![]() |
226f751655 | ||
![]() |
18a0de4c4e | ||
![]() |
e5f29dc46c | ||
![]() |
c94d0133fc | ||
![]() |
7cd1e9190b | ||
![]() |
df735880fe | ||
![]() |
f0b89d4168 | ||
![]() |
8af46d4bfb | ||
![]() |
e8fdbee3e4 | ||
![]() |
6cbd20fc90 | ||
![]() |
25c0b2ba95 | ||
![]() |
f16c0e7bcf | ||
![]() |
12e29bc105 | ||
![]() |
f7a7e34b34 | ||
![]() |
4d7049c9b8 | ||
![]() |
ad61caf1d2 | ||
![]() |
f84cbe2078 | ||
![]() |
a9df37f216 | ||
![]() |
60bec3d46c | ||
![]() |
3c1e1f19c4 | ||
![]() |
207d8ff746 | ||
![]() |
835dc7a0fd | ||
![]() |
cdfb956211 | ||
![]() |
d5ba31e5d7 | ||
![]() |
e80ec4f063 | ||
![]() |
cdb8d8681e | ||
![]() |
d6d0abeb1c | ||
![]() |
9565248f95 | ||
![]() |
1d6cd5984b | ||
![]() |
63b857c915 | ||
![]() |
6811f19db4 | ||
![]() |
847e1c0d6e | ||
![]() |
99a8448d53 | ||
![]() |
4fe9cd21ef | ||
![]() |
bdb53ac436 | ||
![]() |
01b9ee4505 | ||
![]() |
fadbf9c6aa | ||
![]() |
60e235e4d7 | ||
![]() |
da4b431761 | ||
![]() |
7fff30521e | ||
![]() |
e7c78774ca | ||
![]() |
fb6f9da14c | ||
![]() |
7b1773c5f0 | ||
![]() |
7b15a74448 | ||
![]() |
956f65941e | ||
![]() |
6d1f806e94 | ||
![]() |
d727d6b778 | ||
![]() |
ea891861b3 | ||
![]() |
e0826a80c8 | ||
![]() |
74868a918e | ||
![]() |
889ecee3f3 | ||
![]() |
f6dd0bbb56 | ||
![]() |
01686f3e9d | ||
![]() |
5a6cd7d671 | ||
![]() |
35e183b640 | ||
![]() |
a684052966 | ||
![]() |
2beb74c319 | ||
![]() |
5218c95162 | ||
![]() |
83be2066c8 | ||
![]() |
975bcbfc00 | ||
![]() |
dbddbc29a3 | ||
![]() |
af3894a908 | ||
![]() |
abb2fd079a | ||
![]() |
83dacb4e6b | ||
![]() |
e83cbaf011 | ||
![]() |
ecd61fd51b | ||
![]() |
3c800b5193 | ||
![]() |
861a8f46e4 | ||
![]() |
6f0b1556bb | ||
![]() |
ab91735695 | ||
![]() |
c611946a9c | ||
![]() |
6a0fe661fa | ||
![]() |
dd20c72910 | ||
![]() |
0de20a290f | ||
![]() |
b4ba95b3f6 | ||
![]() |
b33b588ea4 | ||
![]() |
9d214e2b8f | ||
![]() |
9073802585 | ||
![]() |
f7b00cf621 | ||
![]() |
9f956f6e8c | ||
![]() |
b33598b847 | ||
![]() |
e7fbc126a1 | ||
![]() |
b92025f26c | ||
![]() |
8ffd121261 | ||
![]() |
ab33d841fe | ||
![]() |
384622176a | ||
![]() |
7744902183 | ||
![]() |
c73f240d86 | ||
![]() |
7f1103a031 | ||
![]() |
c4e9f569b7 | ||
![]() |
8af8d4ccaa | ||
![]() |
c13e68eccd | ||
![]() |
57e2aa57f8 | ||
![]() |
64d3602d31 | ||
![]() |
aa2c4bbb6e | ||
![]() |
d20d6c9b7c | ||
![]() |
a99254d0c3 | ||
![]() |
099dfeddcb | ||
![]() |
a5ea8debaa | ||
![]() |
6f1de5cae8 |
44
.github/workflows/build_docker.yaml
vendored
Normal file
44
.github/workflows/build_docker.yaml
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
name: Build and Push Docker Image
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
with:
|
||||
platforms: all
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Login to CNB Registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ${{ secrets.CNB_DOCKER_REGISTRY }}
|
||||
username: ${{ secrets.CNB_USERNAME }}
|
||||
password: ${{ secrets.CNB_TOKEN }}
|
||||
|
||||
- name: Build and push Docker images
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/386,linux/riscv64
|
||||
# linux/mips,linux/mipsle 暂不支持 alpine, linux/s390x 编译卡死
|
||||
push: true
|
||||
tags: |
|
||||
${{ secrets.DOCKER_USERNAME }}/goecs:latest
|
||||
${{ secrets.CNB_DOCKER_REGISTRY }}/oneclickvirt/ecs:latest
|
87
.github/workflows/ci.yaml
vendored
87
.github/workflows/ci.yaml
vendored
@@ -1,87 +0,0 @@
|
||||
name: go-ci
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
setup:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: set up
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.22.4
|
||||
id: go
|
||||
- name: check out
|
||||
uses: actions/checkout@v3
|
||||
- name: Cache
|
||||
uses: actions/cache@v2.1.0
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
- name: Configure Git for Private Modules
|
||||
run: |
|
||||
git config --global url."https://${{ secrets.GHT }}@github.com/".insteadOf "https://github.com/"
|
||||
git config --global url."git@github.com:".insteadOf "https://github.com/"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GHT }}
|
||||
env:
|
||||
GOPRIVATE: github.com/oneclickvirt/security
|
||||
GITHUB_TOKEN: ${{ secrets.GHT }}
|
||||
|
||||
build:
|
||||
needs: setup
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Configure Git for Private Modules
|
||||
run: |
|
||||
git config --global url."https://${{ secrets.GHT }}@github.com/".insteadOf "https://github.com/"
|
||||
git config --global url."git@github.com:".insteadOf "https://github.com/"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GHT }}
|
||||
- name: build
|
||||
run: go build ./...
|
||||
env:
|
||||
GOPRIVATE: github.com/oneclickvirt/security
|
||||
GITHUB_TOKEN: ${{ secrets.GHT }}
|
||||
|
||||
test:
|
||||
needs: setup
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Configure Git for Private Modules
|
||||
run: |
|
||||
git config --global url."https://${{ secrets.GHT }}@github.com/".insteadOf "https://github.com/"
|
||||
git config --global url."git@github.com:".insteadOf "https://github.com/"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GHT }}
|
||||
- name: test
|
||||
run: go test -v ./...
|
||||
env:
|
||||
GOPRIVATE: github.com/oneclickvirt/security
|
||||
GITHUB_TOKEN: ${{ secrets.GHT }}
|
||||
|
||||
lint:
|
||||
needs: setup
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.22.4
|
||||
- uses: actions/checkout@v3
|
||||
- name: Configure Git for Private Modules
|
||||
run: |
|
||||
git config --global url."https://${{ secrets.GHT }}@github.com/".insteadOf "https://github.com/"
|
||||
git config --global url."git@github.com:".insteadOf "https://github.com/"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GHT }}
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
with:
|
||||
version: v1.53.2
|
||||
env:
|
||||
GOPRIVATE: github.com/oneclickvirt/security
|
||||
GITHUB_TOKEN: ${{ secrets.GHT }}
|
13
.github/workflows/main.yaml
vendored
13
.github/workflows/main.yaml
vendored
@@ -8,16 +8,21 @@ on:
|
||||
jobs:
|
||||
goreleaser:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
# 1.20 是 Windows 7/8 Server 2008/2012 最后一个支持版本
|
||||
image: goreleaser/goreleaser-cross:v1.20
|
||||
steps:
|
||||
- run: |
|
||||
git config --global --add safe.directory /__w/ecs/ecs
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: 1.22.4
|
||||
go-version: 1.23.4
|
||||
|
||||
- name: Configure Git for Private Modules
|
||||
run: |
|
||||
@@ -27,11 +32,11 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GHT }}
|
||||
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v4
|
||||
uses: goreleaser/goreleaser-action@v2
|
||||
with:
|
||||
distribution: goreleaser
|
||||
version: latest
|
||||
args: release --clean
|
||||
args: release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GHT }}
|
||||
GOPRIVATE: github.com/oneclickvirt/security
|
||||
|
80
.github/workflows/public-build.yml
vendored
Normal file
80
.github/workflows/public-build.yml
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
name: Public Build
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23.4'
|
||||
|
||||
- name: Create public branch
|
||||
run: |
|
||||
git config --global user.name 'GitHub Actions'
|
||||
git config --global user.email 'actions@github.com'
|
||||
git checkout -b public || git checkout public
|
||||
git merge ${{ github.ref_name }} --no-edit || true
|
||||
|
||||
- name: Remove security package references
|
||||
run: |
|
||||
# 移除 network 包中对 security 的引用
|
||||
find . -type f -name "*.go" -exec sed -i 's|"github.com/oneclickvirt/security/network"|"github.com/oneclickvirt/basics/network"|g' {} +
|
||||
|
||||
# 修改 network/network.go
|
||||
cat > network/network.go << 'EOF'
|
||||
package network1
|
||||
|
||||
import "github.com/oneclickvirt/basics/network"
|
||||
|
||||
func NetworkCheck(checkType string, enableSecurityCheck bool, language string) (string, string, error) {
|
||||
ipInfo, _, err := network.NetworkCheck(checkType, false, language)
|
||||
return ipInfo, "", err
|
||||
}
|
||||
EOF
|
||||
|
||||
# 修改 utils/utils.go 中的 BasicsAndSecurityCheck 函数
|
||||
sed -i '/SecurityUploadToken/d' utils/utils.go
|
||||
sed -i 's|"github.com/oneclickvirt/security/network"|"github.com/oneclickvirt/basics/network"|g' utils/utils.go
|
||||
|
||||
# 在 utils/utils.go 中添加 token 常量(在 import 语句之后)
|
||||
sed -i '/^import/,/^)/{/^)/a\'$'\n''const token = "OvwKx5qgJtf7PZgCKbtyojSU.MTcwMTUxNzY1MTgwMw"'$'\n''}' utils/utils.go
|
||||
|
||||
# 修改 go.mod,移除私有仓库依赖
|
||||
sed -i '/github.com\/oneclickvirt\/security/d' go.mod
|
||||
|
||||
# 修改 goecs.go,禁用 security 检测
|
||||
sed -i 's|var securityFlag = flag.Bool("security", true,|var securityFlag = flag.Bool("security", false,|g' goecs.go
|
||||
|
||||
# 更新依赖
|
||||
go mod tidy
|
||||
|
||||
# 修改 README.md 和 README_EN.md 中的敏感信息
|
||||
sed -i 's|但二进制文件编译至 \[securityCheck\].*)|但已开源|g' README.md
|
||||
sed -i 's|but binary files compiled in \[securityCheck\].*)|but open sourced|g' README_EN.md
|
||||
|
||||
# 修改命令行帮助信息
|
||||
sed -i 's|security.*Enable/Disable security test (default true)|security Enable/Disable security test (default false)|g' README.md
|
||||
sed -i 's|security.*Enable/Disable security test (default true)|security Enable/Disable security test (default false)|g' README_EN.md
|
||||
|
||||
- name: Build and Test
|
||||
run: |
|
||||
# 构建二进制文件
|
||||
go build -o main
|
||||
|
||||
# 测试无菜单模式是否正常运行(禁用 security 检测)
|
||||
./main -menu=false -l en -security=false -upload=false || exit 1
|
||||
|
||||
- name: Commit and push changes
|
||||
run: |
|
||||
git add .
|
||||
git commit -m "Auto update public version (no security package)" || echo "No changes to commit"
|
||||
git push -f origin public
|
56
.github/workflows/sync.yaml
vendored
Normal file
56
.github/workflows/sync.yaml
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
name: Sync Latest Release
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
sync-release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout source repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Get latest release
|
||||
id: get_release
|
||||
run: |
|
||||
echo "RELEASE_TAG=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV
|
||||
|
||||
- name: Create temporary directory
|
||||
run: |
|
||||
mkdir -p temp_repo
|
||||
cd temp_repo
|
||||
git init
|
||||
git config --local user.name "GitHub Action"
|
||||
git config --local user.email "action@github.com"
|
||||
|
||||
- name: Copy repository files
|
||||
run: |
|
||||
cp goecs.sh temp_repo/
|
||||
cp README_EN.md temp_repo/
|
||||
cp README.md temp_repo/
|
||||
cp LICENSE temp_repo/
|
||||
|
||||
- name: Download release assets
|
||||
run: |
|
||||
cd temp_repo
|
||||
gh release download ${{ env.RELEASE_TAG }} --repo ${{ github.repository }} --dir .
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Push to target repository
|
||||
run: |
|
||||
cd temp_repo
|
||||
git add .
|
||||
git commit -m "Sync release ${{ env.RELEASE_TAG }} from ${{ github.repository }}"
|
||||
git branch -M main
|
||||
git remote add target https://cnb.cool/oneclickvirt/ecs.git
|
||||
echo "machine cnb.cool login ${{ secrets.CNB_USERNAME }} password ${{ secrets.CNB_TOKEN }}" > ~/.netrc
|
||||
chmod 600 ~/.netrc
|
||||
git push -f target main
|
||||
env:
|
||||
CNB_USERNAME: ${{ secrets.CNB_USERNAME }}
|
||||
CNB_TOKEN: ${{ secrets.CNB_TOKEN }}
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
vendor/
|
||||
.idea/
|
78
.goreleaser.yaml
Normal file
78
.goreleaser.yaml
Normal file
@@ -0,0 +1,78 @@
|
||||
before:
|
||||
hooks:
|
||||
- go mod tidy -v
|
||||
builds:
|
||||
- id: universal
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
ldflags:
|
||||
- -s -w -X main.version={{.Version}} -X main.arch={{.Arch}} -checklinkname=0
|
||||
goos:
|
||||
- linux
|
||||
- windows
|
||||
- freebsd
|
||||
goarch:
|
||||
- arm
|
||||
- arm64
|
||||
- 386
|
||||
- amd64
|
||||
- mips
|
||||
- mipsle
|
||||
- s390x
|
||||
- riscv64
|
||||
gomips:
|
||||
- softfloat
|
||||
ignore:
|
||||
- goos: windows
|
||||
goarch: arm
|
||||
main: ./
|
||||
binary: goecs
|
||||
- id: darwin-amd64
|
||||
env:
|
||||
- CGO_ENABLED=1
|
||||
- CC=o64-clang
|
||||
- CXX=o64-clang++
|
||||
ldflags:
|
||||
- -s -w -X main.version={{.Version}} -X main.arch={{.Arch}} -checklinkname=0
|
||||
goos:
|
||||
- darwin
|
||||
goarch:
|
||||
- amd64
|
||||
main: ./
|
||||
binary: goecs
|
||||
- id: darwin-arm64
|
||||
env:
|
||||
- CGO_ENABLED=1
|
||||
- CC=oa64-clang
|
||||
- CXX=oa64-clang++
|
||||
ldflags:
|
||||
- -s -w -X main.version={{.Version}} -X main.arch={{.Arch}} -checklinkname=0
|
||||
goos:
|
||||
- darwin
|
||||
goarch:
|
||||
- arm64
|
||||
main: ./
|
||||
binary: goecs
|
||||
universal_binaries:
|
||||
- name_template: "goecs"
|
||||
replace: false
|
||||
checksum:
|
||||
name_template: "checksums.txt"
|
||||
snapshot:
|
||||
name_template: "goecs"
|
||||
archives:
|
||||
- name_template: "goecs_{{ .Os }}_{{ .Arch }}"
|
||||
format: zip
|
||||
files:
|
||||
- none*
|
||||
changelog:
|
||||
sort: asc
|
||||
filters:
|
||||
exclude:
|
||||
- "^docs:"
|
||||
- "^test:"
|
||||
- "^chore"
|
||||
- Merge pull request
|
||||
- Merge branch
|
||||
- go mod tidy
|
||||
- New translations
|
8
.idea/.gitignore
generated
vendored
8
.idea/.gitignore
generated
vendored
@@ -1,8 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
9
.idea/ecs.iml
generated
9
.idea/ecs.iml
generated
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="Go" enabled="true" />
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/ecs.iml" filepath="$PROJECT_DIR$/.idea/ecs.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
8
.idea/sshConfigs.xml
generated
8
.idea/sshConfigs.xml
generated
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="SshConfigs">
|
||||
<configs>
|
||||
<sshConfig authType="PASSWORD" host="49.234.158.14" id="950b8219-3ab3-47e7-ad76-6b6a5d0857b0" port="22" nameFormat="DESCRIPTIVE" username="root" useOpenSSHConfig="true" />
|
||||
</configs>
|
||||
</component>
|
||||
</project>
|
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
14
Dockerfile
Normal file
14
Dockerfile
Normal file
@@ -0,0 +1,14 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
FROM alpine:latest
|
||||
# 安装必要的工具
|
||||
RUN apk add --no-cache wget curl bash
|
||||
RUN apk add --no-cache bind-tools --repository=http://dl-cdn.alpinelinux.org/alpine/edge/main
|
||||
RUN apk add --no-cache grep openssl ca-certificates uuidgen
|
||||
RUN export noninteractive=true
|
||||
# 下载并执行 goecs.sh 脚本
|
||||
RUN curl -L https://raw.githubusercontent.com/oneclickvirt/ecs/master/goecs.sh -o goecs.sh && \
|
||||
chmod +x goecs.sh && \
|
||||
bash goecs.sh env && \
|
||||
bash goecs.sh install
|
||||
# 设置 goecs 为入口点
|
||||
ENTRYPOINT ["goecs"]
|
687
LICENSE
687
LICENSE
@@ -1,21 +1,674 @@
|
||||
MIT License
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (c) 2024 oneclickvirt
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
Preamble
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
|
384
README.md
384
README.md
@@ -1,30 +1,372 @@
|
||||
# ecs
|
||||
# ECS
|
||||
|
||||
[](https://github.com/oneclickvirt/ecs/actions/workflows/main.yaml)
|
||||
[](https://github.com/oneclickvirt/ecs/actions/workflows/main.yaml)
|
||||
|
||||
融合怪测评脚本 - GO重构版本
|
||||
[](https://www.spiritlhl.net/)
|
||||
|
||||
Shell版本: https://github.com/spiritLHLS/ecs
|
||||
融合怪测评项目 - GO 重构版本
|
||||
|
||||
## 功能
|
||||
如有问题请 [issues](https://github.com/oneclickvirt/ecs/issues) 反馈。
|
||||
|
||||
- [x] 系统基础信息查询[自研[basics](https://github.com/oneclickvirt/basics)、[gostun](https://github.com/oneclickvirt/gostun)]
|
||||
- [x] IP基础信息并发查询[自研[basics](https://github.com/oneclickvirt/basics)]
|
||||
- [x] CPU测试[自研[cputest](https://github.com/oneclickvirt/cputest)支持sysbench、geekbench、winsat]
|
||||
- [x] 内存测试[自研[memorytest](https://github.com/oneclickvirt/memorytest)支持sysbench、dd]
|
||||
- [x] 硬盘测试[自研[disktest](https://github.com/oneclickvirt/disktest)支持dd、fio、winsat]
|
||||
- [x] 御三家流媒体解锁信息并发查询[借鉴[netflix-verify](https://github.com/sjlleo/netflix-verify)、[VerifyDisneyPlus](https://github.com/sjlleo/VerifyDisneyPlus)、[TubeCheck](https://github.com/sjlleo/TubeCheck)二次开发至于[CommonMediaTests](https://github.com/oneclickvirt/CommonMediaTests)]
|
||||
- [x] 常见流媒体测试并发查询[自研代码,逻辑借鉴[RegionRestrictionCheck](https://github.com/lmc999/RegionRestrictionCheck)、[MediaUnlockTest](https://github.com/HsukqiLee/MediaUnlockTest)并自行修复错漏至于[UnlockTests](https://github.com/oneclickvirt/UnlockTests)]
|
||||
- [x] IP质量/安全信息并发查询[自研,由于测试含密钥信息,故而私有化开发,但二进制文件编译至于[securityCheck](https://github.com/oneclickvirt/securityCheck)]
|
||||
- [x] 邮件端口测试[自研[portchecker](https://github.com/oneclickvirt/portchecker)]
|
||||
- [x] 三网回程测试[借鉴[zhanghanyun/backtrace](https://github.com/zhanghanyun/backtrace)二次开发至于[oneclickvirt/backtrace](https://github.com/oneclickvirt/backtrace)]
|
||||
- [x] 三网路由测试[借鉴[NTrace-core](https://github.com/nxtrace/NTrace-core)二次开发至于[nt3](https://github.com/oneclickvirt/nt3)]
|
||||
- [x] 测试网速[基于[speedtest.net-爬虫](https://github.com/spiritLHLS/speedtest.net-CN-ID)、[speedtest.cn-爬虫](https://github.com/spiritLHLS/speedtest.cn-CN-ID)的数据,借鉴[speedtest-go](https://github.com/showwin/speedtest-go)二次开发]
|
||||
Go 版本:[https://github.com/oneclickvirt/ecs](https://github.com/oneclickvirt/ecs)
|
||||
|
||||
## TODO
|
||||
Shell 版本:[https://github.com/spiritLHLS/ecs](https://github.com/spiritLHLS/ecs)
|
||||
|
||||
- [ ] 测试三网Ping值[借鉴[ecsspeed](https://github.com/spiritLHLS/ecsspeed)的逻辑二次开发]
|
||||
---
|
||||
|
||||
## 说明
|
||||
## **语言**
|
||||
|
||||
开发中,勿要使用
|
||||
[中文文档](README.md) | [English Docs](README_EN.md)
|
||||
|
||||
---
|
||||
|
||||
## **适配系统和架构**
|
||||
|
||||
### **编译支持的架构**
|
||||
|
||||
- amd64、arm、arm64、386、mips、mipsle、s390x、riscv64
|
||||
|
||||
### **测试支持的架构**
|
||||
|
||||
- amd64、arm64、s390x
|
||||
|
||||
> 更多架构请自行测试,如有问题请开issues。
|
||||
|
||||
### **编译支持的系统**
|
||||
|
||||
- Linux、Windows、MacOS、FreeBSD、OpenBSD
|
||||
|
||||
### **测试支持的系统**
|
||||
|
||||
- Linux、Windows、FreeBSD、OpenBSD
|
||||
|
||||
> 更多系统请自行测试,如有问题请开issues。
|
||||
|
||||
### **待支持的系统**
|
||||
|
||||
- MacOS、FreeBSD、OpenBSD(存在硬件测试 BUG 未修复)
|
||||
|
||||
---
|
||||
|
||||
## **功能**
|
||||
|
||||
- 系统基础信息查询,IP基础信息并发查询:
|
||||
自研 [basics](https://github.com/oneclickvirt/basics)、[gostun](https://github.com/oneclickvirt/gostun)
|
||||
- CPU 测试:
|
||||
自研 [cputest](https://github.com/oneclickvirt/cputest),支持 sysbench(lua/golang版本)、geekbench、winsat
|
||||
- 内存测试:
|
||||
自研 [memorytest](https://github.com/oneclickvirt/memorytest),支持 sysbench、dd
|
||||
- 硬盘测试:
|
||||
自研 [disktest](https://github.com/oneclickvirt/disktest),支持 dd、fio、winsat
|
||||
- 流媒体解锁信息并发查询:
|
||||
借鉴 [netflix-verify](https://github.com/sjlleo/netflix-verify) 等逻辑,开发至 [CommonMediaTests](https://github.com/oneclickvirt/CommonMediaTests)
|
||||
- 常见流媒体测试并发查询:
|
||||
自研至 [UnlockTests](https://github.com/oneclickvirt/UnlockTests),逻辑借鉴 [RegionRestrictionCheck](https://github.com/lmc999/RegionRestrictionCheck) 等
|
||||
- IP 质量/安全信息并发查询:
|
||||
自研,二进制文件编译至 [securityCheck](https://github.com/oneclickvirt/securityCheck)
|
||||
- 邮件端口测试:
|
||||
自研 [portchecker](https://github.com/oneclickvirt/portchecker)
|
||||
- 三网回程测试:
|
||||
借鉴 [zhanghanyun/backtrace](https://github.com/zhanghanyun/backtrace),二次开发至 [oneclickvirt/backtrace](https://github.com/oneclickvirt/backtrace)
|
||||
- 三网路由测试:
|
||||
基于 [NTrace-core](https://github.com/nxtrace/NTrace-core),二次开发至 [nt3](https://github.com/oneclickvirt/nt3)
|
||||
- 网速测试:
|
||||
基于 [speedtest.net](https://github.com/spiritLHLS/speedtest.net-CN-ID) 和 [speedtest.cn](https://github.com/spiritLHLS/speedtest.cn-CN-ID) 数据,开发至 [oneclickvirt/speedtest](https://github.com/oneclickvirt/speedtest)
|
||||
- 三网 Ping 值测试:
|
||||
借鉴 [ecsspeed](https://github.com/spiritLHLS/ecsspeed),二次开发至 [pingtest](https://github.com/oneclickvirt/pingtest)
|
||||
|
||||
---
|
||||
|
||||
## **使用说明**
|
||||
|
||||
### **Linux/FreeBSD/MacOS**
|
||||
|
||||
#### **一键命令**
|
||||
|
||||
将默认安装依赖,默认更新包管理器,默认非互动模式,下面的非一键命令版本可控制是否安装依赖/是否更新包管理器/默认互动模式
|
||||
|
||||
- **国际用户无加速:**
|
||||
|
||||
```bash
|
||||
export noninteractive=true && curl -L https://raw.githubusercontent.com/oneclickvirt/ecs/master/goecs.sh -o goecs.sh && chmod +x goecs.sh && bash goecs.sh env && bash goecs.sh install && goecs
|
||||
```
|
||||
|
||||
- **国际/国内使用 CDN 加速:**
|
||||
|
||||
```bash
|
||||
export noninteractive=true && curl -L https://cdn.spiritlhl.net/https://raw.githubusercontent.com/oneclickvirt/ecs/master/goecs.sh -o goecs.sh && chmod +x goecs.sh && bash goecs.sh env && bash goecs.sh install && goecs
|
||||
```
|
||||
|
||||
- **国内用户使用 CNB 加速:**
|
||||
|
||||
```bash
|
||||
export noninteractive=true && curl -L https://cnb.cool/oneclickvirt/ecs/-/git/raw/main/goecs.sh -o goecs.sh && chmod +x goecs.sh && bash goecs.sh env && bash goecs.sh install && goecs
|
||||
```
|
||||
|
||||
#### **详细说明**
|
||||
|
||||
1. **下载脚本**
|
||||
|
||||
**国际用户无加速:**
|
||||
|
||||
```bash
|
||||
curl -L https://raw.githubusercontent.com/oneclickvirt/ecs/master/goecs.sh -o goecs.sh && chmod +x goecs.sh
|
||||
```
|
||||
|
||||
**国际/国内使用 CDN 加速:**
|
||||
|
||||
```bash
|
||||
curl -L https://cdn.spiritlhl.net/https://raw.githubusercontent.com/oneclickvirt/ecs/master/goecs.sh -o goecs.sh && chmod +x goecs.sh
|
||||
```
|
||||
|
||||
**国内用户使用 CNB 加速:**
|
||||
|
||||
```bash
|
||||
curl -L https://cnb.cool/oneclickvirt/ecs/-/git/raw/main/goecs.sh -o goecs.sh && chmod +x goecs.sh
|
||||
```
|
||||
|
||||
2. **更新包管理器(可选择)并安装环境**
|
||||
|
||||
```bash
|
||||
./goecs.sh env
|
||||
```
|
||||
|
||||
**非互动模式:**
|
||||
|
||||
```bash
|
||||
export noninteractive=true && ./goecs.sh env
|
||||
```
|
||||
|
||||
3. **安装 `goecs`**
|
||||
|
||||
```bash
|
||||
./goecs.sh install
|
||||
```
|
||||
|
||||
4. **升级 `goecs`**
|
||||
|
||||
```bash
|
||||
./goecs.sh upgrade
|
||||
```
|
||||
|
||||
5. **卸载 `goecs`**
|
||||
|
||||
```bash
|
||||
./goecs.sh uninstall
|
||||
```
|
||||
|
||||
6. **帮助命令**
|
||||
|
||||
```bash
|
||||
./goecs.sh -h
|
||||
```
|
||||
|
||||
7. **唤起菜单**
|
||||
|
||||
```bash
|
||||
goecs
|
||||
```
|
||||
|
||||
#### **命令参数化**
|
||||
|
||||
<details>
|
||||
<summary>展开查看各参数说明</summary>
|
||||
|
||||
```bash
|
||||
Usage: goecs [options]
|
||||
-backtrace
|
||||
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)
|
||||
-cpu
|
||||
Enable/Disable CPU test (default true)
|
||||
-cpum string
|
||||
Set CPU test method (supported: sysbench, geekbench, winsat) (default "sysbench")
|
||||
-cput string
|
||||
Set CPU test thread mode (supported: single, multi) (default "multi")
|
||||
-disk
|
||||
Enable/Disable disk test (default true)
|
||||
-diskm string
|
||||
Set disk test method (supported: fio, dd, winsat) (default "fio")
|
||||
-diskmc
|
||||
Enable/Disable multiple disk checks, e.g., -diskmc=false
|
||||
-diskp string
|
||||
Set disk test path, e.g., -diskp /root
|
||||
-email
|
||||
Enable/Disable email port test (default true)
|
||||
-h Show help information
|
||||
-l string
|
||||
Set language (supported: en, zh) (default "zh")
|
||||
-log
|
||||
Enable/Disable logging in the current path
|
||||
-memory
|
||||
Enable/Disable memory test (default true)
|
||||
-memorym string
|
||||
Set memory test method (supported: sysbench, dd, winsat) (default "sysbench")
|
||||
-menu
|
||||
Enable/Disable menu mode, disable example: -menu=false (default true)
|
||||
-nt3
|
||||
Enable/Disable NT3 test (in 'en' language or on windows it always false) (default true)
|
||||
-nt3loc string
|
||||
Specify NT3 test location (supported: GZ, SH, BJ, CD for Guangzhou, Shanghai, Beijing, Chengdu) (default "GZ")
|
||||
-nt3t string
|
||||
Set NT3 test type (supported: both, ipv4, ipv6) (default "ipv4")
|
||||
-security
|
||||
Enable/Disable security test (default true)
|
||||
-speed
|
||||
Enable/Disable speed test (default true)
|
||||
-spnum int
|
||||
Set the number of servers per operator for speed test (default 2)
|
||||
-upload
|
||||
Enable/Disable upload the result (default true)
|
||||
-ut
|
||||
Enable/Disable unlock media test (default true)
|
||||
-v Display version information
|
||||
```
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
### **Windows**
|
||||
|
||||
1. 下载带 exe 文件的压缩包:[Releases](https://github.com/oneclickvirt/ecs/releases)
|
||||
2. 解压后,右键以管理员模式运行。
|
||||
|
||||
---
|
||||
|
||||
### **Docker**
|
||||
|
||||
国际镜像地址:https://hub.docker.com/r/spiritlhl/goecs
|
||||
|
||||
请确保执行下述命令前本机已安装Docker
|
||||
|
||||
特权模式+host网络
|
||||
|
||||
```shell
|
||||
docker run --rm --privileged --network host spiritlhl/goecs:latest -menu=false -l zh
|
||||
```
|
||||
|
||||
非特权模式+非host网络
|
||||
|
||||
```shell
|
||||
docker run --rm spiritlhl/goecs:latest -menu=false -l zh
|
||||
```
|
||||
|
||||
使用Docker执行测试,硬件测试会有一些偏差和虚拟化架构判断失效,还是推荐直接测试而不使用Docker测试。
|
||||
|
||||
国内镜像地址:https://cnb.cool/oneclickvirt/ecs/-/packages/docker/ecs
|
||||
|
||||
请确保执行下述命令前本机已安装Docker
|
||||
|
||||
特权模式+host网络
|
||||
|
||||
```shell
|
||||
docker run --rm --privileged --network host docker.cnb.cool/oneclickvirt/ecs:latest -menu=false -l zh
|
||||
```
|
||||
|
||||
非特权模式+非host网络
|
||||
|
||||
```shell
|
||||
docker run --rm docker.cnb.cool/oneclickvirt/ecs:latest -menu=false -l zh
|
||||
```
|
||||
|
||||
我来帮你修复排版,以下是格式调整后的完整内容:
|
||||
|
||||
### 从源码中进行编译
|
||||
|
||||
<details>
|
||||
<summary>展开查看编译说明</summary>
|
||||
|
||||
1. 克隆仓库的 public 分支(不含私有依赖)
|
||||
```bash
|
||||
git clone -b public https://github.com/oneclickvirt/ecs.git
|
||||
cd ecs
|
||||
```
|
||||
|
||||
2. 安装 Go 环境(如已安装可跳过)
|
||||
```bash
|
||||
# 下载并安装 Go
|
||||
wget https://go.dev/dl/go1.23.4.linux-amd64.tar.gz
|
||||
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.23.4.linux-amd64.tar.gz
|
||||
export PATH=$PATH:/usr/local/go/bin
|
||||
```
|
||||
|
||||
3. 编译
|
||||
```bash
|
||||
go build -o goecs
|
||||
```
|
||||
|
||||
4. 运行测试
|
||||
```bash
|
||||
./goecs -menu=false -l zh
|
||||
```
|
||||
|
||||
支持的编译参数:
|
||||
- GOOS:支持 linux、windows、darwin、freebsd、openbsd
|
||||
- GOARCH:支持 amd64、arm、arm64、386、mips、mipsle、s390x、riscv64
|
||||
|
||||
跨平台编译示例:
|
||||
```bash
|
||||
# 编译 Windows 版本
|
||||
GOOS=windows GOARCH=amd64 go build -o goecs.exe
|
||||
# 编译 MacOS 版本
|
||||
GOOS=darwin GOARCH=amd64 go build -o goecs_darwin
|
||||
```
|
||||
</details>
|
||||
|
||||
## QA
|
||||
|
||||
#### Q: 为什么默认使用sysbench而不是geekbench
|
||||
|
||||
#### A: 比较二者特点
|
||||
|
||||
| 比较项 | sysbench | geekbench |
|
||||
|------------------|----------|-----------|
|
||||
| 适用范围 | 轻量级,几乎可在任何服务器上运行 | 重量级,小型机器无法运行 |
|
||||
| 测试要求 | 无需网络,无特殊硬件需求 | 需联网,IPV4环境,至少1G内存 |
|
||||
| 开源情况 | 基于LUA,开源,可自行编译各架构版本 | 官方二进制闭源代码,不支持自行编译 |
|
||||
| 测试稳定性 | 核心测试组件10年以上未变 | 每个大版本更新测试项,分数不同版本间难以对比(每个版本对标当前最好的CPU) |
|
||||
| 测试内容 | 仅测试计算性能 | 覆盖多种性能测试,分数加权计算,但部分测试实际不常用 |
|
||||
| 适用场景 | 适合快速测试,仅测试计算性能 | 适合综合全面的测试 |
|
||||
|
||||
且```goecs```测试使用何种CPU测试方式可使用参数指定,默认只是为了更多用户快速测试的需求
|
||||
|
||||
#### Q: 为什么使用Golang而不是Rust重构
|
||||
|
||||
#### A: 因为网络相关的项目目前以Golang语言为趋势,大多组件有开源生态维护,Rust很多得自己手搓,~~我懒得搞~~我没那个技术力
|
||||
|
||||
#### Q: 为什么不继续开发Shell版本而是选择重构
|
||||
|
||||
#### A: 因为太多千奇百怪的环境问题了,还是提前编译好测试的二进制文件比较容易解决环境问题(泛化性更好)
|
||||
|
||||
#### Q: 每个测试项目的说明有吗?
|
||||
|
||||
#### A: 每个测试项目有对应的维护仓库,自行点击查看仓库说明
|
||||
|
||||
#### Q: 测试进行到一半如何手动终止?
|
||||
|
||||
#### A: 按ctrl键和c键终止程序,终止后依然会在当前目录下生成goecs.txt文件和分享链接,里面是已经测试到的信息。
|
||||
|
||||
#### Q: 非Root环境如何进行测试?
|
||||
|
||||
#### A: 手动执行安装命令,实在装不上也没问题,直接在release中下载对应架构的压缩包解压后执行即可,只要你能执行的了文件。或者你能使用docker的话用docker执行。
|
||||
|
||||
## 致谢
|
||||
|
||||
感谢 [ipinfo.io](https://ipinfo.io) [ip.sb](https://ip.sb) [cheervision.co](https://cheervision.co) [scamalytics.com](https://scamalytics.com) [abuseipdb.com](https://www.abuseipdb.com/) [virustotal.com](https://www.virustotal.com/) [ip2location.com](ip2location.com/) [ip-api.com](https://ip-api.com) [ipregistry.co](https://ipregistry.co/) [ipdata.co](https://ipdata.co/) [ipgeolocation.io](https://ipgeolocation.io) [ipwhois.io](https://ipwhois.io) [ipapi.com](https://ipapi.com/) [ipapi.is](https://ipapi.is/) [ipqualityscore.com](https://www.ipqualityscore.com/) [bigdatacloud.com](https://www.bigdatacloud.com/) 等网站提供的API进行检测,感谢互联网各网站提供的查询资源
|
||||
|
||||
感谢
|
||||
|
||||
<a href="https://h501.io/?from=69" target="_blank">
|
||||
<img src="https://github.com/spiritLHLS/ecs/assets/103393591/dfd47230-2747-4112-be69-b5636b34f07f" alt="h501">
|
||||
</a>
|
||||
|
||||
提供的免费托管支持本开源项目的共享测试结果存储
|
||||
|
||||
同时感谢以下平台提供编辑和测试支持
|
||||
|
||||

|
||||
|
||||

|
||||
|
369
README_EN.md
Normal file
369
README_EN.md
Normal file
@@ -0,0 +1,369 @@
|
||||
# ecs
|
||||
|
||||
[](https://github.com/oneclickvirt/ecs/actions/workflows/main.yaml)
|
||||
|
||||
[](https://www.spiritlhl.net/)
|
||||
|
||||
Fusion Monster Evaluation Project - GO Refactored Version
|
||||
|
||||
Please report any issues via [issues](https://github.com/oneclickvirt/ecs/issues).
|
||||
|
||||
Go version: [https://github.com/oneclickvirt/ecs](https://github.com/oneclickvirt/ecs)
|
||||
|
||||
Shell version: [https://github.com/spiritLHLS/ecs/blob/main/README_EN.md](https://github.com/spiritLHLS/ecs/blob/main/README_EN.md)
|
||||
|
||||
---
|
||||
|
||||
## **Language**
|
||||
|
||||
[中文文档](README.md) | [English Docs](README_EN.md)
|
||||
|
||||
---
|
||||
|
||||
## **Supported Systems and Architectures**
|
||||
|
||||
### **Architectures supported for compilation**
|
||||
|
||||
- amd64, arm, arm64, 386, mips, mipsle, s390x, riscv64
|
||||
|
||||
### **Tested architectures**
|
||||
|
||||
- amd64, arm64, s390x
|
||||
|
||||
> More architectures can be tested by yourself.
|
||||
|
||||
### **Compilation supported systems**
|
||||
|
||||
- Linux, Windows, MacOS, FreeBSD, OpenBSD
|
||||
|
||||
### **Tested systems**
|
||||
|
||||
- Linux, Windows、FreeBSD、OpenBSD
|
||||
|
||||
> More systems can be tested by yourself.
|
||||
|
||||
### **Systems to be supported**
|
||||
|
||||
- MacOS, FreeBSD, OpenBSD (hardware testing bugs not yet fixed)
|
||||
|
||||
---
|
||||
|
||||
## **Features**
|
||||
|
||||
- System basic information query and concurrent IP basic information query:
|
||||
Self-developed [basics](https://github.com/oneclickvirt/basics), [gostun](https://github.com/oneclickvirt/gostun)
|
||||
- CPU test:
|
||||
Self-developed [cputest](https://github.com/oneclickvirt/cputest) supporting sysbench(lua/golang version), geekbench, winsat
|
||||
- Memory test:
|
||||
Self-developed [memorytest](https://github.com/oneclickvirt/memorytest) supporting sysbench, dd
|
||||
- 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
|
||||
- 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)
|
||||
- Three-network route test:
|
||||
Modified from [NTrace-core](https://github.com/nxtrace/NTrace-core) to [nt3](https://github.com/oneclickvirt/nt3)
|
||||
- Speed test:
|
||||
Based on data from [speedtest.net](https://github.com/spiritLHLS/speedtest.net-CN-ID) and [speedtest.cn](https://github.com/spiritLHLS/speedtest.cn-CN-ID), developed to [oneclickvirt/speedtest](https://github.com/oneclickvirt/speedtest)
|
||||
- Three-network Ping test:
|
||||
Modified from [ecsspeed](https://github.com/spiritLHLS/ecsspeed) to [pingtest](https://github.com/oneclickvirt/pingtest)
|
||||
|
||||
---
|
||||
|
||||
## **Instructions for Use**
|
||||
|
||||
### **Linux/FreeBSD/MacOS**
|
||||
|
||||
#### **One-click command**
|
||||
|
||||
Will install dependencies by default, update package manager by default, non-interactive mode by default. The non-one-click version below allows control of dependency installation/package manager updates/interactive mode by default.
|
||||
|
||||
- **International users without acceleration:**
|
||||
|
||||
```bash
|
||||
export noninteractive=true && curl -L https://raw.githubusercontent.com/oneclickvirt/ecs/master/goecs.sh -o goecs.sh && chmod +x goecs.sh && bash goecs.sh env && bash goecs.sh install && goecs -l en
|
||||
```
|
||||
|
||||
- **International/domestic users with CDN acceleration:**
|
||||
|
||||
```bash
|
||||
export noninteractive=true && curl -L https://cdn.spiritlhl.net/https://raw.githubusercontent.com/oneclickvirt/ecs/master/goecs.sh -o goecs.sh && chmod +x goecs.sh && bash goecs.sh env && bash goecs.sh install && goecs -l en
|
||||
```
|
||||
|
||||
- **Domestic users with CNB acceleration:**
|
||||
|
||||
```bash
|
||||
export noninteractive=true && curl -L https://cnb.cool/oneclickvirt/ecs/-/git/raw/main/goecs.sh -o goecs.sh && chmod +x goecs.sh && bash goecs.sh env && bash goecs.sh install && goecs -l en
|
||||
```
|
||||
|
||||
#### **Detailed instructions**
|
||||
|
||||
1. **Download the script**
|
||||
|
||||
**International users without acceleration:**
|
||||
|
||||
```bash
|
||||
curl -L https://raw.githubusercontent.com/oneclickvirt/ecs/master/goecs.sh -o goecs.sh && chmod +x goecs.sh
|
||||
```
|
||||
|
||||
**International/domestic users with CDN acceleration:**
|
||||
|
||||
```bash
|
||||
curl -L https://cdn.spiritlhl.net/https://raw.githubusercontent.com/oneclickvirt/ecs/master/goecs.sh -o goecs.sh && chmod +x goecs.sh
|
||||
```
|
||||
|
||||
**Domestic users with CNB acceleration:**
|
||||
|
||||
```bash
|
||||
curl -L https://cnb.cool/oneclickvirt/ecs/-/git/raw/main/goecs.sh -o goecs.sh && chmod +x goecs.sh
|
||||
```
|
||||
|
||||
2. **Update package manager (optional) and install environment**
|
||||
|
||||
```bash
|
||||
./goecs.sh env
|
||||
```
|
||||
|
||||
**Non-interactive mode:**
|
||||
|
||||
```bash
|
||||
export noninteractive=true && ./goecs.sh env
|
||||
```
|
||||
|
||||
3. **Install `goecs`**
|
||||
|
||||
```bash
|
||||
./goecs.sh install
|
||||
```
|
||||
|
||||
4. **Upgrade `goecs`**
|
||||
|
||||
```bash
|
||||
./goecs.sh upgrade
|
||||
```
|
||||
|
||||
5. **Uninstall `goecs`**
|
||||
|
||||
```bash
|
||||
./goecs.sh uninstall
|
||||
|
||||
6. **help command**
|
||||
|
||||
```bash
|
||||
./goecs.sh -h
|
||||
```
|
||||
|
||||
7. **Invoke the menu**
|
||||
|
||||
```bash
|
||||
goecs -l en
|
||||
```
|
||||
|
||||
#### **Command parameterization**
|
||||
|
||||
<details>
|
||||
<summary>Expand to view parameter descriptions</summary>
|
||||
|
||||
```bash
|
||||
Usage: goecs [options]
|
||||
-backtrace
|
||||
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)
|
||||
-cpu
|
||||
Enable/Disable CPU test (default true)
|
||||
-cpum string
|
||||
Set CPU test method (supported: sysbench, geekbench, winsat) (default "sysbench")
|
||||
-cput string
|
||||
Set CPU test thread mode (supported: single, multi) (default "multi")
|
||||
-disk
|
||||
Enable/Disable disk test (default true)
|
||||
-diskm string
|
||||
Set disk test method (supported: fio, dd, winsat) (default "fio")
|
||||
-diskmc
|
||||
Enable/Disable multiple disk checks, e.g., -diskmc=false
|
||||
-diskp string
|
||||
Set disk test path, e.g., -diskp /root
|
||||
-email
|
||||
Enable/Disable email port test (default true)
|
||||
-h Show help information
|
||||
-l string
|
||||
Set language (supported: en, zh) (default "zh")
|
||||
-log
|
||||
Enable/Disable logging in the current path
|
||||
-memory
|
||||
Enable/Disable memory test (default true)
|
||||
-memorym string
|
||||
Set memory test method (supported: sysbench, dd, winsat) (default "sysbench")
|
||||
-menu
|
||||
Enable/Disable menu mode, disable example: -menu=false (default true)
|
||||
-nt3
|
||||
Enable/Disable NT3 test (in 'en' language or on windows it always false) (default true)
|
||||
-nt3loc string
|
||||
Specify NT3 test location (supported: GZ, SH, BJ, CD for Guangzhou, Shanghai, Beijing, Chengdu) (default "GZ")
|
||||
-nt3t string
|
||||
Set NT3 test type (supported: both, ipv4, ipv6) (default "ipv4")
|
||||
-security
|
||||
Enable/Disable security test (default true)
|
||||
-speed
|
||||
Enable/Disable speed test (default true)
|
||||
-spnum int
|
||||
Set the number of servers per operator for speed test (default 2)
|
||||
-upload
|
||||
Enable/Disable upload the result (default true)
|
||||
-ut
|
||||
Enable/Disable unlock media test (default true)
|
||||
-v Display version information
|
||||
```
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
### **Windows**
|
||||
|
||||
1. Download the compressed file with the .exe file: [Releases](https://github.com/oneclickvirt/ecs/releases)
|
||||
2. After unzipping, right-click and run as administrator.
|
||||
|
||||
---
|
||||
|
||||
### **Docker**
|
||||
|
||||
International image: https://hub.docker.com/r/spiritlhl/goecs
|
||||
|
||||
Please ensure Docker is installed on your machine before executing the following commands
|
||||
|
||||
Privileged mode + host network
|
||||
|
||||
```shell
|
||||
docker run --rm --privileged --network host spiritlhl/goecs:latest -menu=false -l en
|
||||
```
|
||||
|
||||
Unprivileged mode + non-host network
|
||||
|
||||
```shell
|
||||
docker run --rm spiritlhl/goecs:latest -menu=false -l en
|
||||
```
|
||||
|
||||
Using Docker to execute tests will result in some hardware testing bias and virtualization architecture detection failure. Direct testing is recommended over Docker testing.
|
||||
|
||||
Domestic image: https://cnb.cool/oneclickvirt/ecs/-/packages/docker/ecs
|
||||
|
||||
Please ensure Docker is installed on your machine before executing the following commands
|
||||
|
||||
Privileged mode + host network
|
||||
|
||||
```shell
|
||||
docker run --rm --privileged --network host docker.cnb.cool/oneclickvirt/ecs:latest -menu=false -l en
|
||||
```
|
||||
|
||||
Unprivileged mode + non-host network
|
||||
|
||||
```shell
|
||||
docker run --rm docker.cnb.cool/oneclickvirt/ecs:latest -menu=false -l en
|
||||
```
|
||||
|
||||
### Compiling from source code
|
||||
|
||||
<details>
|
||||
<summary>Expand to view compilation instructions</summary>
|
||||
|
||||
1. Clone the public branch of the repository (without private dependencies)
|
||||
```bash
|
||||
git clone -b public https://github.com/oneclickvirt/ecs.git
|
||||
cd ecs
|
||||
```
|
||||
|
||||
2. Install Go environment (skip if already installed)
|
||||
```bash
|
||||
# Download and install Go
|
||||
wget https://go.dev/dl/go1.23.4.linux-amd64.tar.gz
|
||||
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.23.4.linux-amd64.tar.gz
|
||||
export PATH=$PATH:/usr/local/go/bin
|
||||
```
|
||||
|
||||
3. Compile
|
||||
```bash
|
||||
go build -o goecs
|
||||
```
|
||||
|
||||
4. Run test
|
||||
```bash
|
||||
./goecs -menu=false -l en
|
||||
```
|
||||
|
||||
Supported compilation parameters:
|
||||
- GOOS: supports linux, windows, darwin, freebsd, openbsd
|
||||
- GOARCH: supports amd64, arm, arm64, 386, mips, mipsle, s390x, riscv64
|
||||
|
||||
Cross-platform compilation examples:
|
||||
```bash
|
||||
# Compile Windows version
|
||||
GOOS=windows GOARCH=amd64 go build -o goecs.exe
|
||||
# Compile MacOS version
|
||||
GOOS=darwin GOARCH=amd64 go build -o goecs_darwin
|
||||
```
|
||||
</details>
|
||||
|
||||
## QA
|
||||
|
||||
#### Q: Why is sysbench used by default instead of geekbench?
|
||||
|
||||
#### A: Comparing the characteristics of both:
|
||||
|
||||
| Comparison | sysbench | geekbench |
|
||||
|------------|----------|-----------|
|
||||
| Application scope | Lightweight, runs on almost any server | Heavyweight, won't run on small machines |
|
||||
| Test requirements | No network needed, no special hardware requirements | Requires internet, IPv4 environment, minimum 1GB memory |
|
||||
| Open source status | Based on LUA, open source, can compile for various architectures | Official binaries are closed source, cannot compile your own version |
|
||||
| Test stability | Core test components unchanged for 10+ years | Each major version updates test items, making scores hard to compare between versions (each version benchmarks against current best CPUs) |
|
||||
| Test content | Only tests computing performance | Covers multiple performance aspects with weighted scores, though some tests aren't commonly used |
|
||||
| Suitable scenarios | Good for quick tests, focuses on computing performance | Good for comprehensive testing |
|
||||
|
||||
Note that `goecs` allows you to specify CPU test method via parameters. The default is chosen for faster testing across more systems.
|
||||
|
||||
#### Q: Why use Golang instead of Rust for refactoring?
|
||||
|
||||
#### A: Because network-related projects currently trend toward Golang, with many components maintained by open source communities. Many Rust components would require building from scratch, ~~I'm too lazy~~ I don't have that technical capability.
|
||||
|
||||
#### Q: Why not continue developing the Shell version instead of refactoring?
|
||||
|
||||
#### A: Because there were too many varied environment issues. Pre-compiled binary files are easier for solving environment problems (better generalization).
|
||||
|
||||
#### Q: Are there explanations for each test item?
|
||||
|
||||
#### A: Each test project has its own maintenance repository. Click through to view the repository description.
|
||||
|
||||
#### Q: How do I manually terminate a test halfway through?
|
||||
|
||||
#### A: Press Ctrl+C to terminate the program. After termination, a goecs.txt file and share link will still be generated in the current directory containing information tested so far.
|
||||
|
||||
#### Q: How do I test in a non-Root environment?
|
||||
|
||||
#### A: Execute the installation command manually. If you can't install it, simply download the appropriate architecture package from releases, extract it, and run the file if you have execution permissions. Alternatively, use Docker if you can.
|
||||
|
||||
## Thanks
|
||||
|
||||
Thank [ipinfo.io](https://ipinfo.io) [ip.sb](https://ip.sb) [cheervision.co](https://cheervision.co) [scamalytics.com](https://scamalytics.com) [abuseipdb.com](https://www.abuseipdb.com/) [virustotal.com](https://www.virustotal.com/) [ip2location.com](ip2location.com/) [ip-api.com](https://ip-api.com) [ipregistry.co](https://ipregistry.co/) [ipdata.co](https://ipdata.co/) [ipgeolocation.io](https://ipgeolocation.io) [ipwhois.io](https://ipwhois.io) [ipapi.com](https://ipapi.com/) [ipapi.is](https://ipapi.is/) [ipqualityscore.com](https://www.ipqualityscore.com/) [bigdatacloud.com](https://www.bigdatacloud.com/) and others for providing APIs for testing, and thanks to various websites on the Internet for providing query resources.
|
||||
|
||||
Thank
|
||||
|
||||
<a href="https://h501.io/?from=69" target="_blank">
|
||||
<img src="https://github.com/spiritLHLS/ecs/assets/103393591/dfd47230-2747-4112-be69-b5636b34f07f" alt="h501">
|
||||
</a>
|
||||
|
||||
provided free hosting support for this open source project's shared test results storage
|
||||
|
||||
Thanks also to the following platforms for editorial and testing support
|
||||
|
||||

|
||||
|
||||

|
@@ -1,6 +1,8 @@
|
||||
package basic
|
||||
package basic1
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_basic(t *testing.T) {
|
||||
Basic("zh")
|
||||
|
@@ -1,4 +1,4 @@
|
||||
package basic
|
||||
package basic1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -7,14 +7,10 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 使用gopsutil查询可能会特别慢,执行命令查询反而更快
|
||||
// TODO
|
||||
// 迁移Shell的完整检测逻辑使用执行命令的方式查询,最后都失败才使用gopsutil查询
|
||||
|
||||
// 本包不在main中使用,仅做测试使用,真正调用的在 utils 中的 BasicsAndSecurityCheck
|
||||
func Basic(language string) {
|
||||
ipInfo, _, _ := network.NetworkCheck("both", false, language)
|
||||
res := system.CheckSystemInfo(language)
|
||||
//fmt.Println("--------------------------------------------------")
|
||||
fmt.Printf(strings.ReplaceAll(res+ipInfo, "\n\n", "\n"))
|
||||
//fmt.Println("--------------------------------------------------")
|
||||
systemInfo := system.CheckSystemInfo(language)
|
||||
basicInfo := strings.ReplaceAll(systemInfo+ipInfo, "\n\n", "\n")
|
||||
fmt.Printf(basicInfo)
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"github.com/oneclickvirt/cputest/cpu"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func CpuTest(language, testMethod, testThread string) {
|
||||
@@ -31,5 +32,8 @@ func CpuTest(language, testMethod, testThread string) {
|
||||
res = "Invalid test method specified.\n"
|
||||
}
|
||||
}
|
||||
if !strings.Contains(res, "\n") && res != "" {
|
||||
res += "\n"
|
||||
}
|
||||
fmt.Print(res)
|
||||
}
|
||||
|
@@ -4,9 +4,10 @@ import (
|
||||
"fmt"
|
||||
"github.com/oneclickvirt/disktest/disk"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func DiskTest(language, testMethod, testPath string, isMultiCheck bool) {
|
||||
func DiskTest(language, testMethod, testPath string, isMultiCheck bool, autoChange bool) {
|
||||
var res string
|
||||
if runtime.GOOS == "windows" {
|
||||
if testMethod != "winsat" && testMethod != "" {
|
||||
@@ -17,13 +18,13 @@ func DiskTest(language, testMethod, testPath string, isMultiCheck bool) {
|
||||
switch testMethod {
|
||||
case "fio":
|
||||
res = disk.FioTest(language, isMultiCheck, testPath)
|
||||
if res == "" {
|
||||
if res == "" && autoChange {
|
||||
res = "Fio test failed, switching to DD for testing.\n"
|
||||
res += disk.DDTest(language, isMultiCheck, testPath)
|
||||
}
|
||||
case "dd":
|
||||
res = disk.DDTest(language, isMultiCheck, testPath)
|
||||
if res == "" {
|
||||
if res == "" && autoChange {
|
||||
res = "DD test failed, switching to Fio for testing.\n"
|
||||
res += disk.FioTest(language, isMultiCheck, testPath)
|
||||
}
|
||||
@@ -32,6 +33,9 @@ func DiskTest(language, testMethod, testPath string, isMultiCheck bool) {
|
||||
}
|
||||
}
|
||||
//fmt.Println("--------------------------------------------------")
|
||||
if !strings.Contains(res, "\n") && res != "" {
|
||||
res += "\n"
|
||||
}
|
||||
fmt.Printf(res)
|
||||
//fmt.Println("--------------------------------------------------")
|
||||
}
|
||||
|
118
go.mod
118
go.mod
@@ -1,102 +1,116 @@
|
||||
module github.com/oneclickvirt/ecs
|
||||
|
||||
go 1.22.4
|
||||
go 1.23.4
|
||||
|
||||
require (
|
||||
github.com/oneclickvirt/CommonMediaTests v0.0.1-20240624094420
|
||||
github.com/oneclickvirt/UnlockTests v0.0.7-20240624115527
|
||||
github.com/oneclickvirt/backtrace v0.0.4-20240624090335
|
||||
github.com/oneclickvirt/basics v0.0.3-20240625075226
|
||||
github.com/oneclickvirt/cputest v0.0.2-20240624103336
|
||||
github.com/imroc/req/v3 v3.49.0
|
||||
github.com/oneclickvirt/CommonMediaTests v0.0.4-20240704024502
|
||||
github.com/oneclickvirt/UnlockTests v0.0.26-20250301144558
|
||||
github.com/oneclickvirt/backtrace v0.0.4-20240702140722
|
||||
github.com/oneclickvirt/basics v0.0.9-20250205131258
|
||||
github.com/oneclickvirt/cputest v0.0.10-20250316113043
|
||||
github.com/oneclickvirt/defaultset v0.0.2-20240624082446
|
||||
github.com/oneclickvirt/disktest v0.0.2-20240624145436
|
||||
github.com/oneclickvirt/memorytest v0.0.1-20240624151629
|
||||
github.com/oneclickvirt/nt3 v0.0.1-20240627070009
|
||||
github.com/oneclickvirt/portchecker v0.0.1-20240624155429
|
||||
github.com/oneclickvirt/security v0.0.1-20240625075931
|
||||
github.com/oneclickvirt/speedtest v0.0.4-20240629100548
|
||||
github.com/oneclickvirt/disktest v0.0.5-20250316104849
|
||||
github.com/oneclickvirt/gostun v0.0.3-20240702054621
|
||||
github.com/oneclickvirt/memorytest v0.0.4-20240820095126
|
||||
github.com/oneclickvirt/nt3 v0.0.4-20250118032755
|
||||
github.com/oneclickvirt/pingtest v0.0.5-20250308015024
|
||||
github.com/oneclickvirt/portchecker v0.0.3-20250118031146
|
||||
github.com/oneclickvirt/security v0.0.4-20240729065854
|
||||
github.com/oneclickvirt/speedtest v0.0.9-20250308142627
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/PuerkitoBio/goquery v1.9.2 // indirect
|
||||
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||
github.com/StackExchange/wmi v1.2.1 // indirect
|
||||
github.com/andybalholm/brotli v1.1.1 // indirect
|
||||
github.com/andybalholm/cascadia v1.3.2 // indirect
|
||||
github.com/cloudflare/circl v1.3.7 // indirect
|
||||
github.com/fatih/color v1.17.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/cloudflare/circl v1.5.0 // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.8.0 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/gofrs/uuid/v5 v5.2.0 // indirect
|
||||
github.com/google/gopacket v1.1.19 // indirect
|
||||
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 // indirect
|
||||
github.com/gopherjs/gopherjs v1.17.2 // indirect
|
||||
github.com/gorilla/websocket v1.5.1 // indirect
|
||||
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/huin/goupnp v1.2.0 // indirect
|
||||
github.com/imroc/req/v3 v3.43.7 // indirect
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
|
||||
github.com/jtolds/gls v4.20.0+incompatible // indirect
|
||||
github.com/klauspost/compress v1.17.7 // indirect
|
||||
github.com/jaypipes/ghw v0.12.0 // indirect
|
||||
github.com/jaypipes/pcidb v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/koron/go-ssdp v0.0.4 // indirect
|
||||
github.com/libp2p/go-nat v0.2.0 // indirect
|
||||
github.com/libp2p/go-netroute v0.2.1 // indirect
|
||||
github.com/lionsoul2014/ip2region v2.11.2+incompatible // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/magiconair/properties v1.8.9 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/miekg/dns v1.1.61 // indirect
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/moul/http2curl v1.0.0 // indirect
|
||||
github.com/nxtrace/NTrace-core v1.3.1 // indirect
|
||||
github.com/oneclickvirt/gostun v0.0.2-20240625025941 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.16.0 // indirect
|
||||
github.com/oschwald/maxminddb-golang v1.12.0 // indirect
|
||||
github.com/parnurzeal/gorequest v0.3.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
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.3.7 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.22.1 // indirect
|
||||
github.com/oschwald/maxminddb-golang v1.13.1 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/pion/dtls/v2 v2.2.7 // indirect
|
||||
github.com/pion/logging v0.2.2 // indirect
|
||||
github.com/pion/stun/v2 v2.0.0 // indirect
|
||||
github.com/pion/transport/v2 v2.2.1 // indirect
|
||||
github.com/pion/transport/v3 v3.0.1 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/quic-go/qpack v0.4.0 // indirect
|
||||
github.com/quic-go/quic-go v0.41.0 // indirect
|
||||
github.com/refraction-networking/utls v1.6.3 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||
github.com/prometheus-community/pro-bing v0.4.1 // indirect
|
||||
github.com/quic-go/qpack v0.5.1 // indirect
|
||||
github.com/quic-go/quic-go v0.48.2 // indirect
|
||||
github.com/refraction-networking/utls v1.6.7 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/rodaine/table v1.2.0 // indirect
|
||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||
github.com/rodaine/table v1.3.0 // indirect
|
||||
github.com/sagikazarmark/locafero v0.7.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/schollz/progressbar/v3 v3.14.4 // indirect
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
|
||||
github.com/shirou/gopsutil/v4 v4.24.5 // indirect
|
||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||
github.com/showwin/speedtest-go v1.7.7 // indirect
|
||||
github.com/smarty/assertions v1.16.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/spf13/afero v1.12.0 // indirect
|
||||
github.com/spf13/cast v1.7.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/viper v1.18.2 // indirect
|
||||
github.com/spf13/viper v1.19.0 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/tidwall/gjson v1.17.1 // indirect
|
||||
github.com/tidwall/gjson v1.18.0 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.14 // indirect
|
||||
github.com/tklauser/numcpus v0.8.0 // indirect
|
||||
github.com/tsosunchia/powclient v0.1.5 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
go.uber.org/mock v0.4.0 // indirect
|
||||
go.uber.org/mock v0.5.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/crypto v0.24.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
|
||||
golang.org/x/mod v0.17.0 // indirect
|
||||
golang.org/x/net v0.26.0 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/sys v0.21.0 // indirect
|
||||
golang.org/x/term v0.21.0 // indirect
|
||||
golang.org/x/text v0.16.0 // indirect
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||
golang.org/x/crypto v0.32.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect
|
||||
golang.org/x/mod v0.22.0 // indirect
|
||||
golang.org/x/net v0.34.0 // indirect
|
||||
golang.org/x/sync v0.10.0 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
golang.org/x/term v0.28.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/tools v0.29.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
howett.net/plist v1.0.0 // indirect
|
||||
)
|
||||
|
274
go.sum
274
go.sum
@@ -1,43 +1,46 @@
|
||||
github.com/PuerkitoBio/goquery v1.9.2 h1:4/wZksC3KgkQw7SQgkKotmKljk0M6V8TUvA8Wb4yPeE=
|
||||
github.com/PuerkitoBio/goquery v1.9.2/go.mod h1:GHPCaP0ODyyxqcNoFGYlAprUFH81NuRPd0GX3Zu2Mvk=
|
||||
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||
github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA=
|
||||
github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
|
||||
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
|
||||
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
|
||||
github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=
|
||||
github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
|
||||
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
|
||||
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
|
||||
github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys=
|
||||
github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/elazarl/goproxy v0.0.0-20240618083138-03be62527ccb h1:2SoxRauy2IqekRMggrQk3yNI5X6omSnk6ugVbFywwXs=
|
||||
github.com/elazarl/goproxy v0.0.0-20240618083138-03be62527ccb/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
|
||||
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
|
||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
||||
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
||||
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/gofrs/uuid/v5 v5.2.0 h1:qw1GMx6/y8vhVsx626ImfKMuS5CvJmhIKKtuyvfajMM=
|
||||
github.com/gofrs/uuid/v5 v5.2.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 h1:y3N7Bm7Y9/CtpiVkw/ZWj6lSlDF3F74SfKwfTCer72Q=
|
||||
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
|
||||
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
|
||||
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
||||
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
|
||||
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
|
||||
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
@@ -47,15 +50,20 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/huin/goupnp v1.2.0 h1:uOKW26NG1hsSSbXIZ1IR7XP9Gjd1U8pnLaCMgntmkmY=
|
||||
github.com/huin/goupnp v1.2.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
|
||||
github.com/imroc/req/v3 v3.43.7 h1:dOcNb9n0X83N5/5/AOkiU+cLhzx8QFXjv5MhikazzQA=
|
||||
github.com/imroc/req/v3 v3.43.7/go.mod h1:SQIz5iYop16MJxbo8ib+4LnostGCok8NQf8ToyQc2xA=
|
||||
github.com/imroc/req/v3 v3.49.0 h1:5Rac2qvz7Dq0E3PeBo/c2szV3hagPQIGLoHtfBmYhu4=
|
||||
github.com/imroc/req/v3 v3.49.0/go.mod h1:XZf4t94DNJzcA0UOBlA68hmSrWsAyvN407ADdH4mzCA=
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
|
||||
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/jaypipes/ghw v0.12.0 h1:xU2/MDJfWmBhJnujHY9qwXQLs3DBsf0/Xa9vECY0Tho=
|
||||
github.com/jaypipes/ghw v0.12.0/go.mod h1:jeJGbkRB2lL3/gxYzNYzEDETV1ZJ56OKr+CSeSEym+g=
|
||||
github.com/jaypipes/pcidb v1.0.0 h1:vtZIfkiCUE42oYbJS0TAq9XSfSmcsgo9IdxSm9qzYU8=
|
||||
github.com/jaypipes/pcidb v1.0.0/go.mod h1:TnYUvqhPBzCKnH34KrIX22kAeEbDCSRJ9cqLRCuNDfk=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
|
||||
github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg=
|
||||
github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||
github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0=
|
||||
github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
@@ -68,61 +76,67 @@ github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9t
|
||||
github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ=
|
||||
github.com/lionsoul2014/ip2region v2.11.2+incompatible h1:+VRsGcrHz8ewXI/2UzTptJlACsxD/p4xCxuql4u2nKU=
|
||||
github.com/lionsoul2014/ip2region v2.11.2+incompatible/go.mod h1:+ZBN7PBoh5gG6/y0ZQ85vJDBe21WnfbRrQQwTfliJJI=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||
github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM=
|
||||
github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs=
|
||||
github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ=
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs=
|
||||
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
|
||||
github.com/nxtrace/NTrace-core v1.3.1 h1:f4z5UaZEuhUP/g6xElpZ2bo+guWITJVrMKrJTqd27oc=
|
||||
github.com/nxtrace/NTrace-core v1.3.1/go.mod h1:0Px/Zc60qk6cssmP+yv4kstFxvX9sXqDduoVqBO+qf8=
|
||||
github.com/oneclickvirt/CommonMediaTests v0.0.1-20240624094420 h1:CBsjuTpAtangTNkfLQDWEDPz3VcBjGHd8WCtifCmTlI=
|
||||
github.com/oneclickvirt/CommonMediaTests v0.0.1-20240624094420/go.mod h1:DAmFPRjFV5p9fEzUUSml5jJGn2f1NZJQCzTxITHDjc4=
|
||||
github.com/oneclickvirt/UnlockTests v0.0.7-20240624115527 h1:rMC+aLDkvOe9K+AXjUt/IMAOx1LieyBv6DN/0/2ww7Q=
|
||||
github.com/oneclickvirt/UnlockTests v0.0.7-20240624115527/go.mod h1:HP3CvAS+AJWxxY+BVbxIOlvaQ87YOSge89vAMG52b5o=
|
||||
github.com/oneclickvirt/backtrace v0.0.4-20240624090335 h1:0LP5KyA6GLlqQAtOF0uyBSAykHJrzOA96Eb87qUhGQw=
|
||||
github.com/oneclickvirt/backtrace v0.0.4-20240624090335/go.mod h1:zvsC7xY/WZqs5KL2JB967OVnuqjNbxu9bW6wXRLo5h8=
|
||||
github.com/oneclickvirt/basics v0.0.3-20240625075226 h1:K9VriCHIYnXPZXBSn9PRQX+jBS6AIFH8tBVb/i8VGAw=
|
||||
github.com/oneclickvirt/basics v0.0.3-20240625075226/go.mod h1:dTB+/oyFQYfTYX55rFJVWatum5F9g62zjfmHCM6Vj1s=
|
||||
github.com/oneclickvirt/cputest v0.0.2-20240624103336 h1:7rrVqE1ODzuItuAXcU1/w4lUOxD7hXXB+c2weoO4eZk=
|
||||
github.com/oneclickvirt/cputest v0.0.2-20240624103336/go.mod h1:wh4fGT3KFG9qztew5eBL9EfWr8WeZPBLsq60ZzudU4g=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/nxtrace/NTrace-core v1.3.7 h1:ZnTbPrPqpyeraCvUyNbQTNyl4Gz3NRQDh06WdIIHh90=
|
||||
github.com/nxtrace/NTrace-core v1.3.7/go.mod h1:aW2owz9I+W5i+gJEDmnWli75mB+fuO4UTwdOPMcQHpE=
|
||||
github.com/oneclickvirt/CommonMediaTests v0.0.4-20240704024502 h1:hRIYJ2uEp2N3AH5bP5X6bwfdwWfZQO/2WoqpUJ8+WsY=
|
||||
github.com/oneclickvirt/CommonMediaTests v0.0.4-20240704024502/go.mod h1:DAmFPRjFV5p9fEzUUSml5jJGn2f1NZJQCzTxITHDjc4=
|
||||
github.com/oneclickvirt/UnlockTests v0.0.26-20250301144558 h1:CE4RKKEXxquXMEmOdiT8XTQvrJHDZdEr+xMFmx3Cw3E=
|
||||
github.com/oneclickvirt/UnlockTests v0.0.26-20250301144558/go.mod h1:yXWIZB6iLS88pEd9m4QJi1GENn+7I91zA72y5ONz2Oc=
|
||||
github.com/oneclickvirt/backtrace v0.0.4-20240702140722 h1:UJ/VWf+ZbhGarc9HcHMIyenpmX+b2LxkXu0hlLk3Gxs=
|
||||
github.com/oneclickvirt/backtrace v0.0.4-20240702140722/go.mod h1:zvsC7xY/WZqs5KL2JB967OVnuqjNbxu9bW6wXRLo5h8=
|
||||
github.com/oneclickvirt/basics v0.0.9-20250205131258 h1:LytqWIVlzT1ZS/thB8ZXk7tEpoaj+i6pBQBtACziBjc=
|
||||
github.com/oneclickvirt/basics v0.0.9-20250205131258/go.mod h1:fUdVpU8gdjaZsTCyqnQBAbHc9BbbN8Fxr3sGPKooUpU=
|
||||
github.com/oneclickvirt/cputest v0.0.10-20250316113043 h1:0IH4TlPWXyvB8D3+/DTRIapFdzlggPW12flPT24wqyk=
|
||||
github.com/oneclickvirt/cputest v0.0.10-20250316113043/go.mod h1:MmaHN9+XMntI3rLycwj8Ne31fG18IfNoa8N2utDK1CY=
|
||||
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.2-20240624145436 h1:c3bt6kB3FKtrMP/tGUIQWTadoiZwP9zcUkaSdsPF9mQ=
|
||||
github.com/oneclickvirt/disktest v0.0.2-20240624145436/go.mod h1:x7VAJF0Ks05FyE4BI5xedXNKmwbeXfp8GCRALAIlueI=
|
||||
github.com/oneclickvirt/gostun v0.0.2-20240625025941 h1:h+ZL8jkjXR6QE0qEX34FjWTv89+lNj2fEkWx5Agpgzc=
|
||||
github.com/oneclickvirt/gostun v0.0.2-20240625025941/go.mod h1:f7DPEXAxbmwXSW33dbxtb0/KzqvOBWhTs2Or5xBerQA=
|
||||
github.com/oneclickvirt/memorytest v0.0.1-20240624151629 h1:2rJAB3gFGlFPocIb/WRVWYqs4nr2jGYokfDOgqFicD4=
|
||||
github.com/oneclickvirt/memorytest v0.0.1-20240624151629/go.mod h1:+YNzy+NeVg61d0kNwSyVDqHyVtKzjuRe1NvMzsDLg0I=
|
||||
github.com/oneclickvirt/nt3 v0.0.1-20240627070009 h1:020pqkdGDnkIIpyNbbS1sjG1uIl3GgjeNgVqJzAw0ng=
|
||||
github.com/oneclickvirt/nt3 v0.0.1-20240627070009/go.mod h1:Vb724PgpP17W09mLw5I2UZZAuYbY8WwGlKZdxRDFr0Y=
|
||||
github.com/oneclickvirt/portchecker v0.0.1-20240624155429 h1:+wapaOcFrg1iWJDhBKThDzppyIMY7hWxK7F5RBkZg4o=
|
||||
github.com/oneclickvirt/portchecker v0.0.1-20240624155429/go.mod h1:HQxSTrqM8/QFqHMTBZ7S8H9eEO5FkUXU1eb7ZX5Mk+k=
|
||||
github.com/oneclickvirt/security v0.0.1-20240625075931 h1:Vj1Wq/JVcqYpfqUWRtsITbz3zM4HxnLC0iPxxA6akP0=
|
||||
github.com/oneclickvirt/security v0.0.1-20240625075931/go.mod h1:6bjZjpYJ8M3aRIcLP61b0mjYRwvtWbYkvoGjS28Bdy4=
|
||||
github.com/oneclickvirt/speedtest v0.0.3-20240629093211 h1:SU1aGYLpszp3csg599PjlrI/u32KNlHC/FiCx2ucn6w=
|
||||
github.com/oneclickvirt/speedtest v0.0.3-20240629093211/go.mod h1:JNIxUbEJD12w81b7754RLHD55fsH6wHj+fCV2PqBDhk=
|
||||
github.com/oneclickvirt/speedtest v0.0.4-20240629100548 h1:DQA0R/EdtmLJrQBb9JvQBaBpcMgiGDvIHq+0quNZQQM=
|
||||
github.com/oneclickvirt/speedtest v0.0.4-20240629100548/go.mod h1:JNIxUbEJD12w81b7754RLHD55fsH6wHj+fCV2PqBDhk=
|
||||
github.com/onsi/ginkgo/v2 v2.16.0 h1:7q1w9frJDzninhXxjZd+Y/x54XNjG/UlRLIYPZafsPM=
|
||||
github.com/onsi/ginkgo/v2 v2.16.0/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
|
||||
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
|
||||
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
|
||||
github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs=
|
||||
github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY=
|
||||
github.com/parnurzeal/gorequest v0.3.0 h1:SoFyqCDC9COr1xuS6VA8fC8RU7XyrJZN2ona1kEX7FI=
|
||||
github.com/parnurzeal/gorequest v0.3.0/go.mod h1:3Kh2QUMJoqw3icWAecsyzkpY7UzRfDhbRdTjtNwNiUE=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||
github.com/oneclickvirt/disktest v0.0.5-20250316104849 h1:gmfXEsdThBEj6Nx5qNHtwQd5pEb1/54PZk91QtyzKak=
|
||||
github.com/oneclickvirt/disktest v0.0.5-20250316104849/go.mod h1:wIZy8G6Mbcy8Op8tc0HmJNpbJQQ5A15fvnUqMJXIdO0=
|
||||
github.com/oneclickvirt/gostun v0.0.3-20240702054621 h1:IE89eEYV9TJbF94SakQDAxTLIaqX+Tb6ZhJ/CCIP+90=
|
||||
github.com/oneclickvirt/gostun v0.0.3-20240702054621/go.mod h1:f7DPEXAxbmwXSW33dbxtb0/KzqvOBWhTs2Or5xBerQA=
|
||||
github.com/oneclickvirt/memorytest v0.0.4-20240820095126 h1:Il3rvWkrZy/6B2iO3HRe9039/qRllA4CzcZ/dI8aG2A=
|
||||
github.com/oneclickvirt/memorytest v0.0.4-20240820095126/go.mod h1:+YNzy+NeVg61d0kNwSyVDqHyVtKzjuRe1NvMzsDLg0I=
|
||||
github.com/oneclickvirt/nt3 v0.0.4-20250118032755 h1:phF5kngqoPnS6onIbKII9ndw/N5l3ciIgR7fK5mfSBk=
|
||||
github.com/oneclickvirt/nt3 v0.0.4-20250118032755/go.mod h1:lDpHmjWwLZd6pO8cZCwzrc5rwd8dK+TIYk+DGmRpSGg=
|
||||
github.com/oneclickvirt/pingtest v0.0.5-20250308015024 h1:AK+jEp6xq8AAuELtOmWG/yv5nEUZANlTmbpTLbOmx9M=
|
||||
github.com/oneclickvirt/pingtest v0.0.5-20250308015024/go.mod h1:d3Ntx5m9lMll3a/k3+2B+5emj//vgDh4/NHTxs2qQE8=
|
||||
github.com/oneclickvirt/portchecker v0.0.3-20250118031146 h1:tXTcpq8P3KgQupEZhPcAwdiyXYy//jXGb28bp4bSt4g=
|
||||
github.com/oneclickvirt/portchecker v0.0.3-20250118031146/go.mod h1:HQxSTrqM8/QFqHMTBZ7S8H9eEO5FkUXU1eb7ZX5Mk+k=
|
||||
github.com/oneclickvirt/security v0.0.4-20240729065854 h1:I27XtMUEHmXw1RN0jNDQmFqNdu6vL4v1g8UZtXiCuBY=
|
||||
github.com/oneclickvirt/security v0.0.4-20240729065854/go.mod h1:384ZpNE3H6T6rtl0QhA4eQn8xGw7tc0rLD8ZH47qNGc=
|
||||
github.com/oneclickvirt/speedtest v0.0.9-20250308142627 h1:HPUJ5LR2C3UkQT7jegG7rtiwJJchGUUpWsbTHn15xT0=
|
||||
github.com/oneclickvirt/speedtest v0.0.9-20250308142627/go.mod h1:zd5ZgIGslmtQLQehEfRjyumlvgDHTpCSMchKfKXoASI=
|
||||
github.com/onsi/ginkgo/v2 v2.22.1 h1:QW7tbJAUDyVDVOM5dFa7qaybo+CRfR7bemlQUN6Z8aM=
|
||||
github.com/onsi/ginkgo/v2 v2.22.1/go.mod h1:S6aTpoRsSq2cZOd+pssHAlKW/Q/jZt6cPrPlnj4a1xM=
|
||||
github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw=
|
||||
github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
|
||||
github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE=
|
||||
github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||
github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8=
|
||||
github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s=
|
||||
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
|
||||
@@ -138,59 +152,65 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
||||
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
||||
github.com/quic-go/quic-go v0.41.0 h1:aD8MmHfgqTURWNJy48IYFg2OnxwHT3JL7ahGs73lb4k=
|
||||
github.com/quic-go/quic-go v0.41.0/go.mod h1:qCkNjqczPEvgsOnxZ0eCD14lv+B2LHlFAB++CNOh9hA=
|
||||
github.com/refraction-networking/utls v1.6.3 h1:MFOfRN35sSx6K5AZNIoESsBuBxS2LCgRilRIdHb6fDc=
|
||||
github.com/refraction-networking/utls v1.6.3/go.mod h1:yil9+7qSl+gBwJqztoQseO6Pr3h62pQoY1lXiNR/FPs=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/prometheus-community/pro-bing v0.4.1 h1:aMaJwyifHZO0y+h8+icUz0xbToHbia0wdmzdVZ+Kl3w=
|
||||
github.com/prometheus-community/pro-bing v0.4.1/go.mod h1:aLsw+zqCaDoa2RLVVSX3+UiCkBBXTMtZC3c7EkfWnAE=
|
||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||
github.com/quic-go/quic-go v0.48.2 h1:wsKXZPeGWpMpCGSWqOcqpW2wZYic/8T3aqiOID0/KWE=
|
||||
github.com/quic-go/quic-go v0.48.2/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
|
||||
github.com/refraction-networking/utls v1.6.7 h1:zVJ7sP1dJx/WtVuITug3qYUq034cDq9B2MR1K67ULZM=
|
||||
github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rodaine/table v1.2.0 h1:38HEnwK4mKSHQJIkavVj+bst1TEY7j9zhLMWu4QJrMA=
|
||||
github.com/rodaine/table v1.2.0/go.mod h1:wejb/q/Yd4T/SVmBSRMr7GCq3KlcZp3gyNYdLSBhkaE=
|
||||
github.com/rodaine/table v1.3.0 h1:4/3S3SVkHnVZX91EHFvAMV7K42AnJ0XuymRR2C5HlGE=
|
||||
github.com/rodaine/table v1.3.0/go.mod h1:47zRsHar4zw0jgxGxL9YtFfs7EGN6B/TaS+/Dmk4WxU=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
|
||||
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
|
||||
github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo=
|
||||
github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||
github.com/schollz/progressbar/v3 v3.14.4 h1:W9ZrDSJk7eqmQhd3uxFNNcTr0QL+xuGNI9dEMrw0r74=
|
||||
github.com/schollz/progressbar/v3 v3.14.4/go.mod h1:aT3UQ7yGm+2ZjeXPqsjTenwL3ddUiuZ0kfQ/2tHlyNI=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/shirou/gopsutil/v4 v4.24.5 h1:gGsArG5K6vmsh5hcFOHaPm87UD003CaDMkAOweSQjhM=
|
||||
github.com/shirou/gopsutil/v4 v4.24.5/go.mod h1:aoebb2vxetJ/yIDZISmduFvVNPHqXQ9SEJwRXxkf0RA=
|
||||
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
||||
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
||||
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
|
||||
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
|
||||
github.com/showwin/speedtest-go v1.7.7 h1:VmK75SZOTKiuWjIVrs+mo7ZoKEw0utiGCvpnurS0olU=
|
||||
github.com/showwin/speedtest-go v1.7.7/go.mod h1:uLgdWCNarXxlYsL2E5TOZpCIwpgSWnEANZp7gfHXHu0=
|
||||
github.com/smarty/assertions v1.16.0 h1:EvHNkdRA4QHMrn75NZSoUQ/mAUXAYWfatfB01yTCzfY=
|
||||
github.com/smarty/assertions v1.16.0/go.mod h1:duaaFdCS0K9dnoM50iyek/eYINOZ64gbh1Xlf6LG7AI=
|
||||
github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY=
|
||||
github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60=
|
||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs=
|
||||
github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4=
|
||||
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
|
||||
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
|
||||
github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
|
||||
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
|
||||
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U=
|
||||
github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
|
||||
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
@@ -202,13 +222,15 @@ github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYg
|
||||
github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE=
|
||||
github.com/tsosunchia/powclient v0.1.5 h1:hpixFWoPbWSEC0zc9osSltyjtr1+SnhCueZVLkEpyyU=
|
||||
github.com/tsosunchia/powclient v0.1.5/go.mod h1:yNlzyq+w9llYZV+0q7nrX83ULy4ghq2mCjpTLJFJ2pg=
|
||||
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
||||
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
|
||||
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
||||
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
|
||||
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
@@ -218,16 +240,16 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
|
||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
|
||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
|
||||
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA=
|
||||
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
|
||||
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
@@ -236,30 +258,30 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
|
||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
@@ -267,32 +289,40 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
|
||||
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
|
||||
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE=
|
||||
golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
|
||||
google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=
|
||||
howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
|
||||
|
696
goecs.go
696
goecs.go
@@ -1,153 +1,625 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/oneclickvirt/CommonMediaTests/commediatests"
|
||||
unlocktestmodel "github.com/oneclickvirt/UnlockTests/model"
|
||||
backtraceori "github.com/oneclickvirt/backtrace/bk"
|
||||
basicmodel "github.com/oneclickvirt/basics/model"
|
||||
cputestmodel "github.com/oneclickvirt/cputest/model"
|
||||
disktestmodel "github.com/oneclickvirt/disktest/disk"
|
||||
"github.com/oneclickvirt/ecs/backtrace"
|
||||
"github.com/oneclickvirt/ecs/basic"
|
||||
"github.com/oneclickvirt/ecs/commediatest"
|
||||
"github.com/oneclickvirt/ecs/cputest"
|
||||
"github.com/oneclickvirt/ecs/disktest"
|
||||
"github.com/oneclickvirt/ecs/memorytest"
|
||||
"github.com/oneclickvirt/ecs/network"
|
||||
"github.com/oneclickvirt/ecs/ntrace"
|
||||
"github.com/oneclickvirt/ecs/port"
|
||||
"github.com/oneclickvirt/ecs/speedtest"
|
||||
"github.com/oneclickvirt/ecs/unlocktest"
|
||||
"github.com/oneclickvirt/ecs/utils"
|
||||
gostunmodel "github.com/oneclickvirt/gostun/model"
|
||||
memorytestmodel "github.com/oneclickvirt/memorytest/memory"
|
||||
nt3model "github.com/oneclickvirt/nt3/model"
|
||||
ptmodel "github.com/oneclickvirt/pingtest/model"
|
||||
"github.com/oneclickvirt/pingtest/pt"
|
||||
"github.com/oneclickvirt/portchecker/email"
|
||||
speedtestmodel "github.com/oneclickvirt/speedtest/model"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
func printCenteredTitle(title string, width int) {
|
||||
titleLength := utf8.RuneCountInString(title) // 计算字符串的字符数
|
||||
totalPadding := width - titleLength
|
||||
padding := totalPadding / 2
|
||||
paddingStr := strings.Repeat("-", padding)
|
||||
fmt.Println(paddingStr + title + paddingStr + strings.Repeat("-", totalPadding%2))
|
||||
var (
|
||||
ecsVersion = "v0.1.19"
|
||||
menuMode bool
|
||||
onlyChinaTest bool
|
||||
input, choice string
|
||||
showVersion bool
|
||||
enableLogger bool
|
||||
language string
|
||||
cpuTestMethod, cpuTestThreadMode string
|
||||
memoryTestMethod string
|
||||
diskTestMethod, diskTestPath string
|
||||
diskMultiCheck bool
|
||||
nt3CheckType, nt3Location string
|
||||
spNum int
|
||||
width = 82
|
||||
basicStatus, cpuTestStatus, memoryTestStatus, diskTestStatus bool
|
||||
commTestStatus, utTestStatus, securityTestStatus, emailTestStatus bool
|
||||
backtraceStatus, nt3Status, speedTestStatus, pingTestStatus bool
|
||||
autoChangeDiskTestMethod = true
|
||||
filePath = "goecs.txt"
|
||||
enabelUpload = true
|
||||
help bool
|
||||
goecsFlag = flag.NewFlagSet("goecs", flag.ContinueOnError)
|
||||
finish bool
|
||||
)
|
||||
|
||||
func getMenuChoice(language string) string {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
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:
|
||||
fmt.Println("\n程序在选择过程中被用户中断")
|
||||
os.Exit(0)
|
||||
case <-ctx.Done():
|
||||
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 "1", "2", "3", "4", "5", "6", "7", "8", "9", "10":
|
||||
return inChoice
|
||||
default:
|
||||
if language == "zh" {
|
||||
fmt.Println("无效的选项")
|
||||
} else {
|
||||
fmt.Println("Invalid choice")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if language == "zh" {
|
||||
fmt.Println("输入错误,请输入一个纯数字")
|
||||
} else {
|
||||
fmt.Println("Invalid input, please enter a number")
|
||||
}
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
var (
|
||||
ecsVersion = "2024.06.25"
|
||||
showVersion bool
|
||||
language string
|
||||
cpuTestMethod, cpuTestThread string
|
||||
memoryTestMethod string
|
||||
diskTestMethod, diskTestPath string
|
||||
diskMultiCheck bool
|
||||
nt3CheckType, nt3Location string
|
||||
spNum int
|
||||
width = 84
|
||||
)
|
||||
flag.BoolVar(&showVersion, "v", false, "Show version information")
|
||||
flag.StringVar(&language, "l", "zh", "Specify language (supported: en, zh)")
|
||||
flag.StringVar(&cpuTestMethod, "cpum", "sysbench", "Specify CPU test method (supported: sysbench, geekbench, winsat)")
|
||||
flag.StringVar(&cpuTestThread, "cput", "", "Specify CPU test thread count (supported: 1, 2, ...)")
|
||||
flag.StringVar(&memoryTestMethod, "memorym", "", "Specify Memory test method (supported: sysbench, dd, winsat)")
|
||||
flag.StringVar(&diskTestMethod, "diskm", "", "Specify Disk test method (supported: sysbench, dd, winsat)")
|
||||
flag.StringVar(&diskTestPath, "diskp", "", "Specify Disk test path, example: -diskp /root")
|
||||
flag.BoolVar(&diskMultiCheck, "diskmc", false, "Enable multiple disk checks, example: -diskmc=false")
|
||||
flag.Parse()
|
||||
if language == "zh" {
|
||||
flag.StringVar(&nt3Location, "nt3loc", "GZ", "指定三网回程路由检测的地址,支持 GZ, SH, BJ, CD 对应 广州,上海,北京,成都")
|
||||
flag.StringVar(&nt3CheckType, "nt3t", "ipv4", "指定三网回程路由检测的类型,支持 both, ipv4, ipv6")
|
||||
goecsFlag.BoolVar(&help, "h", false, "Show help information")
|
||||
goecsFlag.BoolVar(&showVersion, "v", false, "Display version information")
|
||||
goecsFlag.BoolVar(&menuMode, "menu", true, "Enable/Disable menu mode, disable example: -menu=false") // true 默认启用菜单栏模式
|
||||
goecsFlag.StringVar(&language, "l", "zh", "Set language (supported: en, zh)")
|
||||
goecsFlag.BoolVar(&basicStatus, "basic", true, "Enable/Disable basic test")
|
||||
goecsFlag.BoolVar(&cpuTestStatus, "cpu", true, "Enable/Disable CPU test")
|
||||
goecsFlag.BoolVar(&memoryTestStatus, "memory", true, "Enable/Disable memory test")
|
||||
goecsFlag.BoolVar(&diskTestStatus, "disk", true, "Enable/Disable disk test")
|
||||
goecsFlag.BoolVar(&commTestStatus, "comm", true, "Enable/Disable common media test")
|
||||
goecsFlag.BoolVar(&utTestStatus, "ut", true, "Enable/Disable unlock media test")
|
||||
goecsFlag.BoolVar(&securityTestStatus, "security", true, "Enable/Disable security test")
|
||||
goecsFlag.BoolVar(&emailTestStatus, "email", true, "Enable/Disable email port test")
|
||||
goecsFlag.BoolVar(&backtraceStatus, "backtrace", true, "Enable/Disable backtrace test (in 'en' language or on windows it always false)")
|
||||
goecsFlag.BoolVar(&nt3Status, "nt3", true, "Enable/Disable NT3 test (in 'en' language or on windows it always false)")
|
||||
goecsFlag.BoolVar(&speedTestStatus, "speed", true, "Enable/Disable speed test")
|
||||
goecsFlag.StringVar(&cpuTestMethod, "cpum", "sysbench", "Set CPU test method (supported: sysbench, geekbench, winsat)")
|
||||
goecsFlag.StringVar(&cpuTestThreadMode, "cput", "multi", "Set CPU test thread mode (supported: single, multi)")
|
||||
goecsFlag.StringVar(&memoryTestMethod, "memorym", "sysbench", "Set memory test method (supported: sysbench, dd, winsat)")
|
||||
goecsFlag.StringVar(&diskTestMethod, "diskm", "fio", "Set disk test method (supported: fio, dd, winsat)")
|
||||
goecsFlag.StringVar(&diskTestPath, "diskp", "", "Set disk test path, e.g., -diskp /root")
|
||||
goecsFlag.BoolVar(&diskMultiCheck, "diskmc", false, "Enable/Disable multiple disk checks, e.g., -diskmc=false")
|
||||
goecsFlag.StringVar(&nt3Location, "nt3loc", "GZ", "Specify NT3 test location (supported: GZ, SH, BJ, CD for Guangzhou, Shanghai, Beijing, Chengdu)")
|
||||
goecsFlag.StringVar(&nt3CheckType, "nt3t", "ipv4", "Set NT3 test type (supported: both, ipv4, ipv6)")
|
||||
goecsFlag.IntVar(&spNum, "spnum", 2, "Set the number of servers per operator for speed test")
|
||||
goecsFlag.BoolVar(&enableLogger, "log", false, "Enable/Disable logging in the current path")
|
||||
goecsFlag.BoolVar(&enabelUpload, "upload", true, "Enable/Disable upload the result")
|
||||
goecsFlag.Parse(os.Args[1:])
|
||||
if help {
|
||||
fmt.Printf("Usage: %s [options]\n", os.Args[0])
|
||||
goecsFlag.PrintDefaults()
|
||||
return
|
||||
}
|
||||
flag.IntVar(&spNum, "spnum", 2, "Specify speedtest each operator servers num")
|
||||
flag.Parse()
|
||||
if showVersion {
|
||||
fmt.Println(ecsVersion)
|
||||
return
|
||||
}
|
||||
startTime := time.Now()
|
||||
if language == "zh" {
|
||||
printCenteredTitle("融合怪测试", width)
|
||||
fmt.Printf("版本:%s\n", ecsVersion)
|
||||
fmt.Println("测评频道: https://t.me/vps_reviews\nGo项目地址:https://github.com/oneclickvirt/ecs\nShell项目地址:https://github.com/spiritLHLS/ecs")
|
||||
printCenteredTitle("基础信息", width)
|
||||
basic.Basic(language)
|
||||
printCenteredTitle(fmt.Sprintf("CPU测试-通过%s测试", cpuTestMethod), width)
|
||||
cputest.CpuTest(language, cpuTestMethod, cpuTestThread)
|
||||
printCenteredTitle(fmt.Sprintf("内存测试-通过%s测试", cpuTestMethod), width)
|
||||
memorytest.MemoryTest(language, memoryTestMethod)
|
||||
printCenteredTitle(fmt.Sprintf("硬盘测试-通过%s测试", diskTestMethod), width)
|
||||
disktest.DiskTest(language, diskTestMethod, diskTestPath, diskMultiCheck)
|
||||
printCenteredTitle("御三家流媒体解锁", width)
|
||||
commediatest.ComMediaTest(language)
|
||||
printCenteredTitle("跨国流媒体解锁", width)
|
||||
unlocktest.MediaTest(language)
|
||||
printCenteredTitle("IP质量检测", width)
|
||||
ipInfo, securityInfo, _ := network.NetworkCheck("both", true, language)
|
||||
fmt.Printf(securityInfo)
|
||||
printCenteredTitle("邮件端口检测", width)
|
||||
port.EmailCheck()
|
||||
if enableLogger {
|
||||
gostunmodel.EnableLoger = true
|
||||
basicmodel.EnableLoger = true
|
||||
cputestmodel.EnableLoger = true
|
||||
memorytestmodel.EnableLoger = true
|
||||
disktestmodel.EnableLoger = true
|
||||
commediatests.EnableLoger = true
|
||||
unlocktestmodel.EnableLoger = true
|
||||
ptmodel.EnableLoger = true
|
||||
backtraceori.EnableLoger = true
|
||||
nt3model.EnableLoger = true
|
||||
speedtestmodel.EnableLoger = true
|
||||
}
|
||||
go func() {
|
||||
http.Get("https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2Foneclickvirt%2Fecs&count_bg=%2357DEFF&title_bg=%23000000&icon=cliqz.svg&icon_color=%23E7E7E7&title=hits&edge_flat=false")
|
||||
}()
|
||||
if menuMode {
|
||||
basicStatus, cpuTestStatus, memoryTestStatus, diskTestStatus = false, false, false, false
|
||||
commTestStatus, utTestStatus, securityTestStatus, emailTestStatus = false, false, false, false
|
||||
backtraceStatus, nt3Status, speedTestStatus = false, false, false
|
||||
autoChangeDiskTestMethod = true
|
||||
switch language {
|
||||
case "zh":
|
||||
fmt.Println("VPS融合怪版本: ", ecsVersion)
|
||||
fmt.Println("1. 融合怪完全体")
|
||||
fmt.Println("2. 极简版(系统信息+CPU+内存+磁盘+测速节点5个)")
|
||||
fmt.Println("3. 精简版(系统信息+CPU+内存+磁盘+常用流媒体+路由+测速节点5个)")
|
||||
fmt.Println("4. 精简网络版(系统信息+CPU+内存+磁盘+回程+路由+测速节点5个)")
|
||||
fmt.Println("5. 精简解锁版(系统信息+CPU+内存+磁盘IO+御三家+常用流媒体+测速节点5个)")
|
||||
fmt.Println("6. 网络单项(IP质量检测+三网回程+三网路由与延迟+测速节点11个)")
|
||||
fmt.Println("7. 解锁单项(御三家解锁+常用流媒体解锁)")
|
||||
fmt.Println("8. 硬件单项(系统信息+CPU+内存+dd磁盘测试+fio磁盘测试)")
|
||||
fmt.Println("9. IP质量检测(15个数据库的IP检测+邮件端口检测)")
|
||||
fmt.Println("10. 三网回程线路+广州三网路由+全国三网延迟")
|
||||
case "en":
|
||||
fmt.Println("VPS Fusion Monster Test Version: ", ecsVersion)
|
||||
fmt.Println("1. VPS Fusion Monster Test Comprehensive Test Suite")
|
||||
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 + 5 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)")
|
||||
}
|
||||
Loop:
|
||||
for {
|
||||
choice = getMenuChoice(language)
|
||||
switch choice {
|
||||
case "1":
|
||||
basicStatus = true
|
||||
cpuTestStatus = true
|
||||
memoryTestStatus = true
|
||||
diskTestStatus = true
|
||||
commTestStatus = true
|
||||
utTestStatus = true
|
||||
securityTestStatus = true
|
||||
emailTestStatus = true
|
||||
backtraceStatus = true
|
||||
nt3Status = true
|
||||
speedTestStatus = true
|
||||
onlyChinaTest = utils.CheckChina(enableLogger)
|
||||
break Loop
|
||||
case "2":
|
||||
basicStatus = true
|
||||
cpuTestStatus = true
|
||||
memoryTestStatus = true
|
||||
diskTestStatus = true
|
||||
speedTestStatus = true
|
||||
break Loop
|
||||
case "3":
|
||||
basicStatus = true
|
||||
cpuTestStatus = true
|
||||
memoryTestStatus = true
|
||||
diskTestStatus = true
|
||||
utTestStatus = true
|
||||
nt3Status = true
|
||||
speedTestStatus = true
|
||||
break Loop
|
||||
case "4":
|
||||
basicStatus = true
|
||||
cpuTestStatus = true
|
||||
memoryTestStatus = true
|
||||
diskTestStatus = true
|
||||
backtraceStatus = true
|
||||
nt3Status = true
|
||||
speedTestStatus = true
|
||||
break Loop
|
||||
case "5":
|
||||
basicStatus = true
|
||||
cpuTestStatus = true
|
||||
memoryTestStatus = true
|
||||
diskTestStatus = true
|
||||
commTestStatus = true
|
||||
utTestStatus = true
|
||||
speedTestStatus = true
|
||||
break Loop
|
||||
case "6":
|
||||
securityTestStatus = true
|
||||
speedTestStatus = true
|
||||
backtraceStatus = true
|
||||
nt3Status = true
|
||||
break Loop
|
||||
case "7":
|
||||
commTestStatus = true
|
||||
utTestStatus = true
|
||||
enabelUpload = false
|
||||
break Loop
|
||||
case "8":
|
||||
basicStatus = true
|
||||
cpuTestStatus = true
|
||||
memoryTestStatus = true
|
||||
diskTestStatus = true
|
||||
securityTestStatus = false
|
||||
autoChangeDiskTestMethod = false
|
||||
break Loop
|
||||
case "9":
|
||||
securityTestStatus = true
|
||||
emailTestStatus = true
|
||||
break Loop
|
||||
case "10":
|
||||
backtraceStatus = true
|
||||
nt3Status = true
|
||||
pingTestStatus = true
|
||||
enabelUpload = false
|
||||
break Loop
|
||||
default:
|
||||
if language == "zh" {
|
||||
fmt.Println("无效的选项")
|
||||
} else {
|
||||
fmt.Println("Invalid choice")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if language == "en" {
|
||||
backtraceStatus = false
|
||||
nt3Status = false
|
||||
}
|
||||
if !enabelUpload {
|
||||
securityTestStatus = false
|
||||
}
|
||||
var (
|
||||
startTime time.Time
|
||||
wg1, wg2, wg3 sync.WaitGroup
|
||||
basicInfo, securityInfo, emailInfo, mediaInfo, ptInfo string
|
||||
output, tempOutput string
|
||||
)
|
||||
// 信号处理部分
|
||||
uploadDone := make(chan bool, 1)
|
||||
sig := make(chan os.Signal, 1)
|
||||
signal.Notify(sig, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
|
||||
// 启动一个goroutine来等待信号
|
||||
go func() {
|
||||
startTime = time.Now()
|
||||
select {
|
||||
case <-sig:
|
||||
if !finish {
|
||||
endTime := time.Now()
|
||||
duration := endTime.Sub(startTime)
|
||||
minutes := int(duration.Minutes())
|
||||
seconds := int(duration.Seconds()) % 60
|
||||
currentTime := time.Now().Format("Mon Jan 2 15:04:05 MST 2006")
|
||||
var mu sync.Mutex
|
||||
mu.Lock()
|
||||
output = utils.PrintAndCapture(func() {
|
||||
utils.PrintCenteredTitle("", width)
|
||||
fmt.Printf("Cost Time : %d min %d sec\n", minutes, seconds)
|
||||
fmt.Printf("Current Time : %s\n", currentTime)
|
||||
utils.PrintCenteredTitle("", width)
|
||||
}, tempOutput, output)
|
||||
mu.Unlock()
|
||||
// 创建一个通道来传递上传结果
|
||||
resultChan := make(chan struct {
|
||||
httpURL string
|
||||
httpsURL string
|
||||
}, 1) // 使用带缓冲的通道,避免可能的阻塞
|
||||
// 启动上传
|
||||
go func() {
|
||||
httpURL, httpsURL := utils.ProcessAndUpload(output, filePath, enabelUpload)
|
||||
resultChan <- struct {
|
||||
httpURL string
|
||||
httpsURL string
|
||||
}{httpURL, httpsURL}
|
||||
uploadDone <- true
|
||||
}()
|
||||
// 等待上传完成或超时
|
||||
select {
|
||||
case result := <-resultChan:
|
||||
if result.httpURL != "" || result.httpsURL != "" {
|
||||
if language == "en" {
|
||||
fmt.Printf("Upload successfully!\nHttp URL: %s\nHttps URL: %s\n", result.httpURL, result.httpsURL)
|
||||
} else {
|
||||
fmt.Printf("上传成功!\nHttp URL: %s\nHttps URL: %s\n", result.httpURL, result.httpsURL)
|
||||
}
|
||||
}
|
||||
// 给打印操作一些时间完成
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
os.Exit(0)
|
||||
case <-time.After(30 * time.Second):
|
||||
fmt.Println("上传超时,程序退出")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
}()
|
||||
switch language {
|
||||
case "zh":
|
||||
output = utils.PrintAndCapture(func() {
|
||||
utils.PrintHead(language, width, ecsVersion)
|
||||
if basicStatus || securityTestStatus {
|
||||
if basicStatus {
|
||||
utils.PrintCenteredTitle("系统基础信息", width)
|
||||
}
|
||||
basicInfo, securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, nt3CheckType, securityTestStatus)
|
||||
if basicStatus {
|
||||
fmt.Printf(basicInfo)
|
||||
} else if (input == "6" || input == "9") && securityTestStatus {
|
||||
scanner := bufio.NewScanner(strings.NewReader(basicInfo))
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if strings.Contains(line, "IPV") {
|
||||
fmt.Println(line)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, tempOutput, output)
|
||||
output = utils.PrintAndCapture(func() {
|
||||
if cpuTestStatus {
|
||||
utils.PrintCenteredTitle(fmt.Sprintf("CPU测试-通过%s测试", cpuTestMethod), width)
|
||||
cputest.CpuTest(language, cpuTestMethod, cpuTestThreadMode)
|
||||
}
|
||||
}, tempOutput, output)
|
||||
output = utils.PrintAndCapture(func() {
|
||||
if memoryTestStatus {
|
||||
utils.PrintCenteredTitle(fmt.Sprintf("内存测试-通过%s测试", memoryTestMethod), width)
|
||||
memorytest.MemoryTest(language, memoryTestMethod)
|
||||
}
|
||||
}, tempOutput, output)
|
||||
output = utils.PrintAndCapture(func() {
|
||||
if diskTestStatus && autoChangeDiskTestMethod {
|
||||
utils.PrintCenteredTitle(fmt.Sprintf("硬盘测试-通过%s测试", diskTestMethod), width)
|
||||
disktest.DiskTest(language, diskTestMethod, diskTestPath, diskMultiCheck, autoChangeDiskTestMethod)
|
||||
} else if diskTestStatus && !autoChangeDiskTestMethod {
|
||||
utils.PrintCenteredTitle(fmt.Sprintf("硬盘测试-通过%s测试", "dd"), width)
|
||||
disktest.DiskTest(language, "dd", diskTestPath, diskMultiCheck, autoChangeDiskTestMethod)
|
||||
utils.PrintCenteredTitle(fmt.Sprintf("硬盘测试-通过%s测试", "fio"), width)
|
||||
disktest.DiskTest(language, "fio", diskTestPath, diskMultiCheck, autoChangeDiskTestMethod)
|
||||
}
|
||||
}, tempOutput, output)
|
||||
if onlyChinaTest || pingTestStatus {
|
||||
wg3.Add(1)
|
||||
go func() {
|
||||
defer wg3.Done()
|
||||
ptInfo = pt.PingTest()
|
||||
}()
|
||||
}
|
||||
if emailTestStatus {
|
||||
wg2.Add(1)
|
||||
go func() {
|
||||
defer wg2.Done()
|
||||
emailInfo = email.EmailCheck()
|
||||
}()
|
||||
}
|
||||
if utTestStatus && !onlyChinaTest {
|
||||
wg1.Add(1)
|
||||
go func() {
|
||||
defer wg1.Done()
|
||||
mediaInfo = unlocktest.MediaTest(language)
|
||||
}()
|
||||
}
|
||||
output = utils.PrintAndCapture(func() {
|
||||
if commTestStatus && !onlyChinaTest {
|
||||
utils.PrintCenteredTitle("御三家流媒体解锁", width)
|
||||
commediatest.ComMediaTest(language)
|
||||
}
|
||||
}, tempOutput, output)
|
||||
output = utils.PrintAndCapture(func() {
|
||||
if utTestStatus && !onlyChinaTest {
|
||||
utils.PrintCenteredTitle("跨国流媒体解锁", width)
|
||||
wg1.Wait()
|
||||
fmt.Printf(mediaInfo)
|
||||
}
|
||||
}, tempOutput, output)
|
||||
output = utils.PrintAndCapture(func() {
|
||||
if securityTestStatus {
|
||||
utils.PrintCenteredTitle("IP质量检测", width)
|
||||
fmt.Printf(securityInfo)
|
||||
}
|
||||
}, tempOutput, output)
|
||||
output = utils.PrintAndCapture(func() {
|
||||
if emailTestStatus {
|
||||
utils.PrintCenteredTitle("邮件端口检测", width)
|
||||
wg2.Wait()
|
||||
fmt.Println(emailInfo)
|
||||
}
|
||||
}, tempOutput, output)
|
||||
if runtime.GOOS != "windows" {
|
||||
output = utils.PrintAndCapture(func() {
|
||||
if backtraceStatus && !onlyChinaTest {
|
||||
utils.PrintCenteredTitle("三网回程线路检测", width)
|
||||
backtrace.BackTrace()
|
||||
}
|
||||
}, tempOutput, output)
|
||||
// nexttrace 在win上不支持检测,报错 bind: An invalid argument was supplied.
|
||||
printCenteredTitle("三网回程", width)
|
||||
backtrace.BackTrace()
|
||||
output = utils.PrintAndCapture(func() {
|
||||
if nt3Status && !onlyChinaTest {
|
||||
utils.PrintCenteredTitle("三网回程路由检测", width)
|
||||
ntrace.TraceRoute3(language, nt3Location, nt3CheckType)
|
||||
}
|
||||
}, tempOutput, output)
|
||||
output = utils.PrintAndCapture(func() {
|
||||
if onlyChinaTest || pingTestStatus {
|
||||
utils.PrintCenteredTitle("三网ICMP的PING值检测", width)
|
||||
wg3.Wait()
|
||||
fmt.Println(ptInfo)
|
||||
}
|
||||
}, tempOutput, output)
|
||||
}
|
||||
printCenteredTitle("三网回程路由", width)
|
||||
if nt3CheckType == "" && strings.Contains(ipInfo, "IPV4") {
|
||||
nt3CheckType = "ipv4"
|
||||
} else if nt3CheckType == "" && strings.Contains(ipInfo, "IPV6") {
|
||||
nt3CheckType = "ipv6"
|
||||
} else if nt3CheckType == "ipv4" && !strings.Contains(ipInfo, "IPV4") && strings.Contains(ipInfo, "IPV6") {
|
||||
nt3CheckType = "ipv6"
|
||||
} else if nt3CheckType == "ipv6" && !strings.Contains(ipInfo, "IPV6") && strings.Contains(ipInfo, "IPV4") {
|
||||
nt3CheckType = "ipv4"
|
||||
}
|
||||
ntrace.TraceRoute3(language, nt3Location, nt3CheckType)
|
||||
printCenteredTitle("就近节点测速", width)
|
||||
speedtest.ShowHead(language)
|
||||
speedtest.NearbySP()
|
||||
speedtest.CustomSP("net", "global", 4)
|
||||
speedtest.CustomSP("net", "cu", spNum)
|
||||
speedtest.CustomSP("net", "ct", spNum)
|
||||
speedtest.CustomSP("net", "cmcc", spNum)
|
||||
printCenteredTitle("", width)
|
||||
output = utils.PrintAndCapture(func() {
|
||||
if speedTestStatus {
|
||||
utils.PrintCenteredTitle("就近节点测速", width)
|
||||
speedtest.ShowHead(language)
|
||||
if choice == "1" || !menuMode {
|
||||
speedtest.NearbySP()
|
||||
speedtest.CustomSP("net", "global", 2, language)
|
||||
speedtest.CustomSP("net", "cu", spNum, language)
|
||||
speedtest.CustomSP("net", "ct", spNum, language)
|
||||
speedtest.CustomSP("net", "cmcc", spNum, language)
|
||||
} else if choice == "2" || choice == "3" || choice == "4" || choice == "5" {
|
||||
speedtest.CustomSP("net", "global", 4, language)
|
||||
} else if choice == "6" {
|
||||
speedtest.CustomSP("net", "global", 11, language)
|
||||
}
|
||||
}
|
||||
}, tempOutput, output)
|
||||
endTime := time.Now()
|
||||
duration := endTime.Sub(startTime)
|
||||
minutes := int(duration.Minutes())
|
||||
seconds := int(duration.Seconds()) % 60
|
||||
fmt.Printf("花费 : %d 分 %d 秒\n", minutes, seconds)
|
||||
currentTime := time.Now().Format("Mon Jan 2 15:04:05 MST 2006")
|
||||
fmt.Printf("时间 : %s\n", currentTime)
|
||||
printCenteredTitle("", width)
|
||||
} else if language == "en" {
|
||||
printCenteredTitle("Fusion Monster Test", width)
|
||||
fmt.Printf("Version: %s\n", ecsVersion)
|
||||
fmt.Println("Review Channel: https://t.me/vps_reviews\nGo Project URL: https://github.com/oneclickvirt/ecs\nShell Project URL: https://github.com/spiritLHLS/ecs")
|
||||
printCenteredTitle("Basic Information", width)
|
||||
basic.Basic(language)
|
||||
printCenteredTitle(fmt.Sprintf("CPU Test - %s Method", cpuTestMethod), width)
|
||||
cputest.CpuTest(language, cpuTestMethod, cpuTestThread)
|
||||
printCenteredTitle(fmt.Sprintf("Memory Test - %s Method", memoryTestMethod), width)
|
||||
memorytest.MemoryTest(language, memoryTestMethod)
|
||||
printCenteredTitle(fmt.Sprintf("Disk Test - %s Method", diskTestMethod), width)
|
||||
disktest.DiskTest(language, diskTestMethod, diskTestPath, diskMultiCheck)
|
||||
printCenteredTitle("The Three Families Streaming Media Unlock", width)
|
||||
commediatest.ComMediaTest(language)
|
||||
printCenteredTitle("Cross-Border Streaming Media Unlock", width)
|
||||
unlocktest.MediaTest(language)
|
||||
printCenteredTitle("IP Quality Check", width)
|
||||
_, securityInfo, _ := network.NetworkCheck("both", true, language)
|
||||
fmt.Printf(securityInfo)
|
||||
printCenteredTitle("Email Port Check", width)
|
||||
port.EmailCheck()
|
||||
//printCenteredTitle("Return Path Routing", width)
|
||||
printCenteredTitle("Nearby Node Speed Test", width)
|
||||
speedtest.ShowHead(language)
|
||||
speedtest.NearbySP()
|
||||
speedtest.CustomSP("net", "global", -1)
|
||||
printCenteredTitle("", width)
|
||||
output = utils.PrintAndCapture(func() {
|
||||
utils.PrintCenteredTitle("", width)
|
||||
fmt.Printf("花费 : %d 分 %d 秒\n", minutes, seconds)
|
||||
fmt.Printf("时间 : %s\n", currentTime)
|
||||
utils.PrintCenteredTitle("", width)
|
||||
}, tempOutput, output)
|
||||
case "en":
|
||||
output = utils.PrintAndCapture(func() {
|
||||
utils.PrintHead(language, width, ecsVersion)
|
||||
if basicStatus || securityTestStatus {
|
||||
if basicStatus {
|
||||
utils.PrintCenteredTitle("System-Basic-Information", width)
|
||||
}
|
||||
basicInfo, securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, nt3CheckType, securityTestStatus)
|
||||
if basicStatus {
|
||||
fmt.Printf(basicInfo)
|
||||
} else if (input == "6" || input == "9") && securityTestStatus {
|
||||
scanner := bufio.NewScanner(strings.NewReader(basicInfo))
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if strings.Contains(line, "IPV") {
|
||||
fmt.Println(line)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, tempOutput, output)
|
||||
output = utils.PrintAndCapture(func() {
|
||||
if cpuTestStatus {
|
||||
utils.PrintCenteredTitle(fmt.Sprintf("CPU-Test--%s-Method", cpuTestMethod), width)
|
||||
cputest.CpuTest(language, cpuTestMethod, cpuTestThreadMode)
|
||||
}
|
||||
}, tempOutput, output)
|
||||
output = utils.PrintAndCapture(func() {
|
||||
if memoryTestStatus {
|
||||
utils.PrintCenteredTitle(fmt.Sprintf("Memory-Test--%s-Method", memoryTestMethod), width)
|
||||
memorytest.MemoryTest(language, memoryTestMethod)
|
||||
}
|
||||
}, tempOutput, output)
|
||||
output = utils.PrintAndCapture(func() {
|
||||
if diskTestStatus && autoChangeDiskTestMethod {
|
||||
utils.PrintCenteredTitle(fmt.Sprintf("Disk-Test--%s-Method", diskTestMethod), width)
|
||||
disktest.DiskTest(language, diskTestMethod, diskTestPath, diskMultiCheck, autoChangeDiskTestMethod)
|
||||
} else if diskTestStatus && !autoChangeDiskTestMethod {
|
||||
utils.PrintCenteredTitle(fmt.Sprintf("Disk-Test--%s-Method", "dd"), width)
|
||||
disktest.DiskTest(language, "dd", diskTestPath, diskMultiCheck, autoChangeDiskTestMethod)
|
||||
utils.PrintCenteredTitle(fmt.Sprintf("Disk-Test--%s-Method", "fio"), width)
|
||||
disktest.DiskTest(language, "fio", diskTestPath, diskMultiCheck, autoChangeDiskTestMethod)
|
||||
}
|
||||
}, tempOutput, output)
|
||||
if utTestStatus {
|
||||
wg1.Add(1)
|
||||
go func() {
|
||||
defer wg1.Done()
|
||||
mediaInfo = unlocktest.MediaTest(language)
|
||||
}()
|
||||
}
|
||||
if emailTestStatus {
|
||||
wg2.Add(1)
|
||||
go func() {
|
||||
defer wg2.Done()
|
||||
emailInfo = email.EmailCheck()
|
||||
}()
|
||||
}
|
||||
output = utils.PrintAndCapture(func() {
|
||||
if utTestStatus {
|
||||
utils.PrintCenteredTitle("Cross-Border-Streaming-Media-Unlock", width)
|
||||
wg1.Wait()
|
||||
fmt.Printf(mediaInfo)
|
||||
}
|
||||
}, tempOutput, output)
|
||||
output = utils.PrintAndCapture(func() {
|
||||
if securityTestStatus {
|
||||
utils.PrintCenteredTitle("IP-Quality-Check", width)
|
||||
fmt.Printf(securityInfo)
|
||||
}
|
||||
}, tempOutput, output)
|
||||
output = utils.PrintAndCapture(func() {
|
||||
if emailTestStatus {
|
||||
utils.PrintCenteredTitle("Email-Port-Check", width)
|
||||
wg2.Wait()
|
||||
fmt.Println(emailInfo)
|
||||
}
|
||||
}, tempOutput, output)
|
||||
output = utils.PrintAndCapture(func() {
|
||||
if speedTestStatus {
|
||||
utils.PrintCenteredTitle("Speed-Test", width)
|
||||
speedtest.ShowHead(language)
|
||||
speedtest.NearbySP()
|
||||
speedtest.CustomSP("net", "global", -1, language)
|
||||
}
|
||||
}, tempOutput, output)
|
||||
endTime := time.Now()
|
||||
duration := endTime.Sub(startTime)
|
||||
minutes := int(duration.Minutes())
|
||||
seconds := int(duration.Seconds()) % 60
|
||||
fmt.Printf("Cost Time : %d 分 %d 秒\n", minutes, seconds)
|
||||
currentTime := time.Now().Format("Mon Jan 2 15:04:05 MST 2006")
|
||||
fmt.Printf("Current Time : %s\n", currentTime)
|
||||
printCenteredTitle("", width)
|
||||
output = utils.PrintAndCapture(func() {
|
||||
utils.PrintCenteredTitle("", width)
|
||||
fmt.Printf("Cost Time : %d min %d sec\n", minutes, seconds)
|
||||
fmt.Printf("Current Time : %s\n", currentTime)
|
||||
utils.PrintCenteredTitle("", width)
|
||||
}, tempOutput, output)
|
||||
default:
|
||||
fmt.Println("Unsupported language")
|
||||
}
|
||||
httpURL, httpsURL := utils.ProcessAndUpload(output, filePath, enabelUpload)
|
||||
if httpURL != "" || httpsURL != "" {
|
||||
if language == "en" {
|
||||
fmt.Printf("Upload successfully!\nHttp URL: %s\nHttps URL: %s\n", httpURL, httpsURL)
|
||||
} else {
|
||||
fmt.Printf("上传成功!\nHttp URL: %s\nHttps URL: %s\n", httpURL, httpsURL)
|
||||
}
|
||||
}
|
||||
finish = true
|
||||
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
|
||||
fmt.Println("Press Enter to exit...")
|
||||
fmt.Scanln()
|
||||
}
|
||||
}
|
||||
|
675
goecs.sh
Normal file
675
goecs.sh
Normal file
@@ -0,0 +1,675 @@
|
||||
#!/bin/bash
|
||||
# From https://github.com/oneclickvirt/ecs
|
||||
# 2024.12.08
|
||||
|
||||
# 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
|
||||
|
||||
cat <<"EOF"
|
||||
GGGGGGGG OOOOOOO EEEEEEEE CCCCCCCCC SSSSSSSSSS
|
||||
GG GG OO OO EE CC SS
|
||||
GG OO OO EE CC SS
|
||||
GG OO OO EE CC SS
|
||||
GG OO OO EEEEEEEE CC SSSSSSSSSS
|
||||
GG GGGGGG OO OO EE CC SS
|
||||
GG GG OO OO EE CC SS
|
||||
GG GG OO OO EE CC SS
|
||||
GGGGGGGG OOOOOOO EEEEEEEE CCCCCCCCC SSSSSSSSSS
|
||||
EOF
|
||||
|
||||
cd /root >/dev/null 2>&1
|
||||
if [ ! -d "/usr/bin/" ]; then
|
||||
mkdir -p "/usr/bin/"
|
||||
fi
|
||||
_red() { echo -e "\033[31m\033[01m$@\033[0m"; }
|
||||
_green() { echo -e "\033[32m\033[01m$@\033[0m"; }
|
||||
_yellow() { echo -e "\033[33m\033[01m$@\033[0m"; }
|
||||
_blue() { echo -e "\033[36m\033[01m$@\033[0m"; }
|
||||
reading() { read -rp "$(_green "$1")" "$2"; }
|
||||
|
||||
check_cdn() {
|
||||
local o_url=$1
|
||||
for cdn_url in "${cdn_urls[@]}"; do
|
||||
if curl -sL -k "$cdn_url$o_url" --max-time 6 | grep -q "success" >/dev/null 2>&1; then
|
||||
export cdn_success_url="$cdn_url"
|
||||
return
|
||||
fi
|
||||
sleep 0.5
|
||||
done
|
||||
export cdn_success_url=""
|
||||
}
|
||||
|
||||
check_cdn_file() {
|
||||
check_cdn "https://raw.githubusercontent.com/spiritLHLS/ecs/main/back/test"
|
||||
if [ -n "$cdn_success_url" ]; then
|
||||
_green "CDN available, using CDN"
|
||||
else
|
||||
_yellow "No CDN available, no use CDN"
|
||||
fi
|
||||
}
|
||||
|
||||
download_file() {
|
||||
local url="$1"
|
||||
local output="$2"
|
||||
if ! wget -O "$output" "$url"; then
|
||||
_yellow "wget failed, trying curl..."
|
||||
if ! curl -L -o "$output" "$url"; then
|
||||
_red "Both wget and curl failed. Unable to download the file."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
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
|
||||
reading "是否使用中国镜像完成安装? ([y]/n) " input
|
||||
case $input in
|
||||
[yY][eE][sS] | [yY] | "")
|
||||
_green "已选择使用中国镜像"
|
||||
CN=true
|
||||
;;
|
||||
[nN][oO] | [nN])
|
||||
_yellow "已选择不使用中国镜像"
|
||||
CN=false
|
||||
;;
|
||||
*)
|
||||
_green "已选择使用中国镜像"
|
||||
CN=true
|
||||
;;
|
||||
esac
|
||||
else
|
||||
# 在非交互模式下默认不使用中国镜像
|
||||
CN=false
|
||||
fi
|
||||
else
|
||||
CN=false
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
get_memory_size() {
|
||||
if [ -f /proc/meminfo ]; then
|
||||
local mem_kb=$(grep MemTotal /proc/meminfo | awk '{print $2}')
|
||||
echo $((mem_kb / 1024)) # Convert to MB
|
||||
return
|
||||
fi
|
||||
if command -v free >/dev/null 2>&1; then
|
||||
local mem_kb=$(free -m | awk '/^Mem:/ {print $2}')
|
||||
echo "$mem_kb" # Already in MB
|
||||
return
|
||||
fi
|
||||
if command -v sysctl >/dev/null 2>&1; then
|
||||
local mem_bytes=$(sysctl -n hw.memsize 2>/dev/null || sysctl -n hw.physmem 2>/dev/null)
|
||||
if [ -n "$mem_bytes" ]; then
|
||||
echo $((mem_bytes / 1024 / 1024)) # Convert to MB
|
||||
return
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
cleanup_epel() {
|
||||
_yellow "Cleaning up EPEL repositories..."
|
||||
rm -f /etc/yum.repos.d/*epel*
|
||||
yum clean all
|
||||
}
|
||||
|
||||
goecs_check() {
|
||||
# Get system and architecture info with error handling
|
||||
os=$(uname -s 2>/dev/null || echo "Unknown")
|
||||
arch=$(uname -m 2>/dev/null || echo "Unknown")
|
||||
# First check for China IP
|
||||
check_china
|
||||
# Get latest version number with multiple backup sources
|
||||
ECS_VERSION=""
|
||||
for api in \
|
||||
"https://api.github.com/repos/oneclickvirt/ecs/releases/latest" \
|
||||
"https://githubapi.spiritlhl.workers.dev/repos/oneclickvirt/ecs/releases/latest" \
|
||||
"https://githubapi.spiritlhl.top/repos/oneclickvirt/ecs/releases/latest"; do
|
||||
ECS_VERSION=$(curl -m 6 -sSL "$api" | awk -F \" '/tag_name/{gsub(/^v/,"",$4); print $4}')
|
||||
if [ -n "$ECS_VERSION" ]; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
if [ -z "$ECS_VERSION" ]; then
|
||||
_yellow "Unable to get version info, using default version 0.1.19"
|
||||
ECS_VERSION="0.1.19"
|
||||
fi
|
||||
# Check if original goecs command exists
|
||||
version_output=""
|
||||
for cmd_path in "goecs" "./goecs" "/usr/bin/goecs" "/usr/local/bin/goecs"; do
|
||||
if [ -x "$(command -v $cmd_path 2>/dev/null)" ]; then
|
||||
version_output=$($cmd_path -v command 2>/dev/null)
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ -n "$version_output" ]; then
|
||||
extracted_version=${version_output//v/}
|
||||
if [ -n "$extracted_version" ]; then
|
||||
ecs_version=$ECS_VERSION
|
||||
if [[ "$(echo -e "$extracted_version\n$ecs_version" | sort -V | tail -n 1)" == "$extracted_version" ]]; then
|
||||
_green "goecs version ($extracted_version) is up to date, no upgrade needed"
|
||||
return
|
||||
else
|
||||
_yellow "goecs version ($extracted_version) < $ecs_version, upgrade needed, starting in 5 seconds"
|
||||
rm -rf /usr/bin/goecs /usr/local/bin/goecs ./goecs
|
||||
fi
|
||||
fi
|
||||
else
|
||||
_green "goecs not found, installation needed, starting in 5 seconds"
|
||||
fi
|
||||
sleep 5
|
||||
# Download corresponding version with error handling
|
||||
if [[ "$CN" == true ]]; then
|
||||
_yellow "Using China mirror for download..."
|
||||
base_url="https://cnb.cool/oneclickvirt/ecs/-/git/raw/main"
|
||||
else
|
||||
cdn_urls=("https://cdn0.spiritlhl.top/" "http://cdn3.spiritlhl.net/" "http://cdn1.spiritlhl.net/" "http://cdn2.spiritlhl.net/")
|
||||
check_cdn_file
|
||||
if [ -n "$cdn_success_url" ]; then
|
||||
base_url="${cdn_success_url}https://github.com/oneclickvirt/ecs/releases/download/v${ECS_VERSION}"
|
||||
else
|
||||
base_url="https://github.com/oneclickvirt/ecs/releases/download/v${ECS_VERSION}"
|
||||
fi
|
||||
fi
|
||||
# Build download URL with architecture support
|
||||
local zip_file=""
|
||||
case $os in
|
||||
Linux|linux|LINUX)
|
||||
case $arch in
|
||||
x86_64|amd64|x64) zip_file="goecs_linux_amd64.zip" ;;
|
||||
i386|i686) zip_file="goecs_linux_386.zip" ;;
|
||||
aarch64|arm64|armv8|armv8l) zip_file="goecs_linux_arm64.zip" ;;
|
||||
arm|armv7l) zip_file="goecs_linux_arm.zip" ;;
|
||||
mips) zip_file="goecs_linux_mips.zip" ;;
|
||||
mipsle) zip_file="goecs_linux_mipsle.zip" ;;
|
||||
s390x) zip_file="goecs_linux_s390x.zip" ;;
|
||||
riscv64) zip_file="goecs_linux_riscv64.zip" ;;
|
||||
*) zip_file="goecs_linux_amd64.zip" ;;
|
||||
esac
|
||||
;;
|
||||
FreeBSD|freebsd)
|
||||
case $arch in
|
||||
x86_64|amd64) zip_file="goecs_freebsd_amd64.zip" ;;
|
||||
i386|i686) zip_file="goecs_freebsd_386.zip" ;;
|
||||
arm64|aarch64) zip_file="goecs_freebsd_arm64.zip" ;;
|
||||
*) zip_file="goecs_freebsd_amd64.zip" ;;
|
||||
esac
|
||||
;;
|
||||
Darwin|darwin)
|
||||
case $arch in
|
||||
x86_64|amd64) zip_file="goecs_darwin_amd64.zip" ;;
|
||||
arm64|aarch64) zip_file="goecs_darwin_arm64.zip" ;;
|
||||
*) zip_file="goecs_darwin_amd64.zip" ;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
_yellow "Unknown system $os, trying amd64 version"
|
||||
zip_file="goecs_linux_amd64.zip"
|
||||
;;
|
||||
esac
|
||||
download_url="${base_url}/${zip_file}"
|
||||
_green "Downloading $download_url"
|
||||
# Download file with retry mechanism
|
||||
local max_retries=3
|
||||
local retry_count=0
|
||||
while [ $retry_count -lt $max_retries ]; do
|
||||
if download_file "$download_url" "goecs.zip"; then
|
||||
break
|
||||
fi
|
||||
_yellow "Download failed, retrying (${retry_count}/${max_retries})..."
|
||||
retry_count=$((retry_count + 1))
|
||||
sleep 2
|
||||
done
|
||||
if [ $retry_count -eq $max_retries ]; then
|
||||
_red "Download failed, please check your network connection or download manually"
|
||||
return 1
|
||||
fi
|
||||
# Extract and install with error handling
|
||||
if ! unzip -o goecs.zip >/dev/null 2>&1; then
|
||||
_red "Extraction failed"
|
||||
return 1
|
||||
fi
|
||||
rm -f goecs.zip README.md LICENSE README_EN.md
|
||||
# Set execution permissions and install
|
||||
chmod 777 goecs
|
||||
for install_path in "/usr/bin" "/usr/local/bin"; do
|
||||
if [ -d "$install_path" ]; then
|
||||
cp -f goecs "$install_path/"
|
||||
break
|
||||
fi
|
||||
done
|
||||
# Set system parameters
|
||||
if [ "$os" != "Darwin" ]; then
|
||||
PARAM="net.ipv4.ping_group_range"
|
||||
NEW_VALUE="0 2147483647"
|
||||
if [ -f /etc/sysctl.conf ]; then
|
||||
if grep -q "^$PARAM" /etc/sysctl.conf; then
|
||||
sed -i "s/^$PARAM.*/$PARAM = $NEW_VALUE/" /etc/sysctl.conf
|
||||
else
|
||||
echo "$PARAM = $NEW_VALUE" >> /etc/sysctl.conf
|
||||
fi
|
||||
sysctl -p >/dev/null 2>&1
|
||||
fi
|
||||
fi
|
||||
# Set special permissions
|
||||
setcap cap_net_raw=+ep goecs 2>/dev/null
|
||||
setcap cap_net_raw=+ep /usr/bin/goecs 2>/dev/null
|
||||
setcap cap_net_raw=+ep /usr/local/bin/goecs 2>/dev/null
|
||||
_green "goecs installation complete, current version:"
|
||||
goecs -v || ./goecs -v
|
||||
}
|
||||
|
||||
InstallSysbench() {
|
||||
if [ -f "/etc/opencloudos-release" ]; then # OpenCloudOS
|
||||
Var_OSRelease="opencloudos"
|
||||
elif [ -f "/etc/centos-release" ]; then # CentOS
|
||||
Var_OSRelease="centos"
|
||||
elif [ -f "/etc/fedora-release" ]; then # Fedora
|
||||
Var_OSRelease="fedora"
|
||||
elif [ -f "/etc/redhat-release" ]; then # RedHat
|
||||
Var_OSRelease="rhel"
|
||||
elif [ -f "/etc/astra_version" ]; then # Astra
|
||||
Var_OSRelease="astra"
|
||||
elif [ -f "/etc/lsb-release" ]; then # Ubuntu
|
||||
Var_OSRelease="ubuntu"
|
||||
elif [ -f "/etc/debian_version" ]; then # Debian
|
||||
Var_OSRelease="debian"
|
||||
elif [ -f "/etc/alpine-release" ]; then # Alpine Linux
|
||||
Var_OSRelease="alpinelinux"
|
||||
elif [ -f "/etc/almalinux-release" ]; then # almalinux
|
||||
Var_OSRelease="almalinux"
|
||||
elif [ -f "/etc/arch-release" ]; then # archlinux
|
||||
Var_OSRelease="arch"
|
||||
elif [ -f "/etc/freebsd-update.conf" ]; then # freebsd
|
||||
Var_OSRelease="freebsd"
|
||||
else
|
||||
Var_OSRelease="unknown" # 未知系统分支
|
||||
fi
|
||||
local mem_size=$(get_memory_size)
|
||||
if [ -z "$mem_size" ] || [ "$mem_size" -eq 0 ]; then
|
||||
echo "Error: Unable to determine memory size or memory size is zero."
|
||||
elif [ $mem_size -lt 1024 ]; then
|
||||
_red "Warning: Your system has less than 1GB RAM (${mem_size}MB)"
|
||||
if [ "$noninteractive" != "true" ]; then
|
||||
reading "Do you want to continue with EPEL installation? (y/N): " confirm
|
||||
if [[ ! $confirm =~ ^[Yy]$ ]]; then
|
||||
_yellow "Skipping EPEL installation"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
case "$Var_OSRelease" in
|
||||
ubuntu | debian | astra)
|
||||
! apt-get install -y sysbench && apt-get --fix-broken install -y && apt-get install --no-install-recommends -y sysbench ;;
|
||||
centos | rhel | almalinux | redhat | opencloudos)
|
||||
(yum -y install epel-release && yum -y install sysbench) || (dnf install epel-release -y && dnf install sysbench -y) ;;
|
||||
fedora)
|
||||
dnf -y install sysbench ;;
|
||||
arch)
|
||||
pacman -S --needed --noconfirm sysbench && pacman -S --needed --noconfirm libaio && ldconfig ;;
|
||||
freebsd)
|
||||
pkg install -y sysbench ;;
|
||||
alpinelinux)
|
||||
if [ "$noninteractive" != "true" ]; then
|
||||
reading "Do you want to continue with sysbench installation? (y/N): " confirm
|
||||
if [[ ! $confirm =~ ^[Yy]$ ]]; then
|
||||
_yellow "Skipping sysbench installation"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
ALPINE_VERSION=$(grep -o '^[0-9]\+\.[0-9]\+' /etc/alpine-release)
|
||||
COMMUNITY_REPO="http://dl-cdn.alpinelinux.org/alpine/v${ALPINE_VERSION}/community"
|
||||
if grep -q "^${COMMUNITY_REPO}" /etc/apk/repositories; then
|
||||
echo "Community repository is already enabled."
|
||||
else
|
||||
echo "Enabling community repository..."
|
||||
echo "${COMMUNITY_REPO}" >> /etc/apk/repositories
|
||||
echo "Community repository has been added."
|
||||
echo "Updating apk package index..."
|
||||
apk update && echo "Package index updated successfully."
|
||||
fi
|
||||
if apk info sysbench >/dev/null 2>&1; then
|
||||
echo -e "${Msg_Info}Sysbench already installed."
|
||||
else
|
||||
apk add --no-cache sysbench
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${Msg_Warning}Sysbench Module not found, installing ..." && echo -e "${Msg_Warning}SysBench Current not support Alpine Linux, Skipping..." && Var_Skip_SysBench="1"
|
||||
else
|
||||
echo -e "${Msg_Success}Sysbench installed successfully."
|
||||
fi
|
||||
fi ;;
|
||||
*)
|
||||
_red "Sysbench Install Error: Unknown OS release: $Var_OSRelease" ;;
|
||||
esac
|
||||
if [[ $SYSTEM =~ ^(CentOS|RHEL|AlmaLinux)$ ]]; then
|
||||
_yellow "Installing EPEL repository..."
|
||||
if ! yum -y install epel-release; then
|
||||
_red "EPEL installation failed!"
|
||||
cleanup_epel
|
||||
_yellow "Attempting to continue without EPEL..."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
Check_SysBench() {
|
||||
if [ ! -f "/usr/bin/sysbench" ] && [ ! -f "/usr/local/bin/sysbench" ]; then
|
||||
InstallSysbench
|
||||
fi
|
||||
# 尝试编译安装
|
||||
if [ ! -f "/usr/bin/sysbench" ] && [ ! -f "/usr/local/bin/sysbench" ]; then
|
||||
echo -e "${Msg_Warning}Sysbench Module install Failure, trying compile modules ..."
|
||||
Check_Sysbench_InstantBuild
|
||||
fi
|
||||
source ~/.bashrc
|
||||
# 最终检测
|
||||
if [ "$(command -v sysbench)" ] || [ -f "/usr/bin/sysbench" ] || [ -f "/usr/local/bin/sysbench" ]; then
|
||||
_yellow "Install sysbench successfully!"
|
||||
else
|
||||
_red "SysBench Moudle install Failure! Try Restart Bench or Manually install it! (/usr/bin/sysbench)"
|
||||
_blue "Will try to test with geekbench5 instead later."
|
||||
fi
|
||||
sleep 3
|
||||
}
|
||||
|
||||
Check_Sysbench_InstantBuild() {
|
||||
if [ "${Var_OSRelease}" = "centos" ] || [ "${Var_OSRelease}" = "rhel" ] || [ "${Var_OSRelease}" = "almalinux" ] || [ "${Var_OSRelease}" = "ubuntu" ] || [ "${Var_OSRelease}" = "debian" ] || [ "${Var_OSRelease}" = "fedora" ] || [ "${Var_OSRelease}" = "arch" ] || [ "${Var_OSRelease}" = "astra" ]; then
|
||||
local os_sysbench=${Var_OSRelease}
|
||||
if [ "$os_sysbench" = "astra" ]; then
|
||||
os_sysbench="debian"
|
||||
fi
|
||||
if [ "$os_sysbench" = "opencloudos" ]; then
|
||||
os_sysbench="centos"
|
||||
fi
|
||||
echo -e "${Msg_Info}Release Detected: ${os_sysbench}"
|
||||
echo -e "${Msg_Info}Preparing compile enviorment ..."
|
||||
prepare_compile_env "${os_sysbench}"
|
||||
echo -e "${Msg_Info}Downloading Source code (Version 1.0.20)..."
|
||||
mkdir -p /tmp/sysbench_install/src/
|
||||
mv /tmp/sysbench-1.0.20 /tmp/sysbench_install/src/
|
||||
echo -e "${Msg_Info}Compiling Sysbench Module ..."
|
||||
cd /tmp/sysbench_install/src/sysbench-1.0.20
|
||||
./autogen.sh && ./configure --without-mysql && make -j8 && make install
|
||||
echo -e "${Msg_Info}Cleaning up ..."
|
||||
cd /tmp && rm -rf /tmp/sysbench_install/src/sysbench*
|
||||
else
|
||||
echo -e "${Msg_Warning}Unsupported operating system: ${Var_OSRelease}"
|
||||
fi
|
||||
}
|
||||
|
||||
prepare_compile_env() {
|
||||
local system="$1"
|
||||
if [ "${system}" = "centos" ] || [ "${system}" = "rhel" ] || [ "${system}" = "almalinux" ]; then
|
||||
yum install -y epel-release
|
||||
yum install -y wget curl make gcc gcc-c++ make automake libtool pkgconfig libaio-devel
|
||||
elif [ "${system}" = "ubuntu" ] || [ "${system}" = "debian" ]; then
|
||||
! apt-get update && apt-get --fix-broken install -y && apt-get update
|
||||
! apt-get -y install --no-install-recommends curl wget make automake libtool pkg-config libaio-dev unzip && apt-get --fix-broken install -y && apt-get -y install --no-install-recommends curl wget make automake libtool pkg-config libaio-dev unzip
|
||||
elif [ "${system}" = "fedora" ]; then
|
||||
dnf install -y wget curl gcc gcc-c++ make automake libtool pkgconfig libaio-devel
|
||||
elif [ "${system}" = "arch" ]; then
|
||||
pacman -S --needed --noconfirm wget curl gcc gcc make automake libtool pkgconfig libaio lib32-libaio
|
||||
else
|
||||
echo -e "${Msg_Warning}Unsupported operating system: ${system}"
|
||||
fi
|
||||
}
|
||||
|
||||
env_check() {
|
||||
REGEX=("debian|astra" "ubuntu" "centos|red hat|kernel|oracle linux|alma|rocky" "'amazon linux'" "fedora" "arch" "freebsd" "alpine" "openbsd" "opencloudos")
|
||||
RELEASE=("Debian" "Ubuntu" "CentOS" "CentOS" "Fedora" "Arch" "FreeBSD" "Alpine" "OpenBSD" "OpenCloudOS")
|
||||
PACKAGE_UPDATE=("apt-get update" "apt-get update" "yum -y update" "yum -y update" "yum -y update" "pacman -Sy" "pkg update" "apk update" "pkg_add -qu" "yum -y update")
|
||||
PACKAGE_INSTALL=("apt-get -y install" "apt-get -y install" "yum -y install" "yum -y install" "yum -y install" "pacman -Sy --noconfirm --needed" "pkg install -y" "apk add --no-cache" "pkg_add -I" "yum -y install")
|
||||
PACKAGE_REMOVE=("apt-get -y remove" "apt-get -y remove" "yum -y remove" "yum -y remove" "yum -y remove" "pacman -Rsc --noconfirm" "pkg delete" "apk del" "pkg_delete -I" "yum -y remove")
|
||||
PACKAGE_UNINSTALL=("apt-get -y autoremove" "apt-get -y autoremove" "yum -y autoremove" "yum -y autoremove" "yum -y autoremove" "pacman -Rns --noconfirm" "pkg autoremove" "apk autoremove" "pkg_delete -a" "yum -y autoremove")
|
||||
# Check system information
|
||||
if [ -f /etc/opencloudos-release ]; then
|
||||
SYS="opencloudos"
|
||||
elif [ -s /etc/os-release ]; then
|
||||
SYS="$(grep -i pretty_name /etc/os-release | cut -d \" -f2)"
|
||||
elif [ -x "$(type -p hostnamectl)" ]; then
|
||||
SYS="$(hostnamectl | grep -i system | cut -d : -f2 | xargs)"
|
||||
elif [ -x "$(type -p lsb_release)" ]; then
|
||||
SYS="$(lsb_release -sd)"
|
||||
elif [ -s /etc/lsb-release ]; then
|
||||
SYS="$(grep -i description /etc/lsb-release | cut -d \" -f2)"
|
||||
elif [ -s /etc/redhat-release ]; then
|
||||
SYS="$(grep . /etc/redhat-release)"
|
||||
elif [ -s /etc/issue ]; then
|
||||
SYS="$(grep . /etc/issue | cut -d '\' -f1 | sed '/^[ ]*$/d')"
|
||||
else
|
||||
SYS="$(uname -s)"
|
||||
fi
|
||||
# Match operating system
|
||||
SYSTEM=""
|
||||
for ((int = 0; int < ${#REGEX[@]}; int++)); do
|
||||
if [[ $(echo "$SYS" | tr '[:upper:]' '[:lower:]') =~ ${REGEX[int]} ]]; then
|
||||
SYSTEM="${RELEASE[int]}"
|
||||
UPDATE_CMD=${PACKAGE_UPDATE[int]}
|
||||
INSTALL_CMD=${PACKAGE_INSTALL[int]}
|
||||
REMOVE_CMD=${PACKAGE_REMOVE[int]}
|
||||
UNINSTALL_CMD=${PACKAGE_UNINSTALL[int]}
|
||||
break
|
||||
fi
|
||||
done
|
||||
# If system is unrecognized, try common package managers
|
||||
if [ -z "$SYSTEM" ]; then
|
||||
_yellow "Unable to recognize system, trying common package managers..."
|
||||
# Try apt
|
||||
if command -v apt-get >/dev/null 2>&1; then
|
||||
SYSTEM="Unknown-Debian"
|
||||
UPDATE_CMD="apt-get update"
|
||||
INSTALL_CMD="apt-get -y install"
|
||||
REMOVE_CMD="apt-get -y remove"
|
||||
UNINSTALL_CMD="apt-get -y autoremove"
|
||||
# Try yum
|
||||
elif command -v yum >/dev/null 2>&1; then
|
||||
SYSTEM="Unknown-RHEL"
|
||||
UPDATE_CMD="yum -y update"
|
||||
INSTALL_CMD="yum -y install"
|
||||
REMOVE_CMD="yum -y remove"
|
||||
UNINSTALL_CMD="yum -y autoremove"
|
||||
# Try dnf
|
||||
elif command -v dnf >/dev/null 2>&1; then
|
||||
SYSTEM="Unknown-Fedora"
|
||||
UPDATE_CMD="dnf -y update"
|
||||
INSTALL_CMD="dnf -y install"
|
||||
REMOVE_CMD="dnf -y remove"
|
||||
UNINSTALL_CMD="dnf -y autoremove"
|
||||
# Try pacman
|
||||
elif command -v pacman >/dev/null 2>&1; then
|
||||
SYSTEM="Unknown-Arch"
|
||||
UPDATE_CMD="pacman -Sy"
|
||||
INSTALL_CMD="pacman -S --noconfirm"
|
||||
REMOVE_CMD="pacman -R --noconfirm"
|
||||
UNINSTALL_CMD="pacman -Rns --noconfirm"
|
||||
# Try apk
|
||||
elif command -v apk >/dev/null 2>&1; then
|
||||
SYSTEM="Unknown-Alpine"
|
||||
UPDATE_CMD="apk update"
|
||||
INSTALL_CMD="apk add"
|
||||
REMOVE_CMD="apk del"
|
||||
UNINSTALL_CMD="apk del"
|
||||
elif command -v zypper >/dev/null 2>&1; then
|
||||
SYSTEM="Unknown-SLES"
|
||||
UPDATE_CMD="zypper refresh"
|
||||
INSTALL_CMD="zypper install -y"
|
||||
REMOVE_CMD="zypper remove -y"
|
||||
UNINSTALL_CMD="zypper remove -y"
|
||||
else
|
||||
_red "Unable to recognize package manager, exiting installation"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
_green "System information: $SYSTEM"
|
||||
_green "Update command: $UPDATE_CMD"
|
||||
_green "Install command: $INSTALL_CMD"
|
||||
cdn_urls=("https://cdn0.spiritlhl.top/" "http://cdn3.spiritlhl.net/" "http://cdn1.spiritlhl.net/" "http://cdn2.spiritlhl.net/")
|
||||
check_cdn_file
|
||||
_yellow "Warning: System update will be performed"
|
||||
_yellow "This operation may:"
|
||||
_yellow "1. Take considerable time"
|
||||
_yellow "2. Cause temporary network interruptions"
|
||||
_yellow "3. Impact system stability"
|
||||
_yellow "4. Affect subsequent system startups"
|
||||
if [ "$noninteractive" != "true" ]; then
|
||||
reading "Continue with system update? (y/N): " update_confirm
|
||||
if [[ ! $update_confirm =~ ^[Yy]$ ]]; then
|
||||
_yellow "Skipping system update"
|
||||
_yellow "Note: Some packages may fail to install"
|
||||
else
|
||||
_green "Updating system package manager..."
|
||||
if ! ${UPDATE_CMD} 2>/dev/null; then
|
||||
_red "System update failed!"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
# Install necessary commands
|
||||
for cmd in sudo wget tar unzip iproute2 systemd-detect-virt dd fio; do
|
||||
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||
_green "Installing $cmd"
|
||||
${INSTALL_CMD} "$cmd"
|
||||
fi
|
||||
done
|
||||
# sysbench installation
|
||||
if ! command -v sysbench >/dev/null 2>&1; then
|
||||
_green "Installing sysbench"
|
||||
${INSTALL_CMD} sysbench
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Unable to download sysbench through package manager, attempting compilation..."
|
||||
wget -O /tmp/sysbench.zip "${cdn_success_url}https://github.com/akopytov/sysbench/archive/1.0.20.zip" || curl -Lk -o /tmp/sysbench.zip "${cdn_success_url}https://github.com/akopytov/sysbench/archive/1.0.20.zip"
|
||||
if [ ! -f /tmp/sysbench.zip ]; then
|
||||
wget -q -O /tmp/sysbench.zip "https://hub.fgit.cf/akopytov/sysbench/archive/1.0.20.zip"
|
||||
fi
|
||||
chmod +x /tmp/sysbench.zip
|
||||
unzip /tmp/sysbench.zip -d /tmp
|
||||
Check_SysBench
|
||||
fi
|
||||
fi
|
||||
# geekbench and speedtest installation
|
||||
if ! command -v geekbench >/dev/null 2>&1; then
|
||||
_green "Installing geekbench"
|
||||
curl -L "${cdn_success_url}https://raw.githubusercontent.com/oneclickvirt/cputest/main/dgb.sh" -o dgb.sh && chmod +x dgb.sh
|
||||
bash dgb.sh -v gb5
|
||||
rm -rf dgb.sh
|
||||
fi
|
||||
if ! command -v speedtest >/dev/null 2>&1; then
|
||||
_green "Installing speedtest"
|
||||
curl -L "${cdn_success_url}https://raw.githubusercontent.com/oneclickvirt/speedtest/main/dspt.sh" -o dspt.sh && chmod +x dspt.sh
|
||||
bash dspt.sh
|
||||
rm -rf dspt.sh
|
||||
rm -rf speedtest.tar.gz
|
||||
fi
|
||||
if ! command -v ping >/dev/null 2>&1; then
|
||||
_green "Installing ping"
|
||||
${INSTALL_CMD} iputils-ping >/dev/null 2>&1
|
||||
${INSTALL_CMD} ping >/dev/null 2>&1
|
||||
fi
|
||||
# MacOS support
|
||||
if [ "$(uname -s)" = "Darwin" ]; then
|
||||
echo "Detected MacOS, installing sysbench iproute2mac fio..."
|
||||
brew install --force sysbench iproute2mac fio
|
||||
else
|
||||
if ! grep -q "^net.ipv4.ping_group_range = 0 2147483647$" /etc/sysctl.conf; then
|
||||
echo "net.ipv4.ping_group_range = 0 2147483647" >> /etc/sysctl.conf
|
||||
sysctl -p
|
||||
fi
|
||||
fi
|
||||
_green "Environment preparation complete."
|
||||
_green "Next command is: ./goecs.sh install"
|
||||
}
|
||||
|
||||
uninstall_goecs() {
|
||||
rm -rf /root/goecs
|
||||
rm -rf /usr/bin/goecs
|
||||
_green "The command (goecs) has been uninstalled."
|
||||
}
|
||||
|
||||
show_help() {
|
||||
cat <<"EOF"
|
||||
可用命令:
|
||||
|
||||
./goecs.sh env 检查并安装依赖包
|
||||
警告: 此命令会执行系统更新(可选择),可能:
|
||||
1. 耗时较长
|
||||
2. 导致网络短暂中断
|
||||
3. 影响系统稳定性
|
||||
4. 影响后续系统启动
|
||||
对于内存小于1GB的系统,还可能导致:
|
||||
1. 系统卡死
|
||||
2. SSH连接中断
|
||||
3. 关键服务失败
|
||||
推荐:
|
||||
环境依赖安装过程中挂起执行
|
||||
|
||||
必需组件:
|
||||
sysbench/geekbench (CPU性能测试必需)
|
||||
|
||||
可选组件:
|
||||
sudo, tar, unzip, dd, fio
|
||||
speedtest (网络测试)
|
||||
ping (网络连通性测试)
|
||||
systemd-detect-virt/dmidecode (系统信息检测)
|
||||
|
||||
./goecs.sh install 安装 goecs 命令
|
||||
./goecs.sh upgrade 升级 goecs 命令
|
||||
./goecs.sh uninstall 卸载 goecs 命令
|
||||
./goecs.sh help 显示此消息
|
||||
|
||||
Available commands:
|
||||
|
||||
./goecs.sh env Check and Install dependencies
|
||||
Warning: This command performs system update(optional), which may:
|
||||
1. Take considerable time
|
||||
2. Cause temporary network interruptions
|
||||
3. Impact system stability
|
||||
4. Affect subsequent system startups
|
||||
For systems with less than 1GB RAM, additional risks:
|
||||
1. System freeze
|
||||
2. SSH connection loss
|
||||
3. Critical service failures
|
||||
Recommended:
|
||||
Hanging execution during environment dependency installation
|
||||
|
||||
Required components:
|
||||
sysbench/geekbench (Required for CPU testing)
|
||||
|
||||
Optional components:
|
||||
sudo, tar, unzip, dd, fio
|
||||
speedtest (Network testing)
|
||||
ping (Network connectivity)
|
||||
systemd-detect-virt/dmidecode (System info detection)
|
||||
|
||||
./goecs.sh install Install goecs command
|
||||
./goecs.sh upgrade Upgrade goecs command
|
||||
./goecs.sh uninstall Uninstall goecs command
|
||||
./goecs.sh help Show this message
|
||||
EOF
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
"help")
|
||||
show_help
|
||||
;;
|
||||
"env")
|
||||
env_check
|
||||
;;
|
||||
"install" | "upgrade")
|
||||
goecs_check
|
||||
;;
|
||||
"uninstall")
|
||||
uninstall_goecs
|
||||
;;
|
||||
*)
|
||||
echo "No command found."
|
||||
echo
|
||||
show_help
|
||||
;;
|
||||
esac
|
||||
|
@@ -1,93 +0,0 @@
|
||||
#!/bin/bash
|
||||
#From https://github.com/oneclickvirt/ecs
|
||||
#2024.06.29
|
||||
|
||||
rm -rf /usr/bin/goecs
|
||||
rm -rf goecs
|
||||
os=$(uname -s)
|
||||
arch=$(uname -m)
|
||||
|
||||
check_cdn() {
|
||||
local o_url=$1
|
||||
for cdn_url in "${cdn_urls[@]}"; do
|
||||
if curl -sL -k "$cdn_url$o_url" --max-time 6 | grep -q "success" >/dev/null 2>&1; then
|
||||
export cdn_success_url="$cdn_url"
|
||||
return
|
||||
fi
|
||||
sleep 0.5
|
||||
done
|
||||
export cdn_success_url=""
|
||||
}
|
||||
|
||||
check_cdn_file() {
|
||||
check_cdn "https://raw.githubusercontent.com/spiritLHLS/ecs/main/back/test"
|
||||
if [ -n "$cdn_success_url" ]; then
|
||||
echo "CDN available, using CDN"
|
||||
else
|
||||
echo "No CDN available, no use CDN"
|
||||
fi
|
||||
}
|
||||
|
||||
cdn_urls=("https://cdn0.spiritlhl.top/" "http://cdn3.spiritlhl.net/" "http://cdn1.spiritlhl.net/" "http://cdn2.spiritlhl.net/")
|
||||
check_cdn_file
|
||||
|
||||
case $os in
|
||||
Linux)
|
||||
case $arch in
|
||||
"x86_64" | "x86" | "amd64" | "x64")
|
||||
wget -O goecs "${cdn_success_url}https://github.com/oneclickvirt/ecs/releases/download/output/ecs-linux-amd64"
|
||||
;;
|
||||
"i386" | "i686")
|
||||
wget -O goecs "${cdn_success_url}https://github.com/oneclickvirt/ecs/releases/download/output/ecs-linux-386"
|
||||
;;
|
||||
"armv7l" | "armv8" | "armv8l" | "aarch64" | "arm64")
|
||||
wget -O goecs "${cdn_success_url}https://github.com/oneclickvirt/ecs/releases/download/output/ecs-linux-arm64"
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported architecture: $arch"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
Darwin)
|
||||
case $arch in
|
||||
"x86_64" | "x86" | "amd64" | "x64")
|
||||
wget -O goecs "${cdn_success_url}https://github.com/oneclickvirt/ecs/releases/download/output/ecs-darwin-amd64"
|
||||
;;
|
||||
"i386" | "i686")
|
||||
wget -O goecs "${cdn_success_url}https://github.com/oneclickvirt/ecs/releases/download/output/ecs-darwin-386"
|
||||
;;
|
||||
"armv7l" | "armv8" | "armv8l" | "aarch64" | "arm64")
|
||||
wget -O goecs "${cdn_success_url}https://github.com/oneclickvirt/ecs/releases/download/output/ecs-darwin-arm64"
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported architecture: $arch"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
FreeBSD)
|
||||
case $arch in
|
||||
amd64)
|
||||
wget -O goecs "${cdn_success_url}https://github.com/oneclickvirt/ecs/releases/download/output/ecs-freebsd-amd64"
|
||||
;;
|
||||
"i386" | "i686")
|
||||
wget -O goecs "${cdn_success_url}https://github.com/oneclickvirt/ecs/releases/download/output/ecs-freebsd-386"
|
||||
;;
|
||||
"armv7l" | "armv8" | "armv8l" | "aarch64" | "arm64")
|
||||
wget -O goecs "${cdn_success_url}https://github.com/oneclickvirt/ecs/releases/download/output/ecs-freebsd-arm64"
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported architecture: $arch"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported operating system: $os"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
chmod 777 goecs
|
||||
cp goecs /usr/bin/goecs
|
@@ -1,6 +1,8 @@
|
||||
package main
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test(t *testing.T) {
|
||||
main()
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"github.com/oneclickvirt/memorytest/memory"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func MemoryTest(language, testMethod string) {
|
||||
@@ -27,5 +28,8 @@ func MemoryTest(language, testMethod string) {
|
||||
res = "Unsupported test method"
|
||||
}
|
||||
}
|
||||
if !strings.Contains(res, "\n") && res != "" {
|
||||
res += "\n"
|
||||
}
|
||||
fmt.Printf(res)
|
||||
}
|
||||
|
@@ -1,542 +1,8 @@
|
||||
package network
|
||||
package network1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
import "github.com/oneclickvirt/security/network"
|
||||
|
||||
"github.com/oneclickvirt/basics/model"
|
||||
"github.com/oneclickvirt/basics/network/baseinfo"
|
||||
"github.com/oneclickvirt/basics/network/utils"
|
||||
. "github.com/oneclickvirt/defaultset"
|
||||
"github.com/oneclickvirt/security/network/printhead"
|
||||
. "github.com/oneclickvirt/security/network/security"
|
||||
)
|
||||
|
||||
// sortAndTranslateText 对原始文本进行排序和翻译
|
||||
func sortAndTranslateText(orginList []string, language string, fields []string) string {
|
||||
var result string
|
||||
for _, key := range fields {
|
||||
var displayKey string
|
||||
if language == "zh" {
|
||||
displayKey = model.TranslationMap[key]
|
||||
if displayKey == "" {
|
||||
displayKey = key
|
||||
}
|
||||
} else {
|
||||
displayKey = key
|
||||
}
|
||||
for _, line := range orginList {
|
||||
if strings.Contains(line, key) {
|
||||
if displayKey == key {
|
||||
result = result + line + "\n"
|
||||
} else {
|
||||
result = result + strings.ReplaceAll(line, key, displayKey) + "\n"
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// fetchAndLogInfo 子函数执行和日志记录
|
||||
func fetchAndLogInfo(wg *sync.WaitGroup, ip string, scorePtr **model.SecurityScore, infoPtr **model.SecurityInfo, fetchFunc func(string) (*model.SecurityScore, *model.SecurityInfo, error)) {
|
||||
defer wg.Done()
|
||||
var err error
|
||||
if scorePtr != nil && *scorePtr != nil && infoPtr != nil && *infoPtr != nil {
|
||||
*scorePtr, *infoPtr, err = fetchFunc(ip)
|
||||
} else if scorePtr == nil && infoPtr != nil && *infoPtr != nil {
|
||||
_, *infoPtr, err = fetchFunc(ip)
|
||||
} else if scorePtr != nil && *scorePtr != nil && infoPtr == nil {
|
||||
*scorePtr, _, err = fetchFunc(ip)
|
||||
}
|
||||
if err != nil {
|
||||
if model.EnableLoger {
|
||||
Logger.Info(fmt.Sprintf("%s: %s", runtime.FuncForPC(reflect.ValueOf(fetchFunc).Pointer()).Name(), err.Error()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ipv4SecurityCheck 检测 ipv4 安全信息和安全得分
|
||||
func Ipv4SecurityCheck(ipInfo *model.IpInfo, cheervisionInfo *model.SecurityInfo, language string) (string, error) {
|
||||
if model.EnableLoger {
|
||||
InitLogger()
|
||||
defer Logger.Sync()
|
||||
}
|
||||
if ipInfo == nil {
|
||||
if model.EnableLoger {
|
||||
Logger.Info("ipv4 is not available")
|
||||
}
|
||||
return "", fmt.Errorf("ipv4 is not available")
|
||||
}
|
||||
if cheervisionInfo == nil {
|
||||
if model.EnableLoger {
|
||||
Logger.Info("ipv4 cheervisionInfo nil")
|
||||
}
|
||||
}
|
||||
var (
|
||||
ip, temp, orgin, result string
|
||||
wg sync.WaitGroup
|
||||
iPInfoIoInfo = &model.SecurityInfo{}
|
||||
scamalyticsInfo = &model.SecurityInfo{}
|
||||
abuseipdbInfo = &model.SecurityInfo{}
|
||||
ip2locationIoInfo = &model.SecurityInfo{}
|
||||
ipapicomInfo = &model.SecurityInfo{}
|
||||
ipwhoisioInfo = &model.SecurityInfo{}
|
||||
ipregistryCoInfo = &model.SecurityInfo{}
|
||||
ipdataCoInfo = &model.SecurityInfo{}
|
||||
dbIpComInfo = &model.SecurityInfo{}
|
||||
ipapiisInfo = &model.SecurityInfo{}
|
||||
ipapiComInfo = &model.SecurityInfo{}
|
||||
abstractapiInfo = &model.SecurityInfo{}
|
||||
ipqualityscoreComInfo = &model.SecurityInfo{}
|
||||
|
||||
scamalyticsScore = &model.SecurityScore{}
|
||||
virustotalScore = &model.SecurityScore{}
|
||||
abuseipdbScore = &model.SecurityScore{}
|
||||
dbIpComScore = &model.SecurityScore{}
|
||||
ipapiisScore = &model.SecurityScore{}
|
||||
ipdataCoScore = &model.SecurityScore{}
|
||||
ipapiComScore = &model.SecurityScore{}
|
||||
ipqualityscoreComScore = &model.SecurityScore{}
|
||||
)
|
||||
ip = ipInfo.Ip
|
||||
wg.Add(14)
|
||||
go fetchAndLogInfo(&wg, ip, nil, &iPInfoIoInfo, IPInfoIo)
|
||||
go fetchAndLogInfo(&wg, ip, &scamalyticsScore, &scamalyticsInfo, Scamalytics)
|
||||
go fetchAndLogInfo(&wg, ip, &virustotalScore, nil, Virustotal)
|
||||
go fetchAndLogInfo(&wg, ip, &abuseipdbScore, &abuseipdbInfo, Abuseipdb)
|
||||
go fetchAndLogInfo(&wg, ip, nil, &ip2locationIoInfo, Ip2locationIo)
|
||||
go fetchAndLogInfo(&wg, ip, nil, &ipapicomInfo, IpApiCom)
|
||||
go fetchAndLogInfo(&wg, ip, nil, &ipwhoisioInfo, IpwhoisIo)
|
||||
go fetchAndLogInfo(&wg, ip, nil, &ipregistryCoInfo, IpregistryCo)
|
||||
go fetchAndLogInfo(&wg, ip, &ipdataCoScore, &ipdataCoInfo, IpdataCo)
|
||||
go fetchAndLogInfo(&wg, ip, &dbIpComScore, &dbIpComInfo, DbIpCom)
|
||||
go fetchAndLogInfo(&wg, ip, &ipapiisScore, &ipapiisInfo, Ipapiis)
|
||||
go fetchAndLogInfo(&wg, ip, &ipapiComScore, &ipapiComInfo, IpapiCom)
|
||||
go fetchAndLogInfo(&wg, ip, nil, &abstractapiInfo, Abstractapi)
|
||||
go fetchAndLogInfo(&wg, ip, &ipqualityscoreComScore, &ipqualityscoreComInfo, IpqualityscoreCom)
|
||||
wg.Wait()
|
||||
// 构建非空信息
|
||||
var allScoreList []model.SecurityScore
|
||||
scorePointers := []*model.SecurityScore{virustotalScore, scamalyticsScore, abuseipdbScore, dbIpComScore,
|
||||
ipapiisScore, ipapiComScore, ipdataCoScore, ipqualityscoreComScore}
|
||||
for _, score := range scorePointers {
|
||||
if score != nil {
|
||||
allScoreList = append(allScoreList, *score)
|
||||
}
|
||||
}
|
||||
var allInfoList []model.SecurityInfo
|
||||
infoPointers := []*model.SecurityInfo{iPInfoIoInfo, scamalyticsInfo, abuseipdbInfo, ip2locationIoInfo, ipapicomInfo,
|
||||
ipwhoisioInfo, ipregistryCoInfo, ipdataCoInfo, dbIpComInfo, ipapiisInfo, ipapiComInfo, abstractapiInfo,
|
||||
cheervisionInfo, ipqualityscoreComInfo}
|
||||
for _, info := range infoPointers {
|
||||
if info != nil {
|
||||
allInfoList = append(allInfoList, *info)
|
||||
}
|
||||
}
|
||||
// 构建回传的文本内容
|
||||
temp += FormatSecurityScore(allScoreList)
|
||||
temp += "\n"
|
||||
temp += FormatSecurityInfo(allInfoList)
|
||||
// 分割输入为行
|
||||
lines := strings.Split(temp, "\n")
|
||||
// 初始化一个映射用于存储冒号之前的内容及其对应的行数
|
||||
contentMap := make(map[string][]int)
|
||||
// 遍历每一行,提取冒号之前的内容及其行数
|
||||
for i, line := range lines {
|
||||
// 如果行为空则跳过
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
// 切割行,以冒号为分隔符
|
||||
parts := strings.Split(line, ":")
|
||||
// 获取冒号之前的内容
|
||||
content := parts[0]
|
||||
// 将当前行的行号添加到映射中
|
||||
contentMap[content] = append(contentMap[content], i)
|
||||
}
|
||||
// 遍历映射,拼接相同内容的行
|
||||
for _, lineNumbers := range contentMap {
|
||||
if len(lineNumbers) > 1 { // 只对有多个行的内容进行拼接
|
||||
// 初始化一个字符串切片,用于存储拼接后的行
|
||||
var mergedLines []string
|
||||
// 遍历相同内容的行 添加当前行到拼接后的行中
|
||||
for _, lineNumber := range lineNumbers {
|
||||
if lineNumber == lineNumbers[0] {
|
||||
mergedLines = append(mergedLines, strings.TrimSpace(lines[lineNumber]))
|
||||
} else {
|
||||
mergedLines = append(mergedLines, strings.TrimSpace(strings.Split(lines[lineNumber], ":")[1]))
|
||||
}
|
||||
}
|
||||
// 将拼接后的行以空格连接起来
|
||||
mergedLine := strings.Join(mergedLines, " ")
|
||||
// 替换原始行中相同内容的行为拼接后的行,仅替换一次,其他行标注要删除
|
||||
isMerged := false
|
||||
for _, lineNumber := range lineNumbers {
|
||||
if !isMerged {
|
||||
lines[lineNumber] = mergedLine
|
||||
isMerged = true
|
||||
} else {
|
||||
lines[lineNumber] += "delete"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 删除对应的行,构建原始文本
|
||||
for _, line := range lines {
|
||||
if !strings.Contains(line, "delete") {
|
||||
orgin = orgin + line + "\n"
|
||||
}
|
||||
}
|
||||
orginList := strings.Split(orgin, "\n")
|
||||
// 将原始文本按要求进行排序和翻译
|
||||
var score model.SecurityScore
|
||||
scoreFields := utils.ExtractFieldNames(&score)
|
||||
var info model.SecurityInfo
|
||||
infoFields := utils.ExtractFieldNames(&info)
|
||||
// 拼接安全得分
|
||||
if language == "zh" {
|
||||
result += Blue("安全得分:") + "\n"
|
||||
} else if language == "en" {
|
||||
result = Blue("Security Score:") + "\n"
|
||||
}
|
||||
if len(scoreFields) > 4 {
|
||||
result += sortAndTranslateText(orginList, language, scoreFields[:len(scoreFields)-4])
|
||||
} else {
|
||||
result += sortAndTranslateText(orginList, language, scoreFields)
|
||||
}
|
||||
// 安全信息中前三个是字符串类型的得分
|
||||
result += sortAndTranslateText(orginList, language, infoFields[:3])
|
||||
// 需要确保后4个属性都为对应属性时才进行说明的拼接
|
||||
if len(scoreFields) > 4 {
|
||||
t := ""
|
||||
foundKeys := 0
|
||||
for _, key := range scoreFields[len(scoreFields)-4:] {
|
||||
var displayKey string
|
||||
if language == "zh" {
|
||||
displayKey = model.TranslationMap[key]
|
||||
if displayKey == "" {
|
||||
displayKey = key
|
||||
}
|
||||
} else {
|
||||
displayKey = key
|
||||
}
|
||||
found := false
|
||||
for _, line := range orginList {
|
||||
if strings.Contains(line, key) {
|
||||
key = strings.ReplaceAll(key, ": ", "")
|
||||
if displayKey == key {
|
||||
t = t + line + " "
|
||||
} else {
|
||||
t = t + strings.ReplaceAll(line, key, displayKey) + " "
|
||||
}
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if found {
|
||||
foundKeys++
|
||||
}
|
||||
}
|
||||
if foundKeys == 4 {
|
||||
if language == "zh" {
|
||||
result = result + "黑名单记录统计:(有多少黑名单网站有记录):\n" + t + "\n"
|
||||
} else if language == "en" {
|
||||
result = result + "Blacklist_Records_Statistics(how many blacklisted websites have records):\n" + t + "\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
// 拼接安全信息
|
||||
if language == "zh" {
|
||||
result += Blue("安全信息:") + "\n"
|
||||
} else if language == "en" {
|
||||
result += Blue("Security Info:") + "\n"
|
||||
}
|
||||
result += sortAndTranslateText(orginList, language, infoFields[3:])
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Ipv6SecurityCheck 检测 ipv4 安全信息和安全得分
|
||||
func Ipv6SecurityCheck(ipInfo *model.IpInfo, cheervisionInfo *model.SecurityInfo, language string) (string, error) {
|
||||
if model.EnableLoger {
|
||||
InitLogger()
|
||||
defer Logger.Sync()
|
||||
}
|
||||
if ipInfo == nil {
|
||||
if model.EnableLoger {
|
||||
Logger.Info("ipv6 is not available")
|
||||
}
|
||||
return "", fmt.Errorf("ipv6 is not available")
|
||||
}
|
||||
if cheervisionInfo == nil {
|
||||
if model.EnableLoger {
|
||||
Logger.Info("ipv6 cheervisionInfo nil")
|
||||
}
|
||||
}
|
||||
var (
|
||||
ip, temp, orgin, result string
|
||||
wg sync.WaitGroup
|
||||
scamalyticsInfo = &model.SecurityInfo{}
|
||||
abuseipdbInfo = &model.SecurityInfo{}
|
||||
ipapiisInfo = &model.SecurityInfo{}
|
||||
ipapiComInfo = &model.SecurityInfo{}
|
||||
scamalyticsScore = &model.SecurityScore{}
|
||||
abuseipdbScore = &model.SecurityScore{}
|
||||
ipapiisScore = &model.SecurityScore{}
|
||||
ipapiComScore = &model.SecurityScore{}
|
||||
)
|
||||
ip = ipInfo.Ip
|
||||
wg.Add(4)
|
||||
go fetchAndLogInfo(&wg, ip, &scamalyticsScore, &scamalyticsInfo, Scamalytics)
|
||||
go fetchAndLogInfo(&wg, ip, &abuseipdbScore, &abuseipdbInfo, Abuseipdb)
|
||||
go fetchAndLogInfo(&wg, ip, &ipapiisScore, &ipapiisInfo, Ipapiis)
|
||||
go fetchAndLogInfo(&wg, ip, &ipapiComScore, &ipapiComInfo, IpapiComIpv6)
|
||||
wg.Wait()
|
||||
// 构建非空信息
|
||||
var allScoreList []model.SecurityScore
|
||||
scorePointers := []*model.SecurityScore{scamalyticsScore, abuseipdbScore, ipapiisScore, ipapiComScore}
|
||||
for _, score := range scorePointers {
|
||||
if score != nil {
|
||||
allScoreList = append(allScoreList, *score)
|
||||
}
|
||||
}
|
||||
var allInfoList []model.SecurityInfo
|
||||
infoPointers := []*model.SecurityInfo{scamalyticsInfo, abuseipdbInfo, ipapiisInfo, ipapiComInfo, cheervisionInfo}
|
||||
for _, info := range infoPointers {
|
||||
if info != nil {
|
||||
allInfoList = append(allInfoList, *info)
|
||||
}
|
||||
}
|
||||
// 构建回传的文本内容
|
||||
temp += FormatSecurityScore(allScoreList)
|
||||
temp += "\n"
|
||||
temp += FormatSecurityInfo(allInfoList)
|
||||
// 分割输入为行
|
||||
lines := strings.Split(temp, "\n")
|
||||
// 初始化一个映射用于存储冒号之前的内容及其对应的行数
|
||||
contentMap := make(map[string][]int)
|
||||
// 遍历每一行,提取冒号之前的内容及其行数
|
||||
for i, line := range lines {
|
||||
// 如果行为空则跳过
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
// 切割行,以冒号为分隔符
|
||||
parts := strings.Split(line, ":")
|
||||
// 获取冒号之前的内容
|
||||
content := parts[0]
|
||||
// 将当前行的行号添加到映射中
|
||||
contentMap[content] = append(contentMap[content], i)
|
||||
}
|
||||
// 遍历映射,拼接相同内容的行
|
||||
for _, lineNumbers := range contentMap {
|
||||
if len(lineNumbers) > 1 { // 只对有多个行的内容进行拼接
|
||||
// 初始化一个字符串切片,用于存储拼接后的行
|
||||
var mergedLines []string
|
||||
// 遍历相同内容的行 添加当前行到拼接后的行中
|
||||
for _, lineNumber := range lineNumbers {
|
||||
if lineNumber == lineNumbers[0] {
|
||||
mergedLines = append(mergedLines, strings.TrimSpace(lines[lineNumber]))
|
||||
} else {
|
||||
mergedLines = append(mergedLines, strings.TrimSpace(strings.Split(lines[lineNumber], ":")[1]))
|
||||
}
|
||||
}
|
||||
// 将拼接后的行以空格连接起来
|
||||
mergedLine := strings.Join(mergedLines, " ")
|
||||
// 替换原始行中相同内容的行为拼接后的行,仅替换一次,其他行标注要删除
|
||||
isMerged := false
|
||||
for _, lineNumber := range lineNumbers {
|
||||
if !isMerged {
|
||||
lines[lineNumber] = mergedLine
|
||||
isMerged = true
|
||||
} else {
|
||||
lines[lineNumber] += "delete"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 删除对应的行,构建原始文本
|
||||
for _, line := range lines {
|
||||
if !strings.Contains(line, "delete") {
|
||||
orgin = orgin + line + "\n"
|
||||
}
|
||||
}
|
||||
orginList := strings.Split(orgin, "\n")
|
||||
var score model.SecurityScore
|
||||
scoreFields := utils.ExtractFieldNames(&score)
|
||||
var info model.SecurityInfo
|
||||
infoFields := utils.ExtractFieldNames(&info)
|
||||
// 拼接安全得分
|
||||
if language == "zh" {
|
||||
result += Blue("安全得分:") + "\n"
|
||||
} else if language == "en" {
|
||||
result = Blue("Security Score:") + "\n"
|
||||
}
|
||||
result += sortAndTranslateText(orginList, language, scoreFields)
|
||||
result += sortAndTranslateText(orginList, language, infoFields[:3])
|
||||
// 拼接完整安全信息
|
||||
if language == "zh" {
|
||||
result += Blue("安全信息:") + "\n"
|
||||
} else if language == "en" {
|
||||
result += Blue("Security Info:") + "\n"
|
||||
}
|
||||
result += sortAndTranslateText(orginList, language, infoFields[3:])
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// processPrintIPInfo 处理IP信息
|
||||
func processPrintIPInfo(headASNString string, headLocationString string, ipResult *model.IpInfo) string {
|
||||
var info string
|
||||
// 处理ASN信息
|
||||
if ipResult.ASN != "" || ipResult.Org != "" {
|
||||
info += headASNString
|
||||
if ipResult.ASN != "" {
|
||||
info += "AS" + ipResult.ASN
|
||||
if ipResult.Org != "" {
|
||||
info += " "
|
||||
}
|
||||
}
|
||||
info += ipResult.Org + "\n"
|
||||
}
|
||||
// 处理位置信息
|
||||
if ipResult.City != "" || ipResult.Region != "" || ipResult.Country != "" {
|
||||
info += headLocationString
|
||||
if ipResult.City != "" {
|
||||
info += ipResult.City + " / "
|
||||
}
|
||||
if ipResult.Region != "" {
|
||||
info += ipResult.Region + " / "
|
||||
}
|
||||
if ipResult.Country != "" {
|
||||
info += ipResult.Country
|
||||
}
|
||||
info += "\n"
|
||||
}
|
||||
return info
|
||||
}
|
||||
|
||||
// NetworkCheck 查询网络信息
|
||||
// checkType 可选 both ipv4 ipv6
|
||||
// enableSecurityCheck 可选 true false
|
||||
// language 暂时仅支持 en 或 zh
|
||||
// 回传 ipInfo securityInfo err
|
||||
// 本包在main中不使用
|
||||
func NetworkCheck(checkType string, enableSecurityCheck bool, language string) (string, string, error) {
|
||||
var ipInfo, securityInfo string
|
||||
if checkType == "both" {
|
||||
ipInfoV4Result, cheervisionInfoV4, ipInfoV6Result, cheervisionInfoV6, _ := baseinfo.RunIpCheck("both")
|
||||
if ipInfoV4Result != nil {
|
||||
ipInfo += processPrintIPInfo(" IPV4 ASN : ", " IPV4 Location : ", ipInfoV4Result)
|
||||
}
|
||||
if ipInfoV6Result != nil {
|
||||
ipInfo += processPrintIPInfo(" IPV6 ASN : ", " IPV6 Location : ", ipInfoV6Result)
|
||||
}
|
||||
// 检测是否需要查询相关安全信息
|
||||
if enableSecurityCheck {
|
||||
var (
|
||||
wg sync.WaitGroup
|
||||
ipv4Res, ipv6Res, ipv4DNSRes, ipv6DNSRes string
|
||||
err1, err2 error
|
||||
)
|
||||
wg.Add(4)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
ipv4DNSRes = BlackList(ipInfoV4Result, "ipv4", language)
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
ipv6DNSRes = BlackList(ipInfoV6Result, "ipv6", language)
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
ipv4Res, err1 = Ipv4SecurityCheck(ipInfoV4Result, cheervisionInfoV4, language)
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
ipv6Res, err2 = Ipv6SecurityCheck(ipInfoV6Result, cheervisionInfoV6, language)
|
||||
}()
|
||||
wg.Wait()
|
||||
securityHead, err3 := printhead.PrintDatabaseInfo(language)
|
||||
if err1 == nil && err2 == nil && err3 == nil {
|
||||
securityInfo = securityHead + Green("IPV4:") + "\n" + ipv4Res + ipv4DNSRes + Green("IPV6:") + "\n" + ipv6Res + ipv6DNSRes
|
||||
return ipInfo, securityInfo, nil
|
||||
} else if err1 == nil && err2 != nil && err3 == nil {
|
||||
securityInfo = securityHead + Green("IPV4:") + "\n" + ipv4Res + ipv4DNSRes
|
||||
return ipInfo, securityInfo, nil
|
||||
} else if err1 != nil && err2 == nil && err3 == nil {
|
||||
securityInfo = securityHead + Green("IPV6:") + "\n" + ipv6Res + ipv6DNSRes
|
||||
return ipInfo, securityInfo, nil
|
||||
} else {
|
||||
return ipInfo, "", nil
|
||||
}
|
||||
} else {
|
||||
return ipInfo, "", nil
|
||||
}
|
||||
} else if checkType == "ipv4" {
|
||||
ipInfoV4Result, cheervisionInfoV4, _, _, _ := baseinfo.RunIpCheck("ipv4")
|
||||
if ipInfoV4Result != nil {
|
||||
ipInfo += processPrintIPInfo(" IPV4 ASN : ", " IPV4 Location : ", ipInfoV4Result)
|
||||
}
|
||||
if enableSecurityCheck {
|
||||
var (
|
||||
wg sync.WaitGroup
|
||||
ipv4Res, ipv4DNSRes string
|
||||
err1 error
|
||||
)
|
||||
wg.Add(2)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
ipv4DNSRes = BlackList(ipInfoV4Result, "ipv4", language)
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
ipv4Res, err1 = Ipv4SecurityCheck(ipInfoV4Result, cheervisionInfoV4, language)
|
||||
}()
|
||||
wg.Wait()
|
||||
securityHead, err2 := printhead.PrintDatabaseInfo(language)
|
||||
if err1 == nil && err2 == nil {
|
||||
securityInfo = securityHead + Green("IPV4:") + "\n" + ipv4Res + ipv4DNSRes
|
||||
return ipInfo, securityInfo, nil
|
||||
} else {
|
||||
return ipInfo, "", nil
|
||||
}
|
||||
} else {
|
||||
return ipInfo, "", nil
|
||||
}
|
||||
} else if checkType == "ipv6" {
|
||||
_, _, ipInfoV6Result, cheervisionInfoV6, _ := baseinfo.RunIpCheck("ipv6")
|
||||
if ipInfoV6Result != nil {
|
||||
ipInfo += processPrintIPInfo(" IPV6 ASN : ", " IPV6 Location : ", ipInfoV6Result)
|
||||
}
|
||||
if enableSecurityCheck {
|
||||
var (
|
||||
wg sync.WaitGroup
|
||||
ipv6Res, ipv6DNSRes string
|
||||
err1 error
|
||||
)
|
||||
wg.Add(2)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
ipv6DNSRes = BlackList(ipInfoV6Result, "ipv6", language)
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
ipv6Res, err1 = Ipv6SecurityCheck(ipInfoV6Result, cheervisionInfoV6, language)
|
||||
}()
|
||||
wg.Wait()
|
||||
securityHead, err2 := printhead.PrintDatabaseInfo(language)
|
||||
if err1 == nil && err2 == nil {
|
||||
securityInfo = securityHead + Green("IPV6:") + "\n" + ipv6Res + ipv6DNSRes
|
||||
return ipInfo, securityInfo, nil
|
||||
} else {
|
||||
return ipInfo, "", nil
|
||||
}
|
||||
} else {
|
||||
return ipInfo, "", nil
|
||||
}
|
||||
}
|
||||
return "", "", fmt.Errorf("wrong in NetworkCheck")
|
||||
return network.NetworkCheck(checkType, enableSecurityCheck, language)
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
package network
|
||||
package network1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@@ -6,6 +6,7 @@ import (
|
||||
)
|
||||
|
||||
// 常用端口阻断检测 TCP/UDP/ICMP 协议
|
||||
// 本包不在main中使用
|
||||
func EmailCheck() {
|
||||
res := email.EmailCheck()
|
||||
fmt.Println(res)
|
||||
|
@@ -3,6 +3,7 @@ package speedtest
|
||||
import (
|
||||
"github.com/oneclickvirt/speedtest/model"
|
||||
"github.com/oneclickvirt/speedtest/sp"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -11,10 +12,14 @@ func ShowHead(language string) {
|
||||
}
|
||||
|
||||
func NearbySP() {
|
||||
sp.NearbySpeedTest()
|
||||
if runtime.GOOS == "windows" || sp.OfficialAvailableTest() != nil {
|
||||
sp.NearbySpeedTest()
|
||||
} else {
|
||||
sp.OfficialNearbySpeedTest()
|
||||
}
|
||||
}
|
||||
|
||||
func CustomSP(platform, operator string, num int) {
|
||||
func CustomSP(platform, operator string, num int, language string) {
|
||||
var url, parseType string
|
||||
if strings.ToLower(platform) == "cn" {
|
||||
if strings.ToLower(operator) == "cmcc" {
|
||||
@@ -53,5 +58,9 @@ func CustomSP(platform, operator string, num int) {
|
||||
}
|
||||
parseType = "id"
|
||||
}
|
||||
sp.CustomSpeedTest(url, parseType, num)
|
||||
if runtime.GOOS == "windows" || sp.OfficialAvailableTest() != nil {
|
||||
sp.CustomSpeedTest(url, parseType, num, language)
|
||||
} else {
|
||||
sp.OfficialCustomSpeedTest(url, parseType, num, language)
|
||||
}
|
||||
}
|
||||
|
@@ -1,30 +1,26 @@
|
||||
package unlocktest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/oneclickvirt/UnlockTests/utils"
|
||||
"github.com/oneclickvirt/UnlockTests/uts"
|
||||
"github.com/oneclickvirt/defaultset"
|
||||
)
|
||||
|
||||
func MediaTest(language string) {
|
||||
uts.GetIpv4Info(false)
|
||||
uts.GetIpv6Info(false)
|
||||
func MediaTest(language string) string {
|
||||
var res string
|
||||
readStatus := uts.ReadSelect(language, "0")
|
||||
if !readStatus {
|
||||
return
|
||||
return ""
|
||||
}
|
||||
//if language == "zh" {
|
||||
// fmt.Println("测试时间: ", defaultset.Yellow(time.Now().Format("2006-01-02 15:04:05")))
|
||||
//} else {
|
||||
// fmt.Println("Test time: ", defaultset.Yellow(time.Now().Format("2006-01-02 15:04:05")))
|
||||
//}
|
||||
if uts.IPV4 {
|
||||
fmt.Println(defaultset.Blue("IPV4:"))
|
||||
uts.RunTests(utils.Ipv4HttpClient, "ipv4", language)
|
||||
res += defaultset.Blue("IPV4:") + "\n"
|
||||
res += uts.RunTests(utils.Ipv4HttpClient, "ipv4", language, false)
|
||||
return res
|
||||
}
|
||||
if uts.IPV6 {
|
||||
fmt.Println(defaultset.Blue("IPV6:"))
|
||||
uts.RunTests(utils.Ipv6HttpClient, "ipv6", language)
|
||||
res += defaultset.Blue("IPV6:") + "\n"
|
||||
res += uts.RunTests(utils.Ipv6HttpClient, "ipv6", language, false)
|
||||
return res
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
@@ -1,7 +1,10 @@
|
||||
package unlocktest
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test(t *testing.T) {
|
||||
MediaTest("zh")
|
||||
fmt.Printf(MediaTest("zh"))
|
||||
}
|
||||
|
338
utils/utils.go
Normal file
338
utils/utils.go
Normal file
@@ -0,0 +1,338 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/imroc/req/v3"
|
||||
"github.com/oneclickvirt/UnlockTests/uts"
|
||||
"github.com/oneclickvirt/basics/ipv6"
|
||||
"github.com/oneclickvirt/basics/system"
|
||||
. "github.com/oneclickvirt/defaultset"
|
||||
"github.com/oneclickvirt/security/network"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// PrintCenteredTitle 根据指定的宽度打印居中标题
|
||||
func PrintCenteredTitle(title string, width int) {
|
||||
// 计算字符串的字符数
|
||||
titleLength := utf8.RuneCountInString(title)
|
||||
totalPadding := width - titleLength
|
||||
padding := totalPadding / 2
|
||||
paddingStr := strings.Repeat("-", padding)
|
||||
fmt.Println(paddingStr + title + paddingStr + strings.Repeat("-", totalPadding%2))
|
||||
}
|
||||
|
||||
// PrintHead 根据语言打印头部信息
|
||||
func PrintHead(language string, width int, ecsVersion string) {
|
||||
if language == "zh" {
|
||||
PrintCenteredTitle("VPS融合怪测试", width)
|
||||
fmt.Printf("版本:%s\n", ecsVersion)
|
||||
fmt.Println("测评频道: https://t.me/vps_reviews\n" +
|
||||
"Go项目地址:https://github.com/oneclickvirt/ecs\n" +
|
||||
"Shell项目地址:https://github.com/spiritLHLS/ecs")
|
||||
} else {
|
||||
PrintCenteredTitle("VPS Fusion Monster Test", width)
|
||||
fmt.Printf("Version: %s\n", ecsVersion)
|
||||
fmt.Println("Review Channel: https://t.me/vps_reviews\n" +
|
||||
"Go Project: https://github.com/oneclickvirt/ecs\n" +
|
||||
"Shell Project: https://github.com/spiritLHLS/ecs")
|
||||
}
|
||||
}
|
||||
|
||||
func CheckChina(enableLogger bool) bool {
|
||||
if enableLogger {
|
||||
InitLogger()
|
||||
defer Logger.Sync()
|
||||
}
|
||||
var selectChina bool
|
||||
client := req.C()
|
||||
client.SetTimeout(6 * time.Second)
|
||||
client.R().
|
||||
SetRetryCount(2).
|
||||
SetRetryBackoffInterval(1*time.Second, 3*time.Second).
|
||||
SetRetryFixedInterval(2 * time.Second)
|
||||
ipapiURL := "https://ipapi.co/json"
|
||||
ipapiResp, err := client.R().Get(ipapiURL)
|
||||
if err != nil {
|
||||
if enableLogger {
|
||||
Logger.Info("无法获取IP信息:" + err.Error())
|
||||
}
|
||||
return false
|
||||
}
|
||||
defer ipapiResp.Body.Close()
|
||||
ipapiBody, err := ipapiResp.ToString()
|
||||
if err != nil {
|
||||
if enableLogger {
|
||||
Logger.Info("无法读取IP信息响应:" + err.Error())
|
||||
}
|
||||
return false
|
||||
}
|
||||
isInChina := strings.Contains(ipapiBody, "China")
|
||||
if isInChina {
|
||||
fmt.Println("根据 ipapi.co 提供的信息,当前IP可能在中国")
|
||||
var input string
|
||||
fmt.Print("是否选用中国专项测试(无流媒体测试,有三网Ping值测试)? ([y]/n) ")
|
||||
fmt.Scanln(&input)
|
||||
switch strings.ToLower(input) {
|
||||
case "yes", "y":
|
||||
fmt.Println("使用中国专项测试")
|
||||
selectChina = true
|
||||
case "no", "n":
|
||||
fmt.Println("不使用中国专项测试")
|
||||
default:
|
||||
fmt.Println("使用中国专项测试")
|
||||
selectChina = true
|
||||
}
|
||||
}
|
||||
return selectChina
|
||||
}
|
||||
|
||||
// BasicsAndSecurityCheck 执行安全检查
|
||||
func BasicsAndSecurityCheck(language, nt3CheckType string, securtyCheckStatus bool) (string, string, string) {
|
||||
var wgt sync.WaitGroup
|
||||
var ipInfo, securityInfo, systemInfo string
|
||||
var err error
|
||||
wgt.Add(1)
|
||||
go func() {
|
||||
defer wgt.Done()
|
||||
ipInfo, securityInfo, err = network.NetworkCheck("both", securtyCheckStatus, language)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
}()
|
||||
wgt.Add(1)
|
||||
go func() {
|
||||
defer wgt.Done()
|
||||
systemInfo = system.CheckSystemInfo(language)
|
||||
}()
|
||||
wgt.Wait()
|
||||
ipv6Info, errv6 := ipv6.GetIPv6Mask(language)
|
||||
basicInfo := systemInfo + ipInfo
|
||||
if errv6 == nil && ipv6Info != "" {
|
||||
basicInfo += ipv6Info
|
||||
basicInfo += "\n"
|
||||
}
|
||||
if strings.Contains(ipInfo, "IPV4") && strings.Contains(ipInfo, "IPV6") {
|
||||
uts.IPV4 = true
|
||||
uts.IPV6 = true
|
||||
if nt3CheckType == "" {
|
||||
nt3CheckType = "ipv4"
|
||||
}
|
||||
} else if strings.Contains(ipInfo, "IPV4") {
|
||||
uts.IPV4 = true
|
||||
uts.IPV6 = false
|
||||
if nt3CheckType == "" {
|
||||
nt3CheckType = "ipv4"
|
||||
}
|
||||
} else if strings.Contains(ipInfo, "IPV6") {
|
||||
uts.IPV6 = true
|
||||
uts.IPV4 = false
|
||||
if nt3CheckType == "" {
|
||||
nt3CheckType = "ipv6"
|
||||
}
|
||||
}
|
||||
if nt3CheckType == "ipv4" && !strings.Contains(ipInfo, "IPV4") && strings.Contains(ipInfo, "IPV6") {
|
||||
nt3CheckType = "ipv6"
|
||||
} else if nt3CheckType == "ipv6" && !strings.Contains(ipInfo, "IPV6") && strings.Contains(ipInfo, "IPV4") {
|
||||
nt3CheckType = "ipv4"
|
||||
}
|
||||
basicInfo = strings.ReplaceAll(basicInfo, "\n\n", "\n")
|
||||
return basicInfo, securityInfo, nt3CheckType
|
||||
}
|
||||
|
||||
// CaptureOutput 捕获函数输出和错误输出,实时输出,并返回字符串
|
||||
func CaptureOutput(f func()) string {
|
||||
// 保存旧的 stdout 和 stderr
|
||||
oldStdout := os.Stdout
|
||||
oldStderr := os.Stderr
|
||||
// 创建管道
|
||||
stdoutPipeR, stdoutPipeW, err := os.Pipe()
|
||||
if err != nil {
|
||||
return "Error creating stdout pipe"
|
||||
}
|
||||
stderrPipeR, stderrPipeW, err := os.Pipe()
|
||||
if err != nil {
|
||||
stdoutPipeW.Close()
|
||||
stdoutPipeR.Close()
|
||||
return "Error creating stderr pipe"
|
||||
}
|
||||
// 替换标准输出和标准错误输出为管道写入端
|
||||
os.Stdout = stdoutPipeW
|
||||
os.Stderr = stderrPipeW
|
||||
// 恢复标准输出和标准错误输出
|
||||
defer func() {
|
||||
os.Stdout = oldStdout
|
||||
os.Stderr = oldStderr
|
||||
stdoutPipeW.Close()
|
||||
stderrPipeW.Close()
|
||||
stdoutPipeR.Close()
|
||||
stderrPipeR.Close()
|
||||
}()
|
||||
// 缓冲区
|
||||
var stdoutBuf, stderrBuf bytes.Buffer
|
||||
// 并发读取 stdout 和 stderr
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
multiWriter := io.MultiWriter(&stdoutBuf, oldStdout)
|
||||
io.Copy(multiWriter, stdoutPipeR)
|
||||
done <- struct{}{}
|
||||
}()
|
||||
go func() {
|
||||
multiWriter := io.MultiWriter(&stderrBuf, oldStderr)
|
||||
io.Copy(multiWriter, stderrPipeR)
|
||||
done <- struct{}{}
|
||||
}()
|
||||
// 执行函数
|
||||
f()
|
||||
// 关闭管道写入端,让管道读取端可以读取所有数据
|
||||
stdoutPipeW.Close()
|
||||
stderrPipeW.Close()
|
||||
// 等待两个 goroutine 完成
|
||||
<-done
|
||||
<-done
|
||||
// 返回捕获的输出字符串
|
||||
// stderrBuf.String()
|
||||
return stdoutBuf.String()
|
||||
}
|
||||
|
||||
// PrintAndCapture 捕获函数输出的同时打印内容
|
||||
func PrintAndCapture(f func(), tempOutput, output string) string {
|
||||
tempOutput = CaptureOutput(f)
|
||||
output += tempOutput
|
||||
return output
|
||||
}
|
||||
|
||||
// UploadText 上传文本内容到指定URL
|
||||
func UploadText(absPath string) (string, string, error) {
|
||||
primaryURL := "http://hpaste.spiritlhl.net/api/UL/upload"
|
||||
backupURL := "https://paste.spiritlhl.net/api/UL/upload"
|
||||
token := network.SecurityUploadToken
|
||||
client := req.C().SetTimeout(6 * time.Second)
|
||||
client.R().
|
||||
SetRetryCount(2).
|
||||
SetRetryBackoffInterval(1*time.Second, 5*time.Second).
|
||||
SetRetryFixedInterval(2 * time.Second)
|
||||
// 打开文件
|
||||
file, err := os.Open(absPath)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("failed to open file: %w", err)
|
||||
}
|
||||
defer file.Close()
|
||||
// 获取文件信息并检查大小
|
||||
fileInfo, err := file.Stat()
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("failed to get file info: %w", err)
|
||||
}
|
||||
if fileInfo.Size() > 25*1024 { // 25KB
|
||||
return "", "", fmt.Errorf("file size exceeds 25KB limit")
|
||||
}
|
||||
// 上传逻辑
|
||||
upload := func(url string) (string, string, error) {
|
||||
file, err := os.Open(absPath)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("failed to re-open file for %s: %w", url, err)
|
||||
}
|
||||
defer file.Close()
|
||||
content, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("failed to read file content for %s: %w", url, err)
|
||||
}
|
||||
resp, err := client.R().
|
||||
SetHeader("Authorization", token).
|
||||
SetFileBytes("file", filepath.Base(absPath), content).
|
||||
Post(url)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("failed to make request to %s: %w", url, err)
|
||||
}
|
||||
if resp.StatusCode >= 200 && resp.StatusCode <= 299 && resp.String() != "" {
|
||||
fileID := strings.TrimSpace(resp.String())
|
||||
if strings.Contains(fileID, "show") {
|
||||
fileID = fileID[strings.LastIndex(fileID, "/")+1:]
|
||||
}
|
||||
httpURL := fmt.Sprintf("http://hpaste.spiritlhl.net/#/show/%s", fileID)
|
||||
httpsURL := fmt.Sprintf("https://paste.spiritlhl.net/#/show/%s", fileID)
|
||||
return httpURL, httpsURL, nil
|
||||
}
|
||||
return "", "", fmt.Errorf("upload failed for %s with status code: %d", url, resp.StatusCode)
|
||||
}
|
||||
// 尝试上传到主URL
|
||||
httpURL, httpsURL, err := upload(primaryURL)
|
||||
if err == nil {
|
||||
return httpURL, httpsURL, nil
|
||||
}
|
||||
// 尝试上传到备份URL
|
||||
httpURL, httpsURL, err = upload(backupURL)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("failed to upload to both primary and backup URLs: %w", err)
|
||||
}
|
||||
return httpURL, httpsURL, nil
|
||||
}
|
||||
|
||||
// ProcessAndUpload 创建结果文件并上传文件
|
||||
func ProcessAndUpload(output string, filePath string, enableUplaod bool) (string, string) {
|
||||
// 使用 defer 来处理 panic
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
fmt.Printf("处理上传时发生错误: %v\n", r)
|
||||
}
|
||||
}()
|
||||
// 检查文件是否存在
|
||||
if _, err := os.Stat(filePath); err == nil {
|
||||
// 文件存在,删除文件
|
||||
err = os.Remove(filePath)
|
||||
if err != nil {
|
||||
fmt.Println("无法删除文件:", err)
|
||||
return "", ""
|
||||
}
|
||||
}
|
||||
// 创建文件
|
||||
file, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
fmt.Println("无法创建文件:", err)
|
||||
return "", ""
|
||||
}
|
||||
defer file.Close()
|
||||
// 匹配 ANSI 转义序列
|
||||
ansiRegex := regexp.MustCompile("\x1B\\[[0-9;]+[a-zA-Z]")
|
||||
// 移除 ANSI 转义序列
|
||||
cleanedOutput := ansiRegex.ReplaceAllString(output, "")
|
||||
// 使用 bufio.Writer 提高写入效率
|
||||
writer := bufio.NewWriter(file)
|
||||
_, err = writer.WriteString(cleanedOutput)
|
||||
if err != nil {
|
||||
fmt.Println("无法写入文件:", err)
|
||||
return "", ""
|
||||
}
|
||||
// 确保写入缓冲区的数据都刷新到文件中
|
||||
err = writer.Flush()
|
||||
if err != nil {
|
||||
fmt.Println("无法刷新文件缓冲:", err)
|
||||
return "", ""
|
||||
}
|
||||
fmt.Printf("测试结果已写入 %s\n", filePath)
|
||||
if enableUplaod {
|
||||
// 获取文件的绝对路径
|
||||
absPath, err := filepath.Abs(filePath)
|
||||
if err != nil {
|
||||
fmt.Println("无法获取文件绝对路径:", err)
|
||||
return "", ""
|
||||
}
|
||||
// 上传文件并生成短链接
|
||||
http_url, https_url, err := UploadText(absPath)
|
||||
if err != nil {
|
||||
fmt.Println("上传失败,无法生成链接")
|
||||
fmt.Println(err.Error())
|
||||
return "", ""
|
||||
}
|
||||
return http_url, https_url
|
||||
}
|
||||
return "", ""
|
||||
}
|
21
上传所有源码.bat
21
上传所有源码.bat
@@ -1,21 +0,0 @@
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
set repo_path=C:\Users\spiritlhl\Documents\GoWorks\ecs
|
||||
|
||||
git add -A
|
||||
git commit -am"update"
|
||||
|
||||
:push
|
||||
cd %repo_path%
|
||||
|
||||
git push -f origin master
|
||||
if errorlevel 1 (
|
||||
echo Push failed. Retrying in 3 seconds...
|
||||
timeout /nobreak /t 3 >nul
|
||||
goto push
|
||||
)
|
||||
|
||||
echo Push successful.
|
||||
|
||||
endlocal
|
37
发布版本.bat
37
发布版本.bat
@@ -1,37 +0,0 @@
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
REM 设置仓库路径
|
||||
set repo_path=C:\Users\spiritlhl\Documents\GoWorks\ecs
|
||||
|
||||
REM 进入仓库目录
|
||||
cd %repo_path%
|
||||
|
||||
REM 添加所有更改并提交
|
||||
git add -A
|
||||
git commit -am "update"
|
||||
|
||||
REM 推送代码到 master 分支并创建标签
|
||||
:push
|
||||
git push -f origin master
|
||||
if errorlevel 1 (
|
||||
echo Push failed. Retrying in 3 seconds...
|
||||
timeout /nobreak /t 3 >nul
|
||||
goto push
|
||||
)
|
||||
|
||||
REM 提示用户输入版本号
|
||||
set /p version="Enter the version number (e.g., v1.0.0): "
|
||||
|
||||
REM 创建并推送标签
|
||||
git tag %version%
|
||||
git push origin %version%
|
||||
if errorlevel 1 (
|
||||
echo Tag push failed. Retrying in 3 seconds...
|
||||
timeout /nobreak /t 3 >nul
|
||||
goto push_tag
|
||||
)
|
||||
|
||||
echo Push and tag creation successful.
|
||||
|
||||
endlocal
|
Reference in New Issue
Block a user