mirror of
https://github.com/oneclickvirt/ecs.git
synced 2025-09-27 11:42:23 +08:00
Compare commits
238 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
8394f3a78d | ||
![]() |
01e6bac876 | ||
![]() |
5a0bba48ae | ||
![]() |
49a4ef0543 | ||
![]() |
8f74567cbf | ||
![]() |
0f01bd359d | ||
![]() |
d40bc77ba9 | ||
![]() |
c730aa59b4 | ||
![]() |
8a77cff853 | ||
![]() |
8aaa05d45f | ||
![]() |
7e7b65c2b7 | ||
![]() |
65296157d9 | ||
![]() |
61d1607366 | ||
![]() |
8533cfd108 | ||
![]() |
8512f5e34b | ||
![]() |
2c509714a5 | ||
![]() |
a042b66c1e | ||
![]() |
5edf6ca24d | ||
![]() |
adf6fcbcd9 | ||
![]() |
c5445ed679 | ||
![]() |
a3c116a25d | ||
![]() |
84f2b41b05 | ||
![]() |
fca661388d | ||
![]() |
e5cf95b05f | ||
![]() |
dbceca7169 | ||
![]() |
86b28ef383 | ||
![]() |
c1a8695149 | ||
![]() |
ebcf2da2d8 | ||
![]() |
a7207afb50 | ||
![]() |
5aeaa0218a | ||
![]() |
8ac7230b06 | ||
![]() |
3c468794a3 | ||
![]() |
c764f60de9 | ||
![]() |
850c3cb129 | ||
![]() |
cee4e66ad0 | ||
![]() |
4cb5c67183 | ||
![]() |
ff040b1ed2 | ||
![]() |
d739f44bf3 | ||
![]() |
2be35bdffe | ||
![]() |
10e0d09c6f | ||
![]() |
6616da58cd | ||
![]() |
afa684f042 | ||
![]() |
25c1d60d2b | ||
![]() |
f4beb22fb2 | ||
![]() |
df9e4d2a78 | ||
![]() |
4facdad7b5 | ||
![]() |
5faea697b0 | ||
![]() |
07d09e4b41 | ||
![]() |
eb41920720 | ||
![]() |
7a4208ecd3 | ||
![]() |
416170ec30 | ||
![]() |
e26fa8312f | ||
![]() |
288a71f13f | ||
![]() |
ea1b982c0d | ||
![]() |
005bcd750d | ||
![]() |
d08008a51e | ||
![]() |
a5153cbdb4 | ||
![]() |
c20bcc2515 | ||
![]() |
691e934aa9 | ||
![]() |
578fc5338f | ||
![]() |
48c6d76863 | ||
![]() |
ed69abb382 | ||
![]() |
c807be29d8 | ||
![]() |
8554b9184a | ||
![]() |
e787c934c0 | ||
![]() |
a363ee6ee3 | ||
![]() |
ec731a4775 | ||
![]() |
cb8d8226b6 | ||
![]() |
6bd0a1c02d | ||
![]() |
a86f7c4d6c | ||
![]() |
12c5ece7bf | ||
![]() |
f34e182ae4 | ||
![]() |
9f3d1a1960 | ||
![]() |
c19b29e88a | ||
![]() |
2ccf5a9b09 | ||
![]() |
8d1a1c8b3b | ||
![]() |
c65b236a89 | ||
![]() |
c78ba25f02 | ||
![]() |
0a406e744e | ||
![]() |
acb8699211 | ||
![]() |
3b2493f770 | ||
![]() |
af6bda9b86 | ||
![]() |
4608e1bf3a | ||
![]() |
5f3c257158 | ||
![]() |
441b4d28ef | ||
![]() |
6c2c2a6791 | ||
![]() |
4eb982a22d | ||
![]() |
88c50e3c1c | ||
![]() |
c272da23fb | ||
![]() |
094b05ffbd | ||
![]() |
63d2c2be15 | ||
![]() |
9d540c1f94 | ||
![]() |
f9b588007f | ||
![]() |
cb261032fd | ||
![]() |
1fca387a39 | ||
![]() |
370695c670 | ||
![]() |
fa0cb5f194 | ||
![]() |
ba9a9e7cbd | ||
![]() |
66d907a68a | ||
![]() |
8f99d36b4f | ||
![]() |
76af1e9600 | ||
![]() |
6044e328f2 | ||
![]() |
fca03354bb | ||
![]() |
795eaede40 | ||
![]() |
2b7991df96 | ||
![]() |
90d664194b | ||
![]() |
fd62156564 | ||
![]() |
ebd581306c | ||
![]() |
695f13a129 | ||
![]() |
3941537061 | ||
![]() |
daf8f65c12 | ||
![]() |
06addade41 | ||
![]() |
8fda92a19c | ||
![]() |
03b7c1541c | ||
![]() |
7273321854 | ||
![]() |
0556680e61 | ||
![]() |
805809795e | ||
![]() |
e7ac550065 | ||
![]() |
2be8e0ee88 | ||
![]() |
e338f1a512 | ||
![]() |
48023f9ed1 | ||
![]() |
7f9fad3fea | ||
![]() |
d5d139e218 | ||
![]() |
35e0fd426d | ||
![]() |
7bf141e303 | ||
![]() |
12dbceca0d | ||
![]() |
e07d8b5114 | ||
![]() |
0ceb45d17c | ||
![]() |
0bbfa95b9c | ||
![]() |
f927185459 | ||
![]() |
c8271b713c | ||
![]() |
27f3bad9ef | ||
![]() |
dd85b0fd2d | ||
![]() |
47fdb43e54 | ||
![]() |
6e19ab79d7 | ||
![]() |
dee3211d3b | ||
![]() |
67a3bfdaad | ||
![]() |
e57ce05c0c | ||
![]() |
62137f0bb1 | ||
![]() |
f9d8c9ee4c | ||
![]() |
913a1725c1 | ||
![]() |
f1acbd361b | ||
![]() |
d6f62f8624 | ||
![]() |
94da890522 | ||
![]() |
42b94260de | ||
![]() |
16e2603176 | ||
![]() |
0ed9840038 | ||
![]() |
31b53e13b0 | ||
![]() |
fb697fa25f | ||
![]() |
2510b3ead0 | ||
![]() |
b64b8a2d96 | ||
![]() |
663614117d | ||
![]() |
a96c9b6c7d | ||
![]() |
e8f73ba4b8 | ||
![]() |
dd6fbff943 | ||
![]() |
e473851a02 | ||
![]() |
86fc407ccb | ||
![]() |
8e6037c340 | ||
![]() |
be59af4411 | ||
![]() |
7ae753a4e2 | ||
![]() |
3956420ffe | ||
![]() |
6ebe25af2d | ||
![]() |
fe02bd295a | ||
![]() |
172b520702 | ||
![]() |
d460e2b167 | ||
![]() |
03f5fd9e48 | ||
![]() |
0b0972cc3e | ||
![]() |
8273895def | ||
![]() |
3e31671502 | ||
![]() |
42b3ab3cff | ||
![]() |
0bef8161e7 | ||
![]() |
4f7e37f37c | ||
![]() |
c0dcea53e3 | ||
![]() |
02034da2d7 | ||
![]() |
aa6c835aed | ||
![]() |
2ebfdf7533 | ||
![]() |
28e21f0838 | ||
![]() |
23aae0b32b | ||
![]() |
abaf021e1c | ||
![]() |
be4e46ceba | ||
![]() |
4746ae14cf | ||
![]() |
eb702c4d97 | ||
![]() |
86bde156a4 | ||
![]() |
08be6238d2 | ||
![]() |
c0472209b4 | ||
![]() |
e751b76099 | ||
![]() |
bf653ab620 | ||
![]() |
c4b7ba00a1 | ||
![]() |
87a288907a | ||
![]() |
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 |
44
.github/workflows/build_docker.yaml
vendored
44
.github/workflows/build_docker.yaml
vendored
@@ -1,44 +0,0 @@
|
|||||||
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
|
|
66
.github/workflows/ci.yaml_back
vendored
66
.github/workflows/ci.yaml_back
vendored
@@ -1,66 +0,0 @@
|
|||||||
name: go-ci
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
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 ./goecs_test.go
|
|
||||||
# env:
|
|
||||||
# GOPRIVATE: github.com/oneclickvirt/security
|
|
||||||
# GITHUB_TOKEN: ${{ secrets.GHT }}
|
|
42
.github/workflows/main.yaml
vendored
42
.github/workflows/main.yaml
vendored
@@ -1,42 +0,0 @@
|
|||||||
name: goreleaser
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
tags:
|
|
||||||
- "v*.*.*"
|
|
||||||
|
|
||||||
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@v4
|
|
||||||
with:
|
|
||||||
go-version: 1.22.4
|
|
||||||
|
|
||||||
- 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: Run GoReleaser
|
|
||||||
uses: goreleaser/goreleaser-action@v2
|
|
||||||
with:
|
|
||||||
distribution: goreleaser
|
|
||||||
version: latest
|
|
||||||
args: release
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GHT }}
|
|
||||||
GOPRIVATE: github.com/oneclickvirt/security
|
|
56
.github/workflows/sync.yaml
vendored
56
.github/workflows/sync.yaml
vendored
@@ -1,56 +0,0 @@
|
|||||||
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 }}
|
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +0,0 @@
|
|||||||
vendor/
|
|
@@ -1,78 +0,0 @@
|
|||||||
before:
|
|
||||||
hooks:
|
|
||||||
- go mod tidy -v
|
|
||||||
builds:
|
|
||||||
- id: universal
|
|
||||||
env:
|
|
||||||
- CGO_ENABLED=0
|
|
||||||
ldflags:
|
|
||||||
- -s -w -X main.version={{.Version}} -X main.arch={{.Arch}}
|
|
||||||
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}}
|
|
||||||
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}}
|
|
||||||
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>
|
|
17
Dockerfile
17
Dockerfile
@@ -1,17 +0,0 @@
|
|||||||
# 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"]
|
|
674
LICENSE
674
LICENSE
@@ -1,674 +0,0 @@
|
|||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
Version 3, 29 June 2007
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Preamble
|
|
||||||
|
|
||||||
The GNU General Public License is a free, copyleft license for
|
|
||||||
software and other kinds of works.
|
|
||||||
|
|
||||||
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>.
|
|
307
README.md
307
README.md
@@ -1,292 +1,39 @@
|
|||||||
# ECS
|
# CPU性能测试排行榜
|
||||||
|
|
||||||
[](https://github.com/oneclickvirt/ecs/actions/workflows/main.yaml) [](https://www.spiritlhl.net/)
|
本目录包含CPU性能测试的结果和排行榜数据。
|
||||||
|
|
||||||
融合怪测评项目 - GO 重构版本
|
## 文件说明
|
||||||
|
|
||||||
如有问题请 [issues](https://github.com/oneclickvirt/ecs/issues) 反馈。
|
### 主要文件
|
||||||
|
- `index.html`: 排行榜网页展示页面
|
||||||
|
- `all_cpu_results.json`: 包含所有CPU测试结果的完整数据
|
||||||
|
- `CNAME`: GitHub Pages自定义域名配置文件
|
||||||
|
|
||||||
Go 版本:[https://github.com/oneclickvirt/ecs](https://github.com/oneclickvirt/ecs)
|
### CSV文件夹 (csvs/)
|
||||||
|
- `all_cpus_single_core_ranking.csv`: 所有CPU单核性能排行榜
|
||||||
|
- `all_cpus_multi_core_ranking.csv`: 所有CPU多核性能排行榜
|
||||||
|
- `{CPU型号}_single_core.csv`: 特定CPU型号的单核性能排行
|
||||||
|
- `{CPU型号}_multi_core.csv`: 特定CPU型号的多核性能排行
|
||||||
|
|
||||||
Shell 版本:[https://github.com/spiritLHLS/ecs](https://github.com/spiritLHLS/ecs)
|
## 在线查看
|
||||||
|
|
||||||
---
|
可通过 https://sysbench.spiritlhl.net 访问。
|
||||||
|
|
||||||
## **语言**
|
## 数据字段说明
|
||||||
|
|
||||||
[中文文档](README.md) | [English Docs](README_EN.md)
|
| 字段名 | 说明 |
|
||||||
|
|--------|------|
|
||||||
|
| 排名 | 在当前排序中的排名 |
|
||||||
|
| CPU型号 | 完整的CPU型号信息 |
|
||||||
|
| CPU核心数 | CPU的核心数量 |
|
||||||
|
| 单核得分 | 单核性能测试得分 |
|
||||||
|
| 多核得分 | 多核性能测试得分 |
|
||||||
|
| 多核线程数 | 多核测试使用的线程数 |
|
||||||
|
|
||||||
---
|
## 更新时间
|
||||||
|
|
||||||
## **适配系统和架构**
|
最后更新时间: 2025-09-27 01:39:10 UTC
|
||||||
|
|
||||||
### **编译支持的架构**
|
## 数据来源
|
||||||
|
|
||||||
- amd64、arm、arm64、386、mips、mipsle、s390x、riscv64
|
|
||||||
|
|
||||||
### **测试支持的架构**
|
|
||||||
|
|
||||||
- amd64、arm64
|
|
||||||
|
|
||||||
> 更多架构请自行测试。
|
|
||||||
|
|
||||||
### **编译支持的系统**
|
|
||||||
|
|
||||||
- Linux、Windows、MacOS、FreeBSD、OpenBSD
|
|
||||||
|
|
||||||
### **测试支持的系统**
|
|
||||||
|
|
||||||
- Linux、Windows
|
|
||||||
|
|
||||||
> 更多系统请自行测试。
|
|
||||||
|
|
||||||
### **待支持的系统**
|
|
||||||
|
|
||||||
- MacOS、FreeBSD、OpenBSD(存在硬件测试 BUG 未修复)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## **功能**
|
|
||||||
|
|
||||||
- 系统基础信息查询:
|
|
||||||
自研 [basics](https://github.com/oneclickvirt/basics)、[gostun](https://github.com/oneclickvirt/gostun)
|
|
||||||
- IP 基础信息并发查询:
|
|
||||||
自研 [basics](https://github.com/oneclickvirt/basics)
|
|
||||||
- CPU 测试:
|
|
||||||
自研 [cputest](https://github.com/oneclickvirt/cputest),支持 sysbench、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
|
|
||||||
```
|
|
||||||
|
|
||||||
#### **命令参数化**
|
|
||||||
|
|
||||||
```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
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **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
|
|
||||||
```
|
|
||||||
|
|
||||||
## QA
|
|
||||||
|
|
||||||
#### Q: 为什么默认使用sysbench而不是geekbench
|
|
||||||
|
|
||||||
#### A: 比较二者特点
|
|
||||||
|
|
||||||
```
|
|
||||||
sysbench geekbench
|
|
||||||
轻量几乎所有服务器都能跑 重型小机器跑不动
|
|
||||||
测试无联网需求,无硬件需求 测试必须联网,且必须IPV4环境并有内存大小1G的最低需求
|
|
||||||
LUA编写且开源,各架构系统可自行编译 仅官方二进制文件且不开源,无对应架构时无法自行编译
|
|
||||||
核心测试组件十多年不变 每次大版本更新对标的CPU,不同版本间得分互相之间难转化,你只能以对标的CPU为准
|
|
||||||
测试仅测试计算性能 测试涵盖多种性能测试,得分以权重计算,但实际很多测试项目实际是用不到的
|
|
||||||
适合快速测试 适合全面测试
|
|
||||||
```
|
|
||||||
|
|
||||||
且```goecs```测试使用何种CPU测试方式可使用参数指定,默认只是为了更多用户快速测试的需求
|
|
||||||
|
|
||||||
#### Q: 为什么使用Golang而不是Rust重构
|
|
||||||
|
|
||||||
#### A: 因为网络相关的项目目前以Golang语言为趋势,大多组件有开源生态维护,Rust很多得自己手搓,~~我懒得搞~~我没那个技术力
|
|
||||||
|
|
||||||
#### Q: 为什么不继续开发Shell版本而是选择重构
|
|
||||||
|
|
||||||
#### A: 因为太多千奇百怪的环境问题了,还是提前编译好测试的二进制文件比较容易解决环境问题(泛化性更好)
|
|
||||||
|
|
||||||
#### Q: 每个测试项目的说明有吗?
|
|
||||||
|
|
||||||
#### A: 每个测试项目有对应的维护仓库,自行点击查看仓库说明
|
|
||||||
|
|
||||||
|
数据来源于用户提交的CPU性能测试结果,经过自动化脚本处理和排序生成。
|
||||||
|
224
README_EN.md
224
README_EN.md
@@ -1,224 +0,0 @@
|
|||||||
# ecs
|
|
||||||
|
|
||||||
[](https://github.com/oneclickvirt/ecs/actions/workflows/main.yaml) [](https://www.spiritlhl.net/)
|
|
||||||
|
|
||||||
Fusion Monster Evaluation Script - GO Refactored Version
|
|
||||||
|
|
||||||
Please report any issues via 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
|
|
||||||
|
|
||||||
More architectures please test by yourself
|
|
||||||
|
|
||||||
Compilation support: Linux, Windows、MacOS、FreeBSD、OpenBSD
|
|
||||||
|
|
||||||
Tested on: Linux, Windows
|
|
||||||
|
|
||||||
More systems to be tested
|
|
||||||
|
|
||||||
Systems to be supported (hardware testing bugs not yet fixed): MacOS、FreeBSD、OpenBSD
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
- [x] System basic information query [Self-developed [basics](https://github.com/oneclickvirt/basics), [gostun](https://github.com/oneclickvirt/gostun)]
|
|
||||||
- [x] Concurrent IP basic information query [Self-developed [basics](https://github.com/oneclickvirt/basics)]
|
|
||||||
- [x] CPU test [Self-developed [cputest](https://github.com/oneclickvirt/cputest) supporting sysbench, geekbench, winsat]
|
|
||||||
- [x] Memory test [Self-developed [memorytest](https://github.com/oneclickvirt/memorytest) supporting sysbench, dd]
|
|
||||||
- [x] Disk test [Self-developed [disktest](https://github.com/oneclickvirt/disktest) supporting dd, fio, winsat]
|
|
||||||
- [x] Concurrent streaming media unlock information query for three major platforms [Modified from [netflix-verify](https://github.com/sjlleo/netflix-verify), [VerifyDisneyPlus](https://github.com/sjlleo/VerifyDisneyPlus), [TubeCheck](https://github.com/sjlleo/TubeCheck) to [CommonMediaTests](https://github.com/oneclickvirt/CommonMediaTests)]
|
|
||||||
- [x] Concurrent common streaming media tests [Self-developed code, logic modified from [RegionRestrictionCheck](https://github.com/lmc999/RegionRestrictionCheck), [MediaUnlockTest](https://github.com/HsukqiLee/MediaUnlockTest) to [UnlockTests](https://github.com/oneclickvirt/UnlockTests)]
|
|
||||||
- [x] Concurrent IP quality/security information query [Self-developed, due to testing with key information, privately developed, but binary files compiled in [securityCheck](https://github.com/oneclickvirt/securityCheck)]
|
|
||||||
- [x] Email port test [Self-developed [portchecker](https://github.com/oneclickvirt/portchecker)]
|
|
||||||
- [x] Three-network return path test [Modified from [zhanghanyun/backtrace](https://github.com/zhanghanyun/backtrace) to [oneclickvirt/backtrace](https://github.com/oneclickvirt/backtrace)]
|
|
||||||
- [x] Three-network route test [Modified from [NTrace-core](https://github.com/nxtrace/NTrace-core) to [nt3](https://github.com/oneclickvirt/nt3)]
|
|
||||||
- [x] Speed test [Based on data from [speedtest.net-crawler](https://github.com/spiritLHLS/speedtest.net-CN-ID), [speedtest.cn-crawler](https://github.com/spiritLHLS/speedtest.cn-CN-ID), modified from [speedtest-go](https://github.com/showwin/speedtest-go) to [oneclickvirt/speedtest](https://github.com/oneclickvirt/speedtest)]
|
|
||||||
- [x] Three-network Ping test [Modified from [ecsspeed](https://github.com/spiritLHLS/ecsspeed) logic to [pingtest](https://github.com/oneclickvirt/pingtest)]
|
|
||||||
|
|
||||||
## Instructions for Use on Linux/FreeBSD/MacOS
|
|
||||||
|
|
||||||
### one-click command
|
|
||||||
|
|
||||||
```
|
|
||||||
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
|
|
||||||
```
|
|
||||||
|
|
||||||
### explain in detail
|
|
||||||
|
|
||||||
Download the script
|
|
||||||
|
|
||||||
```
|
|
||||||
curl -L https://raw.githubusercontent.com/oneclickvirt/ecs/master/goecs.sh -o goecs.sh && chmod +x goecs.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
Install environment
|
|
||||||
|
|
||||||
```
|
|
||||||
./goecs.sh env
|
|
||||||
```
|
|
||||||
|
|
||||||
If you don't want interaction, use ```export noninteractive=true``` and then execute the ```env``` command
|
|
||||||
|
|
||||||
Install goecs
|
|
||||||
|
|
||||||
```
|
|
||||||
./goecs.sh install
|
|
||||||
```
|
|
||||||
|
|
||||||
Upgrade goecs
|
|
||||||
|
|
||||||
```
|
|
||||||
./goecs.sh upgrade
|
|
||||||
```
|
|
||||||
|
|
||||||
Uninstall goecs
|
|
||||||
|
|
||||||
```
|
|
||||||
./goecs.sh uninstall
|
|
||||||
```
|
|
||||||
|
|
||||||
Explanation of the shell script
|
|
||||||
|
|
||||||
```
|
|
||||||
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
|
|
||||||
```
|
|
||||||
|
|
||||||
Invoke the goecs menu
|
|
||||||
|
|
||||||
```
|
|
||||||
goecs -l en
|
|
||||||
```
|
|
||||||
|
|
||||||
or
|
|
||||||
|
|
||||||
```
|
|
||||||
./goecs -l en
|
|
||||||
```
|
|
||||||
|
|
||||||
Parameterized goecs command
|
|
||||||
|
|
||||||
```
|
|
||||||
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
|
|
||||||
```
|
|
||||||
|
|
||||||
## Instructions for Use on Windows
|
|
||||||
|
|
||||||
Download the compressed file with the exe file
|
|
||||||
|
|
||||||
https://github.com/oneclickvirt/ecs/releases
|
|
||||||
|
|
||||||
Find the latest version, download the .zip file corresponding to your architecture, and unzip it to get an exe file.
|
|
||||||
|
|
||||||
Right-click the exe file and select Run as administrator (running without administrator mode will not allow hardware testing), and invoke the menu to choose.
|
|
||||||
|
|
||||||
No environment installation is required for Windows testing.
|
|
||||||
|
|
||||||
## Instructions for Use in Docker
|
|
||||||
|
|
||||||
Link: https://hub.docker.com/r/spiritlhl/goecs
|
|
||||||
|
|
||||||
Please make sure that 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
|
|
||||||
```
|
|
||||||
|
|
||||||
Using Docker to execute tests, hardware testing will have some bias and virtualization architecture to determine the failure.
|
|
||||||
|
|
||||||
Recommended direct testing without using Docker testing.
|
|
@@ -1,9 +0,0 @@
|
|||||||
package backtrace
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/oneclickvirt/backtrace/bk"
|
|
||||||
)
|
|
||||||
|
|
||||||
func BackTrace() {
|
|
||||||
backtrace.BackTrace()
|
|
||||||
}
|
|
@@ -1,20 +0,0 @@
|
|||||||
package backtrace
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
//func TestGeneratePrefixMap(t *testing.T) {
|
|
||||||
// prefix := "223.119.8.0/21"
|
|
||||||
// prefixList := GeneratePrefixList(prefix)
|
|
||||||
// if prefixList != nil {
|
|
||||||
// // 打印生成的IP地址前缀列表
|
|
||||||
// for _, ip := range prefixList {
|
|
||||||
// fmt.Println(ip)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
func TestBackTrace(t *testing.T) {
|
|
||||||
BackTrace()
|
|
||||||
}
|
|
@@ -1,9 +0,0 @@
|
|||||||
package basic1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_basic(t *testing.T) {
|
|
||||||
Basic("zh")
|
|
||||||
}
|
|
@@ -1,16 +0,0 @@
|
|||||||
package basic1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/oneclickvirt/basics/network"
|
|
||||||
"github.com/oneclickvirt/basics/system"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 本包不在main中使用,仅做测试使用,真正调用的在 utils 中的 BasicsAndSecurityCheck
|
|
||||||
func Basic(language string) {
|
|
||||||
ipInfo, _, _ := network.NetworkCheck("both", false, language)
|
|
||||||
systemInfo := system.CheckSystemInfo(language)
|
|
||||||
basicInfo := strings.ReplaceAll(systemInfo+ipInfo, "\n\n", "\n")
|
|
||||||
fmt.Printf(basicInfo)
|
|
||||||
}
|
|
@@ -1,11 +0,0 @@
|
|||||||
package commediatest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/oneclickvirt/CommonMediaTests/commediatests"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ComMediaTest(language string) {
|
|
||||||
res := commediatests.MediaTests(language)
|
|
||||||
fmt.Printf(res)
|
|
||||||
}
|
|
@@ -1,9 +0,0 @@
|
|||||||
package commediatest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMedia(t *testing.T) {
|
|
||||||
ComMediaTest("zh")
|
|
||||||
}
|
|
19034
cpu_statistics.json
Normal file
19034
cpu_statistics.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,39 +0,0 @@
|
|||||||
package cputest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/oneclickvirt/cputest/cpu"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func CpuTest(language, testMethod, testThread string) {
|
|
||||||
var res string
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
if testMethod != "winsat" && testMethod != "" {
|
|
||||||
res = "Detected host is Windows, using Winsat for testing.\n"
|
|
||||||
}
|
|
||||||
res += cpu.WinsatTest(language, testThread)
|
|
||||||
} else {
|
|
||||||
switch testMethod {
|
|
||||||
case "sysbench":
|
|
||||||
res = cpu.SysBenchTest(language, testThread)
|
|
||||||
if res == "" {
|
|
||||||
res = "Sysbench test failed, switching to Geekbench for testing.\n"
|
|
||||||
res += cpu.GeekBenchTest(language, testThread)
|
|
||||||
}
|
|
||||||
case "geekbench":
|
|
||||||
res = cpu.GeekBenchTest(language, testThread)
|
|
||||||
if res == "" {
|
|
||||||
res = "Geekbench test failed, switching to Sysbench for testing.\n"
|
|
||||||
res += cpu.SysBenchTest(language, testThread)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
res = "Invalid test method specified.\n"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !strings.Contains(res, "\n") && res != "" {
|
|
||||||
res += "\n"
|
|
||||||
}
|
|
||||||
fmt.Print(res)
|
|
||||||
}
|
|
@@ -1,9 +0,0 @@
|
|||||||
package cputest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test(t *testing.T) {
|
|
||||||
CpuTest("zh", "sysbench", "1")
|
|
||||||
}
|
|
@@ -1,41 +0,0 @@
|
|||||||
package disktest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/oneclickvirt/disktest/disk"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func DiskTest(language, testMethod, testPath string, isMultiCheck bool, autoChange bool) {
|
|
||||||
var res string
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
if testMethod != "winsat" && testMethod != "" {
|
|
||||||
res = "Detected host is Windows, using Winsat for testing.\n"
|
|
||||||
}
|
|
||||||
res = disk.WinsatTest(language, isMultiCheck, testPath)
|
|
||||||
} else {
|
|
||||||
switch testMethod {
|
|
||||||
case "fio":
|
|
||||||
res = disk.FioTest(language, isMultiCheck, testPath)
|
|
||||||
if res == "" && autoChange {
|
|
||||||
res = "Fio test failed, switching to DD for testing.\n"
|
|
||||||
res += disk.DDTest(language, isMultiCheck, testPath)
|
|
||||||
}
|
|
||||||
case "dd":
|
|
||||||
res = disk.DDTest(language, isMultiCheck, testPath)
|
|
||||||
if res == "" && autoChange {
|
|
||||||
res = "DD test failed, switching to Fio for testing.\n"
|
|
||||||
res += disk.FioTest(language, isMultiCheck, testPath)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
res = "Unsupported test method specified.\n"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//fmt.Println("--------------------------------------------------")
|
|
||||||
if !strings.Contains(res, "\n") && res != "" {
|
|
||||||
res += "\n"
|
|
||||||
}
|
|
||||||
fmt.Printf(res)
|
|
||||||
//fmt.Println("--------------------------------------------------")
|
|
||||||
}
|
|
@@ -1,7 +0,0 @@
|
|||||||
package disktest
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func TestDiskIoTest(t *testing.T) {
|
|
||||||
DiskTest("zh", "sysbench", "", false)
|
|
||||||
}
|
|
116
go.mod
116
go.mod
@@ -1,116 +0,0 @@
|
|||||||
module github.com/oneclickvirt/ecs
|
|
||||||
|
|
||||||
go 1.22.4
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/imroc/req/v3 v3.49.0
|
|
||||||
github.com/oneclickvirt/CommonMediaTests v0.0.4-20240704024502
|
|
||||||
github.com/oneclickvirt/UnlockTests v0.0.22-20241221103638
|
|
||||||
github.com/oneclickvirt/backtrace v0.0.4-20240702140722
|
|
||||||
github.com/oneclickvirt/basics v0.0.8-20241108124433
|
|
||||||
github.com/oneclickvirt/cputest v0.0.8-20240702070215
|
|
||||||
github.com/oneclickvirt/defaultset v0.0.2-20240624082446
|
|
||||||
github.com/oneclickvirt/disktest v0.0.4-20240809053456
|
|
||||||
github.com/oneclickvirt/gostun v0.0.3-20240702054621
|
|
||||||
github.com/oneclickvirt/memorytest v0.0.4-20240820095126
|
|
||||||
github.com/oneclickvirt/nt3 v0.0.3-20240809100110
|
|
||||||
github.com/oneclickvirt/pingtest v0.0.5-20241006123443
|
|
||||||
github.com/oneclickvirt/portchecker v0.0.2-20240803151204
|
|
||||||
github.com/oneclickvirt/security v0.0.4-20240729065854
|
|
||||||
github.com/oneclickvirt/speedtest v0.0.8-20241005164804
|
|
||||||
)
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/PuerkitoBio/goquery v1.9.2 // 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.5.0 // indirect
|
|
||||||
github.com/fatih/color v1.17.0 // indirect
|
|
||||||
github.com/fsnotify/fsnotify v1.7.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/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-20241210010833-40e02aabc2ad // indirect
|
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
|
||||||
github.com/gorilla/websocket v1.5.2 // 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/jackpal/go-nat-pmp v1.0.2 // 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/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
|
||||||
github.com/magiconair/properties v1.8.7 // indirect
|
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
|
||||||
github.com/mattn/go-runewidth v0.0.15 // 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/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.2 // 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.2 // 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/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.6.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/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/pflag v1.0.5 // 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/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.5.0 // indirect
|
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
|
||||||
go.uber.org/zap v1.27.0 // indirect
|
|
||||||
golang.org/x/crypto v0.31.0 // indirect
|
|
||||||
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect
|
|
||||||
golang.org/x/mod v0.22.0 // indirect
|
|
||||||
golang.org/x/net v0.33.0 // indirect
|
|
||||||
golang.org/x/sync v0.10.0 // indirect
|
|
||||||
golang.org/x/sys v0.28.0 // indirect
|
|
||||||
golang.org/x/term v0.27.0 // indirect
|
|
||||||
golang.org/x/text v0.21.0 // indirect
|
|
||||||
golang.org/x/tools v0.28.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
|
|
||||||
)
|
|
329
go.sum
329
go.sum
@@ -1,329 +0,0 @@
|
|||||||
github.com/PuerkitoBio/goquery v1.9.2 h1:4/wZksC3KgkQw7SQgkKotmKljk0M6V8TUvA8Wb4yPeE=
|
|
||||||
github.com/PuerkitoBio/goquery v1.9.2/go.mod h1:GHPCaP0ODyyxqcNoFGYlAprUFH81NuRPd0GX3Zu2Mvk=
|
|
||||||
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.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/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
|
|
||||||
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
|
|
||||||
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/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/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/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-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.2 h1:qoW6V1GT3aZxybsbC6oLnailWnB+qTMVwMreOso9XUw=
|
|
||||||
github.com/gorilla/websocket v1.5.2/go.mod h1:0n9H61RBAcf5/38py2MCYbxzPIY9rOkpvvMT24Rqs30=
|
|
||||||
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=
|
|
||||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
|
||||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
|
||||||
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.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/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.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=
|
|
||||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
|
||||||
github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk=
|
|
||||||
github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk=
|
|
||||||
github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU=
|
|
||||||
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/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.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/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/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/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.2 h1:8aU/IQFmPnwbaWGVBIJHwwVIWk+roo+9+lG+U0OFZ+o=
|
|
||||||
github.com/nxtrace/NTrace-core v1.3.2/go.mod h1:qCVsgSs982jw02BVjTtN8mjSg5OIXW9TaUdISQrMnTw=
|
|
||||||
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.22-20241221103638 h1:31Ek7CLX94vWzbU4fysqCxn7scC53Zk4OhlaB3OQDYQ=
|
|
||||||
github.com/oneclickvirt/UnlockTests v0.0.22-20241221103638/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.8-20241108124433 h1:eKZcoNoa9uLWmfisk+qN/QOvSGT4ajCmZdZfIAcHG+o=
|
|
||||||
github.com/oneclickvirt/basics v0.0.8-20241108124433/go.mod h1:fUdVpU8gdjaZsTCyqnQBAbHc9BbbN8Fxr3sGPKooUpU=
|
|
||||||
github.com/oneclickvirt/cputest v0.0.8-20240702070215 h1:CcFpyVPlQkJ6vjFP17BRuJhh/afiJhOhZ0BW+TtfVDg=
|
|
||||||
github.com/oneclickvirt/cputest v0.0.8-20240702070215/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.4-20240809053456 h1:g6fKzvImIV8YQZKKEJ2FdvooL+EUf9NndAU8c4aGCX4=
|
|
||||||
github.com/oneclickvirt/disktest v0.0.4-20240809053456/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.3-20240809100110 h1:UyF0jBDP0xpxSV9L/GYG83SKUMPSjHPru+3iPZHYG7U=
|
|
||||||
github.com/oneclickvirt/nt3 v0.0.3-20240809100110/go.mod h1:4SDl5o83wbixk9YJqvG0eNo2w8aWt/QgntfPBi9wEpY=
|
|
||||||
github.com/oneclickvirt/pingtest v0.0.5-20241006123443 h1:Ywrh0Yd/PYXOKGE8VaNiKGWlIqdgLLgsthAzxy0t7s8=
|
|
||||||
github.com/oneclickvirt/pingtest v0.0.5-20241006123443/go.mod h1:d3Ntx5m9lMll3a/k3+2B+5emj//vgDh4/NHTxs2qQE8=
|
|
||||||
github.com/oneclickvirt/portchecker v0.0.2-20240803151204 h1:ZruxRgyIv3d6Y8n0Ney5FHhQtcQLxCvs+xJmGsh9/7E=
|
|
||||||
github.com/oneclickvirt/portchecker v0.0.2-20240803151204/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.8-20241005164804 h1:qguczGucxyRCRaeI2Av7+QpgYb6o8lTJJmOjPkmGiSg=
|
|
||||||
github.com/oneclickvirt/speedtest v0.0.8-20241005164804/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.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
|
||||||
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=
|
|
||||||
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
|
|
||||||
github.com/pion/stun/v2 v2.0.0 h1:A5+wXKLAypxQri59+tmQKVs7+l6mMM+3d+eER9ifRU0=
|
|
||||||
github.com/pion/stun/v2 v2.0.0/go.mod h1:22qRSh08fSEttYUmJZGlriq9+03jtVmXNODgLccj8GQ=
|
|
||||||
github.com/pion/transport/v2 v2.2.1 h1:7qYnCBlpgSJNYMbLCKuSY9KbQdBFoETvPNETv0y4N7c=
|
|
||||||
github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g=
|
|
||||||
github.com/pion/transport/v3 v3.0.1 h1:gDTlPJwROfSfz6QfSi0ZmeCSkFcnWWiiR9ES0ouANiM=
|
|
||||||
github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0=
|
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
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/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/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.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk=
|
|
||||||
github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0=
|
|
||||||
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/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/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.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.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/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/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=
|
|
||||||
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
|
||||||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
|
||||||
github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
|
|
||||||
github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
|
|
||||||
github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY=
|
|
||||||
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.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=
|
|
||||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
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.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
|
||||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
|
||||||
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo=
|
|
||||||
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
|
||||||
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.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=
|
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
|
||||||
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.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
|
||||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
|
||||||
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.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.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
|
||||||
golang.org/x/sys v0.28.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=
|
|
||||||
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.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
|
|
||||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
|
||||||
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.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
|
||||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
|
||||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
|
||||||
golang.org/x/time v0.5.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.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
|
|
||||||
golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
|
|
||||||
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=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
|
||||||
google.golang.org/protobuf v1.35.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=
|
|
583
goecs.go
583
goecs.go
@@ -1,583 +0,0 @@
|
|||||||
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/commediatest"
|
|
||||||
"github.com/oneclickvirt/ecs/cputest"
|
|
||||||
"github.com/oneclickvirt/ecs/disktest"
|
|
||||||
"github.com/oneclickvirt/ecs/memorytest"
|
|
||||||
"github.com/oneclickvirt/ecs/ntrace"
|
|
||||||
"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"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ecsVersion = "v0.1.01"
|
|
||||||
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() {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
if showVersion {
|
|
||||||
fmt.Println(ecsVersion)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
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
|
|
||||||
)
|
|
||||||
// 设置主程序的信号处理
|
|
||||||
sig := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(sig, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
|
|
||||||
// 启动一个goroutine来等待信号,内置计时器
|
|
||||||
go func() {
|
|
||||||
startTime = time.Now()
|
|
||||||
// 等待信号
|
|
||||||
<-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")
|
|
||||||
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)
|
|
||||||
utils.ProcessAndUpload(output, filePath, enabelUpload)
|
|
||||||
}
|
|
||||||
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.
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
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
|
|
||||||
currentTime := time.Now().Format("Mon Jan 2 15:04:05 MST 2006")
|
|
||||||
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
|
|
||||||
currentTime := time.Now().Format("Mon Jan 2 15:04:05 MST 2006")
|
|
||||||
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")
|
|
||||||
}
|
|
||||||
utils.ProcessAndUpload(output, filePath, enabelUpload)
|
|
||||||
finish = true
|
|
||||||
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
|
|
||||||
fmt.Println("Press Enter to exit...")
|
|
||||||
fmt.Scanln()
|
|
||||||
}
|
|
||||||
}
|
|
732
goecs.sh
732
goecs.sh
@@ -1,732 +0,0 @@
|
|||||||
#!/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=true
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
# 如果 ipapi.co 检测失败,尝试使用 cip.cc
|
|
||||||
if ! curl -m 6 -s https://ipapi.co/json >/dev/null 2>&1; then
|
|
||||||
if curl -m 6 -s cip.cc | grep -q "中国"; then
|
|
||||||
_yellow "根据cip.cc提供的信息,当前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=true
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
CN=false
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
CN=false
|
|
||||||
fi
|
|
||||||
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() {
|
|
||||||
os=$(uname -s)
|
|
||||||
arch=$(uname -m)
|
|
||||||
# 先进行中国IP检测
|
|
||||||
check_china
|
|
||||||
ECS_VERSION=$(curl -m 6 -sSL "https://api.github.com/repos/oneclickvirt/ecs/releases/latest" | awk -F \" '/tag_name/{gsub(/^v/,"",$4); print $4}')
|
|
||||||
# 如果 https://api.github.com/ 请求失败,则使用 https://githubapi.spiritlhl.workers.dev/ ,此时可能宿主机无IPV4网络
|
|
||||||
if [ -z "$ECS_VERSION" ]; then
|
|
||||||
ECS_VERSION=$(curl -m 6 -sSL "https://githubapi.spiritlhl.workers.dev/repos/oneclickvirt/ecs/releases/latest" | awk -F \" '/tag_name/{gsub(/^v/,"",$4); print $4}')
|
|
||||||
fi
|
|
||||||
# 如果 https://githubapi.spiritlhl.workers.dev/ 请求失败,则使用 https://githubapi.spiritlhl.top/ ,此时可能宿主机在国内
|
|
||||||
if [ -z "$ECS_VERSION" ]; then
|
|
||||||
ECS_VERSION=$(curl -m 6 -sSL "https://githubapi.spiritlhl.top/repos/oneclickvirt/ecs/releases/latest" | awk -F \" '/tag_name/{gsub(/^v/,"",$4); print $4}')
|
|
||||||
fi
|
|
||||||
# 检测原始goecs命令是否存在,若存在则升级,不存在则安装
|
|
||||||
version_output=$(goecs -v command 2>/dev/null || ./goecs -v command 2>/dev/null)
|
|
||||||
if [ $? -eq 0 ]; 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 latest, no need to upgrade."
|
|
||||||
return
|
|
||||||
else
|
|
||||||
_yellow "goecs version ($extracted_version) < $ecs_version, need to upgrade, 5 seconds later will start to upgrade"
|
|
||||||
rm -rf /usr/bin/goecs
|
|
||||||
rm -rf goecs
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
_green "Can not find goecs, need to download and install, 5 seconds later will start to install"
|
|
||||||
fi
|
|
||||||
sleep 5
|
|
||||||
if [[ "$CN" == true ]]; then
|
|
||||||
_yellow "使用中国镜像下载..."
|
|
||||||
case $os in
|
|
||||||
Linux)
|
|
||||||
case $arch in
|
|
||||||
"x86_64" | "x86" | "amd64" | "x64")
|
|
||||||
download_file "https://cnb.cool/oneclickvirt/ecs/-/git/raw/main/goecs_linux_amd64.zip" "goecs.zip"
|
|
||||||
;;
|
|
||||||
"i386" | "i686")
|
|
||||||
download_file "https://cnb.cool/oneclickvirt/ecs/-/git/raw/main/goecs_linux_386.zip" "goecs.zip"
|
|
||||||
;;
|
|
||||||
"armv7l" | "armv8" | "armv8l" | "aarch64" | "arm64")
|
|
||||||
download_file "https://cnb.cool/oneclickvirt/ecs/-/git/raw/main/goecs_linux_arm64.zip" "goecs.zip"
|
|
||||||
;;
|
|
||||||
"mips")
|
|
||||||
download_file "https://cnb.cool/oneclickvirt/ecs/-/git/raw/main/goecs_linux_mips.zip" "goecs.zip"
|
|
||||||
;;
|
|
||||||
"mipsle")
|
|
||||||
download_file "https://cnb.cool/oneclickvirt/ecs/-/git/raw/main/goecs_linux_mipsle.zip" "goecs.zip"
|
|
||||||
;;
|
|
||||||
"s390x")
|
|
||||||
download_file "https://cnb.cool/oneclickvirt/ecs/-/git/raw/main/goecs_linux_s390x.zip" "goecs.zip"
|
|
||||||
;;
|
|
||||||
"riscv64")
|
|
||||||
download_file "https://cnb.cool/oneclickvirt/ecs/-/git/raw/main/goecs_linux_riscv64.zip" "goecs.zip"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
_red "不支持的架构: $arch"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
FreeBSD)
|
|
||||||
case $arch in
|
|
||||||
"x86_64" | "x86" | "amd64" | "x64")
|
|
||||||
download_file "https://cnb.cool/oneclickvirt/ecs/-/git/raw/main/goecs_freebsd_amd64.zip" "goecs.zip"
|
|
||||||
;;
|
|
||||||
"i386" | "i686")
|
|
||||||
download_file "https://cnb.cool/oneclickvirt/ecs/-/git/raw/main/goecs_freebsd_386.zip" "goecs.zip"
|
|
||||||
;;
|
|
||||||
"armv7l" | "armv8" | "armv8l" | "aarch64" | "arm64")
|
|
||||||
download_file "https://cnb.cool/oneclickvirt/ecs/-/git/raw/main/goecs_freebsd_arm64.zip" "goecs.zip"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
_red "不支持的架构: $arch"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
Darwin)
|
|
||||||
case $arch in
|
|
||||||
"x86_64" | "x86" | "amd64" | "x64")
|
|
||||||
download_file "https://cnb.cool/oneclickvirt/ecs/-/git/raw/main/goecs_darwin_amd64.zip" "goecs.zip"
|
|
||||||
;;
|
|
||||||
"armv7l" | "armv8" | "armv8l" | "aarch64" | "arm64")
|
|
||||||
download_file "https://cnb.cool/oneclickvirt/ecs/-/git/raw/main/goecs_darwin_arm64.zip" "goecs.zip"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
_red "不支持的架构: $arch"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
_red "不支持的操作系统: $os"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
else
|
|
||||||
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")
|
|
||||||
download_file "${cdn_success_url}https://github.com/oneclickvirt/ecs/releases/download/v${ECS_VERSION}/goecs_linux_amd64.zip" "goecs.zip"
|
|
||||||
;;
|
|
||||||
"i386" | "i686")
|
|
||||||
download_file "${cdn_success_url}https://github.com/oneclickvirt/ecs/releases/download/v${ECS_VERSION}/goecs_linux_386.zip" "goecs.zip"
|
|
||||||
;;
|
|
||||||
"armv7l" | "armv8" | "armv8l" | "aarch64" | "arm64")
|
|
||||||
download_file "${cdn_success_url}https://github.com/oneclickvirt/ecs/releases/download/v${ECS_VERSION}/goecs_linux_arm64.zip" "goecs.zip"
|
|
||||||
;;
|
|
||||||
"mips")
|
|
||||||
download_file "${cdn_success_url}https://github.com/oneclickvirt/ecs/releases/download/v${ECS_VERSION}/goecs_linux_mips.zip" "goecs.zip"
|
|
||||||
;;
|
|
||||||
"mipsle")
|
|
||||||
download_file "${cdn_success_url}https://github.com/oneclickvirt/ecs/releases/download/v${ECS_VERSION}/goecs_linux_mipsle.zip" "goecs.zip"
|
|
||||||
;;
|
|
||||||
"s390x")
|
|
||||||
download_file "${cdn_success_url}https://github.com/oneclickvirt/ecs/releases/download/v${ECS_VERSION}/goecs_linux_s390x.zip" "goecs.zip"
|
|
||||||
;;
|
|
||||||
"riscv64")
|
|
||||||
download_file "${cdn_success_url}https://github.com/oneclickvirt/ecs/releases/download/v${ECS_VERSION}/goecs_linux_riscv64.zip" "goecs.zip"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
_red "Unsupported architecture: $arch , please check https://github.com/oneclickvirt/ecs/releases to download the zip for yourself and unzip it to use the binary for testing."
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
FreeBSD)
|
|
||||||
case $arch in
|
|
||||||
"x86_64" | "x86" | "amd64" | "x64")
|
|
||||||
download_file "${cdn_success_url}https://github.com/oneclickvirt/ecs/releases/download/v${ECS_VERSION}/goecs_freebsd_amd64.zip" "goecs.zip"
|
|
||||||
;;
|
|
||||||
"i386" | "i686")
|
|
||||||
download_file "${cdn_success_url}https://github.com/oneclickvirt/ecs/releases/download/v${ECS_VERSION}/goecs_freebsd_386.zip" "goecs.zip"
|
|
||||||
;;
|
|
||||||
"armv7l" | "armv8" | "armv8l" | "aarch64" | "arm64")
|
|
||||||
download_file "${cdn_success_url}https://github.com/oneclickvirt/ecs/releases/download/v${ECS_VERSION}/goecs_freebsd_arm64.zip" "goecs.zip"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
_red "Unsupported architecture: $arch , please check https://github.com/oneclickvirt/ecs/releases to download the zip for yourself and unzip it to use the binary for testing."
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
Darwin)
|
|
||||||
case $arch in
|
|
||||||
"x86_64" | "x86" | "amd64" | "x64")
|
|
||||||
download_file "${cdn_success_url}https://github.com/oneclickvirt/ecs/releases/download/v${ECS_VERSION}/goecs_amd64.zip" "goecs.zip"
|
|
||||||
;;
|
|
||||||
"armv7l" | "armv8" | "armv8l" | "aarch64" | "arm64")
|
|
||||||
download_file "${cdn_success_url}https://github.com/oneclickvirt/ ecs/releases/download/v${ECS_VERSION}/goecs_arm64.zip" "goecs.zip"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
_red "Unsupported architecture: $arch , please check https://github.com/oneclickvirt/ecs/releases to download the zip for yourself and unzip it to use the binary for testing."
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
_red "Unsupported operating system: $os , please check https://github.com/oneclickvirt/ecs/releases to download the zip for yourself and unzip it to use the binary for testing."
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
unzip goecs.zip
|
|
||||||
rm -rf goecs.zip
|
|
||||||
rm -rf README.md
|
|
||||||
rm -rf LICENSE
|
|
||||||
sleep 1
|
|
||||||
chmod 777 goecs
|
|
||||||
rm -rf /usr/bin/goecs
|
|
||||||
sleep 1
|
|
||||||
cp goecs /usr/bin/goecs
|
|
||||||
rm -rf README_EN.md
|
|
||||||
rm -rf README.md
|
|
||||||
PARAM="net.ipv4.ping_group_range"
|
|
||||||
NEW_VALUE="0 2147483647"
|
|
||||||
CURRENT_VALUE=$(sysctl -n "$PARAM" 2>/dev/null)
|
|
||||||
if [ -f /etc/sysctl.conf ] && [ "$CURRENT_VALUE" != "$NEW_VALUE" ]; then
|
|
||||||
if grep -q "^$PARAM" /etc/sysctl.conf; then
|
|
||||||
sudo sed -i "s/^$PARAM.*/$PARAM = $NEW_VALUE/" /etc/sysctl.conf
|
|
||||||
else
|
|
||||||
echo "$PARAM = $NEW_VALUE" | sudo tee -a /etc/sysctl.conf
|
|
||||||
fi
|
|
||||||
sudo sysctl -p
|
|
||||||
fi
|
|
||||||
setcap cap_net_raw=+ep goecs
|
|
||||||
setcap cap_net_raw=+ep /usr/bin/goecs
|
|
||||||
echo "goecs 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")
|
|
||||||
# 检查系统信息
|
|
||||||
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
|
|
||||||
[[ -n $SYS ]] || exit 1
|
|
||||||
|
|
||||||
# 匹配操作系统
|
|
||||||
for ((int = 0; int < ${#REGEX[@]}; int++)); do
|
|
||||||
if [[ $(echo "$SYS" | tr '[:upper:]' '[:lower:]') =~ ${REGEX[int]} ]]; then
|
|
||||||
SYSTEM="${RELEASE[int]}"
|
|
||||||
[[ -n $SYSTEM ]] && break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# 检查是否成功匹配
|
|
||||||
[[ -n $SYSTEM ]] || exit 1
|
|
||||||
|
|
||||||
# 根据 SYSTEM 设置相应的包管理命令
|
|
||||||
UPDATE_CMD=${PACKAGE_UPDATE[int]}
|
|
||||||
INSTALL_CMD=${PACKAGE_INSTALL[int]}
|
|
||||||
REMOVE_CMD=${PACKAGE_REMOVE[int]}
|
|
||||||
UNINSTALL_CMD=${PACKAGE_UNINSTALL[int]}
|
|
||||||
|
|
||||||
echo "System: $SYSTEM"
|
|
||||||
echo "Update command: $UPDATE_CMD"
|
|
||||||
echo "Install command: $INSTALL_CMD"
|
|
||||||
echo "Remove command: $REMOVE_CMD"
|
|
||||||
echo "Uninstall command: $UNINSTALL_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 significant time to complete"
|
|
||||||
_yellow "2. Cause temporary network interruptions"
|
|
||||||
_yellow "3. Impact system stability"
|
|
||||||
_yellow "4. Affect future system startup"
|
|
||||||
if [ "$noninteractive" != "true" ]; then
|
|
||||||
reading "Do you want to proceed with system update? (y/N): " update_confirm
|
|
||||||
if [[ ! $update_confirm =~ ^[Yy]$ ]]; then
|
|
||||||
_yellow "Skipping system update"
|
|
||||||
_yellow "Note: Some package installations may fail"
|
|
||||||
else
|
|
||||||
_green "Updating system package manager..."
|
|
||||||
if ! ${PACKAGE_UPDATE[int]} 2>/dev/null; then
|
|
||||||
_red "System update failed!"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 安装必要的命令
|
|
||||||
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"
|
|
||||||
${PACKAGE_INSTALL[int]} "$cmd"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if ! command -v sysbench >/dev/null 2>&1; then
|
|
||||||
_green "Installing sysbench"
|
|
||||||
${PACKAGE_INSTALL[int]} sysbench
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo "Unable to download sysbench through the system's package manager, trying to compile and install it..."
|
|
||||||
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
|
|
||||||
|
|
||||||
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
|
|
||||||
_blue "If you do not want to use geekbench5, you can use"
|
|
||||||
echo "bash dgb.sh -v gb6"
|
|
||||||
echo "bash dgb.sh -v gb4"
|
|
||||||
_blue "to change version, or use"
|
|
||||||
echo "rm -rf /usr/bin/geekbench*"
|
|
||||||
_blue "to uninstall geekbench"
|
|
||||||
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
|
|
||||||
_blue "if you want to use golang original speedtest, you can use"
|
|
||||||
echo "rm -rf /usr/bin/speedtest"
|
|
||||||
echo "rm -rf /usr/bin/speedtest-go"
|
|
||||||
_blue "to uninstall speedtest and speedtest-go"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! command -v ping >/dev/null 2>&1; then
|
|
||||||
_green "Installing ping"
|
|
||||||
${PACKAGE_INSTALL[int]} iputils-ping >/dev/null 2>&1
|
|
||||||
${PACKAGE_INSTALL[int]} ping >/dev/null 2>&1
|
|
||||||
fi
|
|
||||||
|
|
||||||
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 "The environment is ready."
|
|
||||||
_green "The 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 显示此消息
|
|
||||||
|
|
||||||
[English version follows...]
|
|
||||||
|
|
||||||
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,9 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test(t *testing.T) {
|
|
||||||
main()
|
|
||||||
}
|
|
816
index.html
Executable file
816
index.html
Executable file
@@ -0,0 +1,816 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta name="google-site-verification" content="wdrGBim_2XmtMrqxivze70saMiPQAiOhpmN3KAWb0Sw" />
|
||||||
|
<title>CPU Performance Ladder For Sysbench</title>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
background: #fafafa;
|
||||||
|
color: #37352f;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 40px 20px;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 48px;
|
||||||
|
padding-bottom: 24px;
|
||||||
|
border-bottom: 1px solid #e9e9e7;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.header h1 {
|
||||||
|
font-size: 32px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #2d2d2d;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
.header p {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #6b6b6b;
|
||||||
|
}
|
||||||
|
.language-toggle {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #e9e9e7;
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.language-toggle button {
|
||||||
|
padding: 8px 16px;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 12px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
color: #6b6b6b;
|
||||||
|
}
|
||||||
|
.language-toggle button.active {
|
||||||
|
background: #0066cc;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.language-toggle button:hover:not(.active) {
|
||||||
|
background: #f7f7f5;
|
||||||
|
}
|
||||||
|
.controls {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.search-box {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 200px;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.search-box input {
|
||||||
|
flex: 1;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border: 1px solid #e9e9e7;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
background: white;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
.search-box input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #0066cc;
|
||||||
|
box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1);
|
||||||
|
}
|
||||||
|
.search-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
.search-btn {
|
||||||
|
padding: 12px 16px;
|
||||||
|
border: 1px solid #e9e9e7;
|
||||||
|
background: white;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
color: #6b6b6b;
|
||||||
|
}
|
||||||
|
.search-btn:hover {
|
||||||
|
background: #f7f7f5;
|
||||||
|
}
|
||||||
|
.search-btn.search {
|
||||||
|
background: #0066cc;
|
||||||
|
color: white;
|
||||||
|
border-color: #0066cc;
|
||||||
|
}
|
||||||
|
.search-btn.clear {
|
||||||
|
background: #e91e63;
|
||||||
|
color: white;
|
||||||
|
border-color: #e91e63;
|
||||||
|
}
|
||||||
|
.view-toggle {
|
||||||
|
display: flex;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #e9e9e7;
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.view-toggle button {
|
||||||
|
padding: 12px 20px;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
.view-toggle button.active {
|
||||||
|
background: #0066cc;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.view-toggle button:hover:not(.active) {
|
||||||
|
background: #f7f7f5;
|
||||||
|
}
|
||||||
|
.stats-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
.stat-card {
|
||||||
|
background: white;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 12px;
|
||||||
|
border: 1px solid #e9e9e7;
|
||||||
|
text-align: center;
|
||||||
|
transition: transform 0.2s ease;
|
||||||
|
}
|
||||||
|
.stat-card:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 8px 25px -8px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
.stat-value {
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #0066cc;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
.stat-label {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #6b6b6b;
|
||||||
|
}
|
||||||
|
.pagination {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.pagination button {
|
||||||
|
padding: 8px 16px;
|
||||||
|
border: 1px solid #e9e9e7;
|
||||||
|
background: white;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
.pagination button:hover:not(:disabled) {
|
||||||
|
background: #f7f7f5;
|
||||||
|
}
|
||||||
|
.pagination button:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
.pagination button.active {
|
||||||
|
background: #0066cc;
|
||||||
|
color: white;
|
||||||
|
border-color: #0066cc;
|
||||||
|
}
|
||||||
|
.pagination-info {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #6b6b6b;
|
||||||
|
}
|
||||||
|
.page-jump {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.page-jump input {
|
||||||
|
width: 60px;
|
||||||
|
padding: 6px 8px;
|
||||||
|
border: 1px solid #e9e9e7;
|
||||||
|
border-radius: 4px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.page-jump button {
|
||||||
|
padding: 6px 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.cpu-groups {
|
||||||
|
display: grid;
|
||||||
|
gap: 24px;
|
||||||
|
}
|
||||||
|
.cpu-group {
|
||||||
|
background: white;
|
||||||
|
border-radius: 12px;
|
||||||
|
border: 1px solid #e9e9e7;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
.cpu-group:hover {
|
||||||
|
box-shadow: 0 4px 20px -4px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
.group-header {
|
||||||
|
padding: 20px 24px;
|
||||||
|
background: #f7f7f5;
|
||||||
|
border-bottom: 1px solid #e9e9e7;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.group-header:hover {
|
||||||
|
background: #f0f0ef;
|
||||||
|
}
|
||||||
|
.group-title-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
.rank-badge {
|
||||||
|
background: #0066cc;
|
||||||
|
color: white;
|
||||||
|
padding: 4px 12px;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
min-width: 40px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.group-title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #2d2d2d;
|
||||||
|
}
|
||||||
|
.group-stats {
|
||||||
|
display: flex;
|
||||||
|
gap: 24px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #6b6b6b;
|
||||||
|
}
|
||||||
|
.expand-icon {
|
||||||
|
transition: transform 0.2s ease;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.cpu-group.expanded .expand-icon {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
.group-content {
|
||||||
|
max-height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: max-height 0.3s ease;
|
||||||
|
}
|
||||||
|
.cpu-group.expanded .group-content {
|
||||||
|
max-height: 2000px;
|
||||||
|
}
|
||||||
|
.cpu-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
.cpu-table th,
|
||||||
|
.cpu-table td {
|
||||||
|
padding: 16px 24px;
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid #f0f0ef;
|
||||||
|
}
|
||||||
|
.cpu-table th {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #6b6b6b;
|
||||||
|
font-size: 12px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
.cpu-table td {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.cpu-table tbody tr:hover {
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
.score-cell {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.score-single {
|
||||||
|
color: #0066cc;
|
||||||
|
}
|
||||||
|
.score-multi {
|
||||||
|
color: #e91e63;
|
||||||
|
}
|
||||||
|
.loading {
|
||||||
|
text-align: center;
|
||||||
|
padding: 60px 20px;
|
||||||
|
color: #6b6b6b;
|
||||||
|
}
|
||||||
|
.spinner {
|
||||||
|
display: inline-block;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border: 3px solid #f0f0ef;
|
||||||
|
border-top: 3px solid #0066cc;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: spin 1s linear infinite;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
@keyframes spin {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.no-data {
|
||||||
|
text-align: center;
|
||||||
|
padding: 60px 20px;
|
||||||
|
color: #6b6b6b;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
margin-top: 60px;
|
||||||
|
padding: 32px 0;
|
||||||
|
border-top: 1px solid #e9e9e7;
|
||||||
|
text-align: center;
|
||||||
|
background: white;
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
.footer-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.footer-links {
|
||||||
|
display: flex;
|
||||||
|
gap: 32px;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.footer-link {
|
||||||
|
color: #0066cc;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 14px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
transition: color 0.2s ease;
|
||||||
|
}
|
||||||
|
.footer-link:hover {
|
||||||
|
color: #004499;
|
||||||
|
}
|
||||||
|
.footer-text {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #6b6b6b;
|
||||||
|
}
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.container {
|
||||||
|
padding: 20px 16px;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
position: static;
|
||||||
|
}
|
||||||
|
.language-toggle {
|
||||||
|
position: static;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
.header h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
.controls {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
.search-box {
|
||||||
|
min-width: auto;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.search-buttons {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.stats-grid {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
.stat-card {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
.stat-value {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
.group-stats {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.group-title-section {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
.cpu-table {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.cpu-table th,
|
||||||
|
.cpu-table td {
|
||||||
|
padding: 12px 16px;
|
||||||
|
}
|
||||||
|
.pagination {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.footer-links {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<div class="language-toggle">
|
||||||
|
<button id="langZh" class="active">中文</button>
|
||||||
|
<button id="langEn">English</button>
|
||||||
|
</div>
|
||||||
|
<h1 data-zh="CPU Performance Ladder For Sysbench" data-en="CPU Performance Ladder For Sysbench">CPU Performance Ladder For Sysbench</h1>
|
||||||
|
<p data-zh="Sysbench天梯图" data-en="Sysbench CPU Benchmark Rankings">Sysbench天梯图</p>
|
||||||
|
</div>
|
||||||
|
<div class="controls">
|
||||||
|
<div class="search-box">
|
||||||
|
<input type="text" id="searchInput" placeholder="搜索CPU型号或关键词..." data-placeholder-zh="搜索CPU型号或关键词..." data-placeholder-en="Search CPU model or keywords...">
|
||||||
|
<div class="search-buttons">
|
||||||
|
<button id="searchBtn" class="search-btn search" data-zh="搜索" data-en="Search">搜索</button>
|
||||||
|
<button id="clearBtn" class="search-btn clear" data-zh="清除" data-en="Clear">清除</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="view-toggle">
|
||||||
|
<button id="compactView" class="active" data-zh="紧凑视图" data-en="Compact View">紧凑视图</button>
|
||||||
|
<button id="detailView" data-zh="详细视图" data-en="Detail View">详细视图</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="stats-grid" id="statsGrid">
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-value" id="totalCpus">-</div>
|
||||||
|
<div class="stat-label" data-zh="CPU型号总数" data-en="Total CPU Models">CPU型号总数</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-value" id="totalTests">-</div>
|
||||||
|
<div class="stat-label" data-zh="测试样本数" data-en="Test Samples">测试样本数</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-value" id="topSingle">-</div>
|
||||||
|
<div class="stat-label" data-zh="最高单核分数" data-en="Highest Single Score">最高单核分数</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-value" id="topMulti">-</div>
|
||||||
|
<div class="stat-label" data-zh="最高多核分数" data-en="Highest Multi Score">最高多核分数</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="loadingIndicator" class="loading">
|
||||||
|
<div class="spinner"></div>
|
||||||
|
<div data-zh="正在加载CPU数据..." data-en="Loading CPU data...">正在加载CPU数据...</div>
|
||||||
|
</div>
|
||||||
|
<div class="pagination" id="pagination" style="display: none;">
|
||||||
|
<button id="prevPage" data-zh="上一页" data-en="Previous">上一页</button>
|
||||||
|
<div class="pagination-info" id="pageInfo">-</div>
|
||||||
|
<div class="page-jump">
|
||||||
|
<span data-zh="跳转到" data-en="Go to">跳转到</span>
|
||||||
|
<input type="number" id="pageInput" min="1">
|
||||||
|
<span data-zh="页" data-en="page">页</span>
|
||||||
|
<button id="jumpBtn" data-zh="跳转" data-en="Go">跳转</button>
|
||||||
|
</div>
|
||||||
|
<button id="nextPage" data-zh="下一页" data-en="Next">下一页</button>
|
||||||
|
</div>
|
||||||
|
<div id="cpuGroups" class="cpu-groups" style="display: none;"></div>
|
||||||
|
<div id="noData" class="no-data" style="display: none;">
|
||||||
|
<div data-zh="📄 未找到CPU数据文件" data-en="📄 CPU data file not found">📄 未找到CPU数据文件</div>
|
||||||
|
<p data-zh="请确保 cpu_statistics.json 文件存在于当前目录" data-en="Please ensure cpu_statistics.json file exists in current directory">请确保 cpu_statistics.json 文件存在于当前目录</p>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<div class="footer-content">
|
||||||
|
<div class="footer-links">
|
||||||
|
<a href="https://github.com/oneclickvirt/ecs" class="footer-link" target="_blank" rel="noopener">
|
||||||
|
<span>🚀</span>
|
||||||
|
<span data-zh="测试脚本" data-en="Test Script">测试脚本</span>
|
||||||
|
</a>
|
||||||
|
<a href="https://www.spiritlhl.net/" class="footer-link" target="_blank" rel="noopener">
|
||||||
|
<span>🌐</span>
|
||||||
|
<span data-zh="spiritlhl 官网" data-en="spiritlhl Official">spiritlhl 官网</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="footer-text" data-zh="本项目隶属于 spiritlhl 旗下" data-en="This project is under spiritlhl">本项目隶属于 spiritlhl 旗下</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
class CPUDashboard {
|
||||||
|
constructor() {
|
||||||
|
this.data = [];
|
||||||
|
this.groupedData = {};
|
||||||
|
this.filteredGroups = {};
|
||||||
|
this.sortedPrefixes = [];
|
||||||
|
this.allSortedPrefixes = [];
|
||||||
|
this.prefixRanks = {};
|
||||||
|
this.isDetailView = false;
|
||||||
|
this.searchTerm = '';
|
||||||
|
this.currentPage = 1;
|
||||||
|
this.itemsPerPage = 10;
|
||||||
|
this.currentLang = 'zh';
|
||||||
|
this.total_samples = 0;
|
||||||
|
this.initializeEventListeners();
|
||||||
|
this.loadData();
|
||||||
|
}
|
||||||
|
initializeEventListeners() {
|
||||||
|
const searchInput = document.getElementById('searchInput');
|
||||||
|
const searchBtn = document.getElementById('searchBtn');
|
||||||
|
const clearBtn = document.getElementById('clearBtn');
|
||||||
|
const performSearch = () => {
|
||||||
|
this.searchTerm = searchInput.value.toLowerCase();
|
||||||
|
this.currentPage = 1;
|
||||||
|
this.filterAndRender();
|
||||||
|
};
|
||||||
|
searchInput.addEventListener('keypress', (e) => {
|
||||||
|
if (e.key === 'Enter') performSearch();
|
||||||
|
});
|
||||||
|
searchBtn.addEventListener('click', performSearch);
|
||||||
|
clearBtn.addEventListener('click', () => {
|
||||||
|
searchInput.value = '';
|
||||||
|
this.searchTerm = '';
|
||||||
|
this.currentPage = 1;
|
||||||
|
this.filterAndRender();
|
||||||
|
});
|
||||||
|
document.getElementById('compactView').addEventListener('click', () => {
|
||||||
|
this.setViewMode(false);
|
||||||
|
});
|
||||||
|
document.getElementById('detailView').addEventListener('click', () => {
|
||||||
|
this.setViewMode(true);
|
||||||
|
});
|
||||||
|
document.getElementById('prevPage').addEventListener('click', () => {
|
||||||
|
if (this.currentPage > 1) {
|
||||||
|
this.currentPage--;
|
||||||
|
this.renderGroups();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
document.getElementById('nextPage').addEventListener('click', () => {
|
||||||
|
const totalPages = Math.ceil(this.sortedPrefixes.length / this.itemsPerPage);
|
||||||
|
if (this.currentPage < totalPages) {
|
||||||
|
this.currentPage++;
|
||||||
|
this.renderGroups();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
document.getElementById('jumpBtn').addEventListener('click', () => {
|
||||||
|
const page = parseInt(document.getElementById('pageInput').value);
|
||||||
|
const totalPages = Math.ceil(this.sortedPrefixes.length / this.itemsPerPage);
|
||||||
|
if (page >= 1 && page <= totalPages) {
|
||||||
|
this.currentPage = page;
|
||||||
|
this.renderGroups();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
document.getElementById('langZh').addEventListener('click', () => {
|
||||||
|
this.setLanguage('zh');
|
||||||
|
});
|
||||||
|
document.getElementById('langEn').addEventListener('click', () => {
|
||||||
|
this.setLanguage('en');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setLanguage(lang) {
|
||||||
|
this.currentLang = lang;
|
||||||
|
document.getElementById('langZh').classList.toggle('active', lang === 'zh');
|
||||||
|
document.getElementById('langEn').classList.toggle('active', lang === 'en');
|
||||||
|
document.querySelectorAll('[data-zh]').forEach(el => {
|
||||||
|
if (el.tagName === 'INPUT') {
|
||||||
|
el.placeholder = el.getAttribute(`data-placeholder-${lang}`);
|
||||||
|
} else {
|
||||||
|
el.textContent = el.getAttribute(`data-${lang}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.updatePagination();
|
||||||
|
this.renderGroups();
|
||||||
|
}
|
||||||
|
async loadData() {
|
||||||
|
const cdnUrls = [
|
||||||
|
"http://cdn1.spiritlhl.net/",
|
||||||
|
"http://cdn2.spiritlhl.net/",
|
||||||
|
"http://cdn3.spiritlhl.net/",
|
||||||
|
"http://cdn4.spiritlhl.net/"
|
||||||
|
];
|
||||||
|
const urls = [
|
||||||
|
'cpu_statistics.json',
|
||||||
|
...cdnUrls.map(cdn => `${cdn}https://raw.githubusercontent.com/oneclickvirt/ecs/refs/heads/ranks/cpu_statistics.json`)
|
||||||
|
];
|
||||||
|
for (let url of urls) {
|
||||||
|
try {
|
||||||
|
const response = await fetch(url);
|
||||||
|
if (!response.ok) throw new Error('请求失败');
|
||||||
|
const data = await response.json();
|
||||||
|
if (data.cpu_statistics) {
|
||||||
|
this.data = data.cpu_statistics.map(stat => ({
|
||||||
|
cpu_prefix: stat.cpu_prefix,
|
||||||
|
cpu_model: stat.cpu_model,
|
||||||
|
cpu_cores: stat.typical_cores,
|
||||||
|
single_score: stat.max_single_score,
|
||||||
|
multi_score: stat.max_multi_score,
|
||||||
|
multi_threads: stat.typical_threads
|
||||||
|
}));
|
||||||
|
if (data.total_samples) {
|
||||||
|
this.total_samples = data.total_samples;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.data = Array.isArray(data) ? data : [];
|
||||||
|
}
|
||||||
|
this.processData();
|
||||||
|
this.updateStats();
|
||||||
|
this.filterAndRender();
|
||||||
|
document.getElementById('loadingIndicator').style.display = 'none';
|
||||||
|
document.getElementById('pagination').style.display = 'flex';
|
||||||
|
document.getElementById('cpuGroups').style.display = 'block';
|
||||||
|
return;
|
||||||
|
} catch (error) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
document.getElementById('loadingIndicator').style.display = 'none';
|
||||||
|
document.getElementById('noData').style.display = 'block';
|
||||||
|
}
|
||||||
|
processData() {
|
||||||
|
this.groupedData = {};
|
||||||
|
this.data.forEach(cpu => {
|
||||||
|
const prefix = cpu.cpu_prefix;
|
||||||
|
if (!this.groupedData[prefix]) {
|
||||||
|
this.groupedData[prefix] = [];
|
||||||
|
}
|
||||||
|
this.groupedData[prefix].push(cpu);
|
||||||
|
});
|
||||||
|
Object.keys(this.groupedData).forEach(prefix => {
|
||||||
|
this.groupedData[prefix].sort((a, b) => b.single_score - a.single_score);
|
||||||
|
});
|
||||||
|
this.allSortedPrefixes = Object.keys(this.groupedData).sort((a, b) => {
|
||||||
|
const maxSingleA = Math.max(...this.groupedData[a].map(cpu => cpu.single_score));
|
||||||
|
const maxSingleB = Math.max(...this.groupedData[b].map(cpu => cpu.single_score));
|
||||||
|
return maxSingleB - maxSingleA;
|
||||||
|
});
|
||||||
|
this.allSortedPrefixes.forEach((prefix, index) => {
|
||||||
|
this.prefixRanks[prefix] = index + 1;
|
||||||
|
});
|
||||||
|
this.sortedPrefixes = [...this.allSortedPrefixes];
|
||||||
|
}
|
||||||
|
updateStats() {
|
||||||
|
const totalCpus = Object.keys(this.groupedData).length;
|
||||||
|
const totalTests = this.total_samples;
|
||||||
|
const topSingle = Math.max(...this.data.map(cpu => cpu.single_score));
|
||||||
|
const topMulti = Math.max(...this.data.map(cpu => cpu.multi_score));
|
||||||
|
document.getElementById('totalCpus').textContent = totalCpus.toLocaleString();
|
||||||
|
document.getElementById('totalTests').textContent = totalTests.toLocaleString();
|
||||||
|
document.getElementById('topSingle').textContent = topSingle.toLocaleString();
|
||||||
|
document.getElementById('topMulti').textContent = topMulti.toLocaleString();
|
||||||
|
}
|
||||||
|
filterAndRender() {
|
||||||
|
if (this.searchTerm) {
|
||||||
|
this.filteredGroups = {};
|
||||||
|
const filteredPrefixes = [];
|
||||||
|
this.allSortedPrefixes.forEach(prefix => {
|
||||||
|
const filteredCpus = this.groupedData[prefix].filter(cpu =>
|
||||||
|
cpu.cpu_model.toLowerCase().includes(this.searchTerm) ||
|
||||||
|
cpu.cpu_prefix.toLowerCase().includes(this.searchTerm)
|
||||||
|
);
|
||||||
|
if (filteredCpus.length > 0) {
|
||||||
|
this.filteredGroups[prefix] = filteredCpus;
|
||||||
|
filteredPrefixes.push(prefix);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.sortedPrefixes = filteredPrefixes;
|
||||||
|
} else {
|
||||||
|
this.filteredGroups = this.groupedData;
|
||||||
|
this.sortedPrefixes = [...this.allSortedPrefixes];
|
||||||
|
}
|
||||||
|
this.renderGroups();
|
||||||
|
}
|
||||||
|
renderGroups() {
|
||||||
|
const container = document.getElementById('cpuGroups');
|
||||||
|
const startIndex = (this.currentPage - 1) * this.itemsPerPage;
|
||||||
|
const endIndex = startIndex + this.itemsPerPage;
|
||||||
|
const currentPagePrefixes = this.sortedPrefixes.slice(startIndex, endIndex);
|
||||||
|
container.innerHTML = currentPagePrefixes.map(prefix => {
|
||||||
|
const cpus = this.filteredGroups[prefix];
|
||||||
|
const topCpu = cpus[0];
|
||||||
|
const maxSingle = Math.max(...cpus.map(cpu => cpu.single_score));
|
||||||
|
const maxMulti = Math.max(...cpus.map(cpu => cpu.multi_score));
|
||||||
|
const rank = this.prefixRanks[prefix];
|
||||||
|
const sampleText = this.currentLang === 'zh' ? '样本' : 'Samples';
|
||||||
|
const singleText = this.currentLang === 'zh' ? '单核最高' : 'Max Single';
|
||||||
|
const multiText = this.currentLang === 'zh' ? '多核最高' : 'Max Multi';
|
||||||
|
return `
|
||||||
|
<div class="cpu-group" data-prefix="${prefix}">
|
||||||
|
<div class="group-header">
|
||||||
|
<div class="group-title-section">
|
||||||
|
<div class="rank-badge">#${rank}</div>
|
||||||
|
<div class="group-title">${topCpu.cpu_model}</div>
|
||||||
|
</div>
|
||||||
|
<div class="group-stats">
|
||||||
|
<span>${sampleText}: ${cpus.length}</span>
|
||||||
|
<span>${singleText}: ${maxSingle.toLocaleString()}</span>
|
||||||
|
<span>${multiText}: ${maxMulti.toLocaleString()}</span>
|
||||||
|
</div>
|
||||||
|
<div class="expand-icon">▼</div>
|
||||||
|
</div>
|
||||||
|
<div class="group-content">
|
||||||
|
${this.renderTable(cpus)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}).join('');
|
||||||
|
container.querySelectorAll('.group-header').forEach(header => {
|
||||||
|
header.addEventListener('click', () => {
|
||||||
|
const group = header.parentElement;
|
||||||
|
group.classList.toggle('expanded');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.updatePagination();
|
||||||
|
}
|
||||||
|
updatePagination() {
|
||||||
|
const totalPages = Math.ceil(this.sortedPrefixes.length / this.itemsPerPage);
|
||||||
|
const pageInfo = document.getElementById('pageInfo');
|
||||||
|
const pageText = this.currentLang === 'zh'
|
||||||
|
? `第 ${this.currentPage} 页,共 ${totalPages} 页`
|
||||||
|
: `Page ${this.currentPage} of ${totalPages}`;
|
||||||
|
pageInfo.textContent = pageText;
|
||||||
|
const pageInput = document.getElementById('pageInput');
|
||||||
|
pageInput.max = totalPages;
|
||||||
|
pageInput.value = this.currentPage;
|
||||||
|
const prevBtn = document.getElementById('prevPage');
|
||||||
|
const nextBtn = document.getElementById('nextPage');
|
||||||
|
prevBtn.disabled = this.currentPage === 1;
|
||||||
|
nextBtn.disabled = this.currentPage === totalPages;
|
||||||
|
}
|
||||||
|
renderTable(cpus) {
|
||||||
|
const headers = this.isDetailView
|
||||||
|
? (this.currentLang === 'zh'
|
||||||
|
? ['CPU型号', '核心数', '单核分数', '多核分数', '多核线程']
|
||||||
|
: ['CPU Model', 'Cores', 'Single Score', 'Multi Score', 'Multi Threads'])
|
||||||
|
: (this.currentLang === 'zh'
|
||||||
|
? ['CPU型号', '核心数', '单核分数', '多核分数']
|
||||||
|
: ['CPU Model', 'Cores', 'Single Score', 'Multi Score']);
|
||||||
|
const rows = cpus.slice(0, this.isDetailView ? cpus.length : 10).map(cpu => {
|
||||||
|
const cells = this.isDetailView
|
||||||
|
? [cpu.cpu_model, cpu.cpu_cores, cpu.single_score.toLocaleString(),
|
||||||
|
cpu.multi_score.toLocaleString(), cpu.multi_threads]
|
||||||
|
: [cpu.cpu_model, cpu.cpu_cores, cpu.single_score.toLocaleString(),
|
||||||
|
cpu.multi_score.toLocaleString()];
|
||||||
|
return `
|
||||||
|
<tr>
|
||||||
|
${cells.map((cell, index) => {
|
||||||
|
let className = '';
|
||||||
|
if (index === 2) className = 'score-cell score-single';
|
||||||
|
else if (index === 3) className = 'score-cell score-multi';
|
||||||
|
return `<td class="${className}">${cell}</td>`;
|
||||||
|
}).join('')}
|
||||||
|
</tr>
|
||||||
|
`;
|
||||||
|
}).join('');
|
||||||
|
return `
|
||||||
|
<table class="cpu-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
${headers.map(header => `<th>${header}</th>`).join('')}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
${rows}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
setViewMode(isDetail) {
|
||||||
|
this.isDetailView = isDetail;
|
||||||
|
document.getElementById('compactView').classList.toggle('active', !isDetail);
|
||||||
|
document.getElementById('detailView').classList.toggle('active', isDetail);
|
||||||
|
this.renderGroups();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new CPUDashboard();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@@ -1,35 +0,0 @@
|
|||||||
package memorytest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/oneclickvirt/memorytest/memory"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func MemoryTest(language, testMethod string) {
|
|
||||||
var res string
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
if testMethod != "winsat" && testMethod != "" {
|
|
||||||
res = "Detected host is Windows, using Winsat for testing.\n"
|
|
||||||
}
|
|
||||||
res += memory.WinsatTest(language)
|
|
||||||
} else {
|
|
||||||
switch testMethod {
|
|
||||||
case "sysbench":
|
|
||||||
res = memory.SysBenchTest(language)
|
|
||||||
if res == "" {
|
|
||||||
res = "sysbench test failed, switch to use dd test.\n"
|
|
||||||
res += memory.DDTest(language)
|
|
||||||
}
|
|
||||||
case "dd":
|
|
||||||
res = memory.DDTest(language)
|
|
||||||
default:
|
|
||||||
res = "Unsupported test method"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !strings.Contains(res, "\n") && res != "" {
|
|
||||||
res += "\n"
|
|
||||||
}
|
|
||||||
fmt.Printf(res)
|
|
||||||
}
|
|
@@ -1,9 +0,0 @@
|
|||||||
package memorytest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test(t *testing.T) {
|
|
||||||
MemoryTest("zh", "sysbench")
|
|
||||||
}
|
|
@@ -1,8 +0,0 @@
|
|||||||
package network1
|
|
||||||
|
|
||||||
import "github.com/oneclickvirt/security/network"
|
|
||||||
|
|
||||||
// 本包在main中不使用
|
|
||||||
func NetworkCheck(checkType string, enableSecurityCheck bool, language string) (string, string, error) {
|
|
||||||
return network.NetworkCheck(checkType, enableSecurityCheck, language)
|
|
||||||
}
|
|
@@ -1,22 +0,0 @@
|
|||||||
package network1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestIpv4SecurityCheck(t *testing.T) {
|
|
||||||
// 单项测试
|
|
||||||
//result1, _ := Ipv4SecurityCheck("8.8.8.8", nil, "zh")
|
|
||||||
//fmt.Println(result1)
|
|
||||||
//result2, _ := Ipv6SecurityCheck("2001:4860:4860::8844", nil, "zh")
|
|
||||||
//fmt.Println(result2)
|
|
||||||
|
|
||||||
// 全项测试
|
|
||||||
ipInfo, securityInfo, _ := NetworkCheck("both", true, "zh")
|
|
||||||
fmt.Println("--------------------------------------------------")
|
|
||||||
fmt.Printf(ipInfo)
|
|
||||||
fmt.Println("--------------------------------------------------")
|
|
||||||
fmt.Printf(securityInfo)
|
|
||||||
fmt.Println("--------------------------------------------------")
|
|
||||||
}
|
|
@@ -1,9 +0,0 @@
|
|||||||
package ntrace
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/oneclickvirt/nt3/nt"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TraceRoute3(language, location, checkType string) {
|
|
||||||
nt.TraceRoute(language, location, checkType)
|
|
||||||
}
|
|
@@ -1,8 +0,0 @@
|
|||||||
package ntrace
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
// https://github.com/nxtrace/NTrace-core/blob/main/fast_trace/fast_trace.go
|
|
||||||
func TestTraceRoute(t *testing.T) {
|
|
||||||
TraceRoute3("en", "GZ", "ipv4")
|
|
||||||
}
|
|
13
port/port.go
13
port/port.go
@@ -1,13 +0,0 @@
|
|||||||
package port
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/oneclickvirt/portchecker/email"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 常用端口阻断检测 TCP/UDP/ICMP 协议
|
|
||||||
// 本包不在main中使用
|
|
||||||
func EmailCheck() {
|
|
||||||
res := email.EmailCheck()
|
|
||||||
fmt.Println(res)
|
|
||||||
}
|
|
@@ -1,9 +0,0 @@
|
|||||||
package port
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test(t *testing.T) {
|
|
||||||
EmailCheck()
|
|
||||||
}
|
|
@@ -1,66 +0,0 @@
|
|||||||
package speedtest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/oneclickvirt/speedtest/model"
|
|
||||||
"github.com/oneclickvirt/speedtest/sp"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ShowHead(language string) {
|
|
||||||
sp.ShowHead(language)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NearbySP() {
|
|
||||||
if runtime.GOOS == "windows" || sp.OfficialAvailableTest() != nil {
|
|
||||||
sp.NearbySpeedTest()
|
|
||||||
} else {
|
|
||||||
sp.OfficialNearbySpeedTest()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func CustomSP(platform, operator string, num int, language string) {
|
|
||||||
var url, parseType string
|
|
||||||
if strings.ToLower(platform) == "cn" {
|
|
||||||
if strings.ToLower(operator) == "cmcc" {
|
|
||||||
url = model.CnCMCC
|
|
||||||
} else if strings.ToLower(operator) == "cu" {
|
|
||||||
url = model.CnCU
|
|
||||||
} else if strings.ToLower(operator) == "ct" {
|
|
||||||
url = model.CnCT
|
|
||||||
} else if strings.ToLower(operator) == "hk" {
|
|
||||||
url = model.CnHK
|
|
||||||
} else if strings.ToLower(operator) == "tw" {
|
|
||||||
url = model.CnTW
|
|
||||||
} else if strings.ToLower(operator) == "jp" {
|
|
||||||
url = model.CnJP
|
|
||||||
} else if strings.ToLower(operator) == "sg" {
|
|
||||||
url = model.CnSG
|
|
||||||
}
|
|
||||||
parseType = "url"
|
|
||||||
} else if strings.ToLower(platform) == "net" {
|
|
||||||
if strings.ToLower(operator) == "cmcc" {
|
|
||||||
url = model.NetCMCC
|
|
||||||
} else if strings.ToLower(operator) == "cu" {
|
|
||||||
url = model.NetCU
|
|
||||||
} else if strings.ToLower(operator) == "ct" {
|
|
||||||
url = model.NetCT
|
|
||||||
} else if strings.ToLower(operator) == "hk" {
|
|
||||||
url = model.NetHK
|
|
||||||
} else if strings.ToLower(operator) == "tw" {
|
|
||||||
url = model.NetTW
|
|
||||||
} else if strings.ToLower(operator) == "jp" {
|
|
||||||
url = model.NetJP
|
|
||||||
} else if strings.ToLower(operator) == "sg" {
|
|
||||||
url = model.NetSG
|
|
||||||
} else if strings.ToLower(operator) == "global" {
|
|
||||||
url = model.NetGlobal
|
|
||||||
}
|
|
||||||
parseType = "id"
|
|
||||||
}
|
|
||||||
if runtime.GOOS == "windows" || sp.OfficialAvailableTest() != nil {
|
|
||||||
sp.CustomSpeedTest(url, parseType, num, language)
|
|
||||||
} else {
|
|
||||||
sp.OfficialCustomSpeedTest(url, parseType, num, language)
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,8 +0,0 @@
|
|||||||
package speedtest
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func Test(t *testing.T) {
|
|
||||||
ShowHead("en")
|
|
||||||
NearbySP()
|
|
||||||
}
|
|
@@ -1,26 +0,0 @@
|
|||||||
package unlocktest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/oneclickvirt/UnlockTests/utils"
|
|
||||||
"github.com/oneclickvirt/UnlockTests/uts"
|
|
||||||
"github.com/oneclickvirt/defaultset"
|
|
||||||
)
|
|
||||||
|
|
||||||
func MediaTest(language string) string {
|
|
||||||
var res string
|
|
||||||
readStatus := uts.ReadSelect(language, "0")
|
|
||||||
if !readStatus {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
if uts.IPV4 {
|
|
||||||
res += defaultset.Blue("IPV4:") + "\n"
|
|
||||||
res += uts.RunTests(utils.Ipv4HttpClient, "ipv4", language, false)
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
if uts.IPV6 {
|
|
||||||
res += defaultset.Blue("IPV6:") + "\n"
|
|
||||||
res += uts.RunTests(utils.Ipv6HttpClient, "ipv6", language, false)
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
@@ -1,10 +0,0 @@
|
|||||||
package unlocktest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test(t *testing.T) {
|
|
||||||
fmt.Printf(MediaTest("zh"))
|
|
||||||
}
|
|
346
utils/utils.go
346
utils/utils.go
@@ -1,346 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"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"
|
|
||||||
cipccURL := "http://cip.cc"
|
|
||||||
ipapiResp, err := client.R().Get(ipapiURL)
|
|
||||||
if err != nil {
|
|
||||||
if enableLogger {
|
|
||||||
Logger.Info("无法获取IP信息:" + err.Error())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
defer ipapiResp.Body.Close()
|
|
||||||
var ipapiBody string
|
|
||||||
ipapiBody, err = ipapiResp.ToString()
|
|
||||||
if err != nil {
|
|
||||||
if enableLogger {
|
|
||||||
Logger.Info("无法读取IP信息响应:" + err.Error())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cipccResp, err := client.R().Get(cipccURL)
|
|
||||||
if err != nil {
|
|
||||||
if enableLogger {
|
|
||||||
Logger.Info("无法获取IP信息:" + err.Error())
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
defer cipccResp.Body.Close()
|
|
||||||
cipccBody, err := cipccResp.ToString()
|
|
||||||
if err != nil {
|
|
||||||
if enableLogger {
|
|
||||||
Logger.Info("无法读取IP信息响应:" + err.Error())
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
isInChina := strings.Contains(cipccBody, "中国")
|
|
||||||
if isInChina {
|
|
||||||
fmt.Println("根据cip.cc提供的信息,当前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
|
|
||||||
}
|
|
||||||
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()
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
httpURL, httpsURL, err := upload(primaryURL)
|
|
||||||
if err == nil {
|
|
||||||
return httpURL, httpsURL, nil
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
// 检查文件是否存在
|
|
||||||
if _, err := os.Stat(filePath); err == nil {
|
|
||||||
// 文件存在,删除文件
|
|
||||||
err = os.Remove(filePath)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Cannot delete file:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 创建文件
|
|
||||||
file, err := os.Create(filePath)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Cannot create file:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
// 匹配 ANSI 转义序列
|
|
||||||
ansiRegex := regexp.MustCompile("\x1B\\[[0-9;]+[a-zA-Z]")
|
|
||||||
// 移除 ANSI 转义序列
|
|
||||||
cleanedOutput := ansiRegex.ReplaceAllString(output, "")
|
|
||||||
// 写入文件
|
|
||||||
_, err = file.WriteString(cleanedOutput)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Cannot write to file:", err)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
fmt.Println("Write test result in ", filePath)
|
|
||||||
}
|
|
||||||
if enableUplaod {
|
|
||||||
// 获取文件的绝对路径
|
|
||||||
absPath, err2 := filepath.Abs(filePath)
|
|
||||||
if err2 != nil {
|
|
||||||
fmt.Println("Failed to get absolute file path:", err2)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 上传文件并生成短链接
|
|
||||||
http_url, https_url, err3 := UploadText(absPath)
|
|
||||||
if err3 != nil {
|
|
||||||
fmt.Println("Upload failed, cannot generate short URL.")
|
|
||||||
fmt.Println(err3.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Printf("Upload successful!\nHttp URL: %s\nHttps URL: %s\n", http_url, https_url)
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user